6.24.2011

Handling Registry in DotNet - RegNotifyChangeKeyValue

In other programming languages, it is most likely a must to use the registry Api's, listed on msdn Here.
But using dotnet, thanks to the Microsoft.Win32.Registry Class, we have all methods needed to Open a key, enumerate keys, create or delete keys, or even enumerating values, reading names, values, adding, modifying and deleting. there are various examples on msdn for almost every method of this class, they could really show you the simplicity of handling registry.

Probably the function that i find important and "missing" in this class is the ability to monitor changes in the registry.
therefor, we are going to use the RegNotifyChangeKeyValue as we do in any other language.
but first, we are going to use RegOpenKeyEx to open the key with the KEY_NOTIFY.

Here is an exemple :

Private Declare Function RegNotifyChangeKeyValue Lib "advapi32.dll" (ByVal hKey As IntPtr, _
ByVal watchSubtree As Boolean, ByVal dwNotifyFilter As Integer, ByVal hEvent As IntPtr, _
ByVal fAsynchronous As Boolean) As Integer

Private Declare Auto Function RegOpenKeyEx Lib "advapi32.dll" ( _
ByVal hKey As IntPtr, _
ByVal lpSubKey As String, _
ByVal ulOptions As Integer, _
ByVal samDesired As Integer, _
ByRef phkResult As Integer) As Integer

Const REG_NOTIFY_CHANGE_LAST_SET As Integer = &H4L
Const HKEY_CURRENT_USER As Integer = &H80000001
Const KEY_NOTIFY As Integer = &H10 
Const ERROR_SUCCESS As Integer = 0


Sub RegNotifyChange()
        Dim regkey As IntPtr
        If RegOpenKeyEx(HKEY_CURRENT_USER, "Software\Microsoft\Windows", 0, KEY_NOTIFY, regkey) = ERROR_SUCCESS Then
            If RegNotifyChangeKeyValue(regkey, False, REG_NOTIFY_CHANGE_LAST_SET, Nothing, False) = ERROR_SUCCESS Then
                MsgBox("Change!")
            Else
                MsgBox("RegNotifyChangeKeyValue Failed.")
            End If
        Else
            MsgBox("RegOpenKeyEx Failed.")
        End If
    End Sub

Explaining the code :
we need to open a registry key with the notify access, so we can tell RegNotifyChangeKeyValue to "notify" us whenever something changed.
we call RegOpenKeyEx with HKEY_CURRENT_USER as the root key, which is already opened.
our subkey for exemple will be "Software\Microsoft\Windows". set 0 for the reserved parameter, KEY_NOTIFY for desired Access, and our variable regkey where the handle will be stored.
after that, we call RegNotifyChangeKeyValue with the specified opened key. we set true if want to monitor subkeys also, in this case we dont (for example). Then, when need to specify a filter, which can be a combination of REG_NOTIFY_CHANGE_NAME, REG_NOTIFY_CHANGE_ATTRIBUTES, REG_NOTIFY_CHANGE_LAST_SET and REG_NOTIFY_CHANGE_SECURITY, they are all described in the RegNotifyChangeKeyValue page. in our case, all we need is to monitor changes in values only.
in the next parameter, we need to specify whether we want to "fire" an event when a change occurs, so we set hEvent to a handle of an event, and fAsynchronous to True. in our case, where fAsynchronous is set to false, the calling thread will sleep after the call, and the function will only return when a change occurs. in this case hEvent is ignored.

Debugging :
When this method is called, the thread will be waiting for the function to return, in other words, will be waiting for a specific changes in the registry, a messagebox will pop up, and our sub will exit. if we want to continue to monitor changes, we can keep calling RegNotifyChangeKeyValue in a loop, but it is better to use another thread for the job, because this thread will be busy.

After Finishing using the key, it is best to call RegCloseKey to close the handle.

No comments: