Before we start adding code to a sample Delphi project capable of monitoring Registry changes we have to create a new thread object - the one that, in a loop, waits for a change to happen.
For the sake of simplicity we'll add this thread class in an existing project. First, start Delphi. By default a new project with one form is created. Second, add a TMemo component to that form. This is all we need, any change to the Registry will be added to the Memo. Now, we move onto creating that thread...
The TRegMonitorThread Class
To create a new Thread object, you simply point to (main Delphi menu) File | New | Other and select "Thread Object", a "New Thread Object" dialog box will ask you to specify the name for your class.
Name it 'TRegMonitorThread', click OK. This will add a new unit to your project, with a skeleton code (and an empty Execute function) that defines the TRegMonitorThread class as a class derived from TThread.
Note: if you have never worked with threads in Delphi - why not start now! Either way, "Threading in Delphi" has all the information about creating multithread applications with Delphi that you can think of.
Now, I'll show you some code snippets from the TRegMonitorThread class. Later, you'll have the option to download all the code from the article.
Let's see. The main code goes in the Execute procedure of the thread object. As explained in the beginning of the article, the code in the Execute procedure is in fact one big loop - executes until you terminate the monitoring process. In the loop, the code calls the WaitForSingleObject API that enters a wait state and uses almost no CPU cycles until a condition is met. The condition we are waiting for, is the event called by the RegNotifyChangeKeyValue function.
This is how the above looks when talking Delphi language:
procedure TRegMonitorThread.InitThread;
begin
FReg.RootKey := RootKey;
if not FReg.OpenKeyReadOnly(Key) then
begin
raise Exception.Create('Unable to open registry key ' + Key);
end;
FEvent := CreateEvent(nil, True, False, 'RegMonitorChange');
RegNotifyChangeKeyValue(FReg.CurrentKey, 1, Filter, FEvent, 1);
end;
procedure TRegMonitorThread.Execute;
begin
InitThread;
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;
|
Note: The Execute function first calls the InitThread procedure that uses the values of the properties of the class to create the event and to make the first call to RegNotifyChangeKeyValue function. The properties of the TRegMonitorThread class provide a simpler way for a developer to supply values to the RegNotifyChangeKeyValue function and other structures defined inside the thread class.
Now, what happens when the wait loop traps a Registry change?
The fChangeData is a record type variable (exposed as a read-only property) in which we save the current value of the Key where the change has occurred. The code upon notification sends a user defined message to the window (Wnd parameter) that called the monitoring thread. And finally, we call the RegNotifyChangeKeyValue again.
This is, more or less, everything you need to enable Registry monitoring using Delphi. But, and there is always a "but", due to some situations when monitoring sub-keys is not working you'll need to redeclare the RegNotifyChangeKeyValue function by changing some parameters from Boolean to Integer, like this:
function RegNotifyChangeKeyValue(
hKey: HKEY; bWatchSubtree: DWORD;
dwNotifyFilter: DWORD;
hEvent: THandle;
fAsynchronus: DWORD): Longint; stdcall;
external 'advapi32.dll' name 'RegNotifyChangeKeyValue';
|
Next, you are ready to add the code in the main project to call the TRegMonitorThread.
Next page > Sample project > Page 1, 2, 3
~ Zarko Gajic