How to start / stop Delphi stream monitoring on demand?

I was looking for a way to track specific registry changes in Delphi. Found solution in about.com:

procedure TRegMonitorThread.Execute; begin InitThread; // method omitted here while not Terminated do begin if WaitForSingleObject(FEvent, INFINITE) = WAIT_OBJECT_0 then begin fChangeData.RootKey := RootKey; fChangeData.Key := Key; SendMessage(Wnd, WM_REGCHANGE, RootKey, LongInt(PChar(Key))); ResetEvent(FEvent); RegNotifyChangeKeyValue(FReg.CurrentKey, 1, Filter, FEvent, 1); end; end; end; 

In my application, I will need to start and stop this thread on demand, but the above code does not allow this. Just set the Terminated flag will not.

It would be enough to say somehow that the stream will stop waiting, and then release it and, if necessary, create a new one. How can I change this code to achieve this?

+1
source share
3 answers

Use WaitForMultipleObjects() with an array of two events instead of WaitForSingleObject() . Add a reset message to the stream class and pass it after you set Terminated to True . Check the return value, which of the two events has been signaled, and act accordingly.

Edit:

Some minimal Delphi 2009 code to demonstrate the idea. You must add SyncObjs to the list of units used and add

  fTerminateEvent: TEvent; 

to the private section of your thread class.

 constructor TTestThread.Create; begin inherited Create(TRUE); fTerminateEvent := TEvent.Create(nil, True, False, ''); // ... Resume; end; destructor TTestThread.Destroy; begin fTerminateEvent.SetEvent; Terminate; // not necessary if you don't check Terminated in your code WaitFor; fTerminateEvent.Free; inherited; end; procedure TTestThread.Execute; var Handles: array[0..1] of THandle; begin Handles[0] := ...; // your event handle goes here Handles[1] := fTerminateEvent.Handle; while not Terminated do begin if WaitForMultipleObjects(2, @Handles[0], False, INFINITE) <> WAIT_OBJECT_0 then break; // ... end; end; 

You only need to add the code in your question to it. Just trying to free an instance of a thread will do whatever it takes to unlock the thread (if necessary).

+8
source

Instead of INFINITE, you should have a WaitForSingleObject timeout after a period. Thus, the cycle continues, and verification is completed.

 procedure TRegMonitorThread.Execute; begin InitThread; // method omitted here while not Terminated do begin if WaitForSingleObject(FEvent, 1000) = WAIT_OBJECT_0 then begin fChangeData.RootKey := RootKey; fChangeData.Key := Key; SendMessage(Wnd, WM_REGCHANGE, RootKey, LongInt(PChar(Key))); ResetEvent(FEvent); RegNotifyChangeKeyValue(FReg.CurrentKey, 1, Filter, FEvent, 1); end; end; end; 

The TThread.Suspend and TThread.Resume methods can theoretically be used to temporarily terminate threads, but since Delphi 2010 now recognizes that they are unsafe to use. See TThread.resume deprecated in Delphi 2010, what should be used in place? and http://msdn.microsoft.com/en-us/library/ms686345%28VS.85%29.aspx

+1
source

This works, just make small changes as shown below, and now when you call Terminate:

  TRegMonitorThread = class(TThread) ... public procedure Terminate; reintroduce; ... procedure TRegMonitorThread. Terminate; // add new public procedure begin inherited Terminate; Windows.SetEvent(FEvent); end; procedure TRegMonitorThread.Execute; begin InitThread; while not Terminated do begin if WaitForSingleObject(FEvent, INFINITE) = WAIT_OBJECT_0 then begin if Terminated then // <- add this 2 lines Exit; ... end; end; end; 
+1
source

All Articles