DrDamnit
asked on
Use RegNotifyChangeKeyValue without WaitForSingleObject
I have a loop that I want to use to tell me whether or not a registry key has changed:
'Monitoring Loop
Do
DoEvents
hEvent = CreateEvent(lpEventAttribu tes, True, False, lpName)
lRet = RegOpenKey(hKey, sRegKeyPath, lKeyHandle)
notify = RegNotifyChangeKeyValue(lK eyHandle, bWatchSubTree, dwFilters, hEvent, True)
lWait = WaitForSingleObject(hEvent , INFINITE)
If lWait = WAIT_FAILED Then
MsgBox "Wait Failed!"
End If
If Not notify = error_sucess Then
FormatMessage FORMAT_MESSAGE_FROM_SYSTEM , ByVal 0&, notify, LANG_NEUTRAL, buffer, 200, ByVal 0&
MsgBox buffer
End If
lRet = RegCloseKey(lKeyHandle)
MsgBox "A registry key has changed!" & vbCrLf & mvarMonitoredKey
If mvarStart = False Then Exit Do
Loop
I want to be able to use the RegNotifyChangeKeyValue API call without having to answer either FALSE to the asynchronus parameter of the API itself OR using sometype of wait routine (WaitForSingleObject). I want this to run in a loop so I can execute a doevents and paint the screen while waiting for a registry change.
How do I do that?
'Monitoring Loop
Do
DoEvents
hEvent = CreateEvent(lpEventAttribu
lRet = RegOpenKey(hKey, sRegKeyPath, lKeyHandle)
notify = RegNotifyChangeKeyValue(lK
lWait = WaitForSingleObject(hEvent
If lWait = WAIT_FAILED Then
MsgBox "Wait Failed!"
End If
If Not notify = error_sucess Then
FormatMessage FORMAT_MESSAGE_FROM_SYSTEM
MsgBox buffer
End If
lRet = RegCloseKey(lKeyHandle)
MsgBox "A registry key has changed!" & vbCrLf & mvarMonitoredKey
If mvarStart = False Then Exit Do
Loop
I want to be able to use the RegNotifyChangeKeyValue API call without having to answer either FALSE to the asynchronus parameter of the API itself OR using sometype of wait routine (WaitForSingleObject). I want this to run in a loop so I can execute a doevents and paint the screen while waiting for a registry change.
How do I do that?
lWait = WaitForSingleObject(hEvent , INFINITE)
Replace this line with loop:
While True
lWait = WaitForSingleObject(hEvent , 100)
if lWait = WAIT_TIMEOUT Then
DoEvents
' continue waiting
else
' handle lWait as you do this now
Exit While
end if
WEnd
This code fragment replaces infinite wait for hEvent with waiting and handling of messages. When WaitForSingleObject returns WAIT_TIMEOUT, call DoEvents and continue to wait. Any other return value (success - WAIT_OBJECT_0, error code) should be handled according to your current program logic, and program exits from wait loop.
Replace this line with loop:
While True
lWait = WaitForSingleObject(hEvent
if lWait = WAIT_TIMEOUT Then
DoEvents
' continue waiting
else
' handle lWait as you do this now
Exit While
end if
WEnd
This code fragment replaces infinite wait for hEvent with waiting and handling of messages. When WaitForSingleObject returns WAIT_TIMEOUT, call DoEvents and continue to wait. Any other return value (success - WAIT_OBJECT_0, error code) should be handled according to your current program logic, and program exits from wait loop.
ASKER
Ark,
I've seen that. I am trying to monitor more than one key without threading anything. So I can't use waitforsingleobject.
AlexFM,
I don't want to use waitforsingleobject at all.
I've seen that. I am trying to monitor more than one key without threading anything. So I can't use waitforsingleobject.
AlexFM,
I don't want to use waitforsingleobject at all.
There are two ways to use RegNotifyChangeKeyValue function:
1) With fAsynchronous = FALSE. In this case you don't need WaitForSingleObject, but function is synchronous and returns only when there is change in the Registry.
2) With fAsynchronous = TRUE. In this case function returns immidiately and event is signaled later when Registry is changed. The only way to test event state is using WaitForSingleObject or other wait functions like WaitForSingleObject, which is basically the same. If you don't want to use wait functions (BTW, why?), there is no solution to your problem.
>> I am trying to monitor more than one key without threading anything.
Using wait functions doesnt require threading.
1) With fAsynchronous = FALSE. In this case you don't need WaitForSingleObject, but function is synchronous and returns only when there is change in the Registry.
2) With fAsynchronous = TRUE. In this case function returns immidiately and event is signaled later when Registry is changed. The only way to test event state is using WaitForSingleObject or other wait functions like WaitForSingleObject, which is basically the same. If you don't want to use wait functions (BTW, why?), there is no solution to your problem.
>> I am trying to monitor more than one key without threading anything.
Using wait functions doesnt require threading.
ASKER
Because the program freezes until a registry change occurs.
This happens because you use WaitForSingleObject by wrong way:
lWait = WaitForSingleObject(hEvent , INFINITE)
And I suggest you to wait fore some short time and handle events, exactly as you need:
While True
lWait = WaitForSingleObject(hEvent , 100) ' wait 100 ms (or 50, 20 as you need)
if lWait = WAIT_TIMEOUT Then
DoEvents
' continue waiting - go to the beginning of the loop again
else
' handle lWait as you do this now
Exit While ' to external loop: call RegNotifyChangeKeyValue again
end if
WEnd
lWait = WaitForSingleObject(hEvent
And I suggest you to wait fore some short time and handle events, exactly as you need:
While True
lWait = WaitForSingleObject(hEvent
if lWait = WAIT_TIMEOUT Then
DoEvents
' continue waiting - go to the beginning of the loop again
else
' handle lWait as you do this now
Exit While ' to external loop: call RegNotifyChangeKeyValue again
end if
WEnd
Hi again
>>I've seen that<< - This is my own code - probably you've seen my sample at freevbcode.com
As for monitoring multiple key - just set top root key for all subkeys, set bWatchSubTree = True and compare old values for your subkeys with current values for each change event
>>I've seen that<< - This is my own code - probably you've seen my sample at freevbcode.com
As for monitoring multiple key - just set top root key for all subkeys, set bWatchSubTree = True and compare old values for your subkeys with current values for each change event
ASKER
Your code? Cool! Good Job!
I have thought about setting up a compare routine, but the execution is not as "lean" as I would like it to be. I have specific keys that I want to monitor, and I don't want to monitor the whole route. For instance, I don't want to monitor all of HKLM\SOFTWARE, and compare changes. I would rather montior HKLM\Software\Specific Key\ and HKCU\Software\Specific Key 2\ only.
Can that be done with what you're talking about? I know I can do it with C++, but the problem is....I don't know C++ yet. :-)
I have thought about setting up a compare routine, but the execution is not as "lean" as I would like it to be. I have specific keys that I want to monitor, and I don't want to monitor the whole route. For instance, I don't want to monitor all of HKLM\SOFTWARE, and compare changes. I would rather montior HKLM\Software\Specific Key\ and HKCU\Software\Specific Key 2\ only.
Can that be done with what you're talking about? I know I can do it with C++, but the problem is....I don't know C++ yet. :-)
Hi
You can create an array of events - one for each key, then use WaitForMultipleObjects and check return values
You can create an array of events - one for each key, then use WaitForMultipleObjects and check return values
ASKER
What would the code for that look like?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Excellent info, Ark. If you;re still monitoring this thread, I'd appreciate if you can help me. I use this code, and getting the error mentioned at the bottom.
====CODE=====
Dim sArray() As String
Dim i as integer
For ListViewIndex = 1 To ListView1.ListItems.Count
ReDim Preserve strKeys(i)
RNumber = ListView1.ListItems(ListVi ewIndex).T ext
RPath = "Software\MyKey\" & RNumber
strKeys(i) = RPath
i = i + 1
Next
Call RegMonitor(HKEY_CURRENT_US ER, strKeys, True, REG_NOTIFY_CHANGE_ATTRIBUT ES + REG_NOTIFY_CHANGE_LAST_SET + REG_NOTIFY_CHANGE_NAME + REG_NOTIFY_CHANGE_SECURITY )
====End of CODE=====
ERROR: "ByRef Argument type mismatch" in variable "strKeys"
Perhaps I did something wrong in declaring the Array ? If you've found where the error is, pls let me know so that I can post a new question.
====CODE=====
Dim sArray() As String
Dim i as integer
For ListViewIndex = 1 To ListView1.ListItems.Count
ReDim Preserve strKeys(i)
RNumber = ListView1.ListItems(ListVi
RPath = "Software\MyKey\" & RNumber
strKeys(i) = RPath
i = i + 1
Next
Call RegMonitor(HKEY_CURRENT_US
====End of CODE=====
ERROR: "ByRef Argument type mismatch" in variable "strKeys"
Perhaps I did something wrong in declaring the Array ? If you've found where the error is, pls let me know so that I can post a new question.
Revised code:
------------------
====CODE=====
Dim strKeys() As String
Dim i as integer
For ListViewIndex = 1 To ListView1.ListItems.Count
ReDim Preserve strKeys(i)
RNumber = ListView1.ListItems(ListVi ewIndex).T ext
RPath = "Software\MyKey\" & RNumber
strKeys(i) = RPath
i = i + 1
Next
Call RegMonitor(HKEY_CURRENT_US ER, strKeys, True, REG_NOTIFY_CHANGE_ATTRIBUT ES + REG_NOTIFY_CHANGE_LAST_SET + REG_NOTIFY_CHANGE_NAME + REG_NOTIFY_CHANGE_SECURITY )
====End of CODE=====
ERROR: "ByRef Argument type mismatch" in variable "strKeys"
Perhaps I did something wrong in declaring the Array ? If you've found where the error is, pls let me know so that I can post a new question.
------------------
====CODE=====
Dim strKeys() As String
Dim i as integer
For ListViewIndex = 1 To ListView1.ListItems.Count
ReDim Preserve strKeys(i)
RNumber = ListView1.ListItems(ListVi
RPath = "Software\MyKey\" & RNumber
strKeys(i) = RPath
i = i + 1
Next
Call RegMonitor(HKEY_CURRENT_US
====End of CODE=====
ERROR: "ByRef Argument type mismatch" in variable "strKeys"
Perhaps I did something wrong in declaring the Array ? If you've found where the error is, pls let me know so that I can post a new question.
should be
lWait = WaitForSingleObject(hEvent
'=======bas module code========
Public Enum ROOT_KEYS
HKEY_CLASSES_ROOT = &H80000000
HKEY_CURRENT_USER = &H80000001
HKEY_LOCAL_MACHINE = &H80000002
HKEY_USERS = &H80000003
HKEY_PERFORMANCE_DATA = &H80000004
HKEY_CURRENT_CONFIG = &H80000005
HKEY_DYN_DATA = &H80000006
End Enum
Public Enum NOTIFY_EVENTS
REG_NOTIFY_CHANGE_NAME = &H1
REG_NOTIFY_CHANGE_ATTRIBUT
REG_NOTIFY_CHANGE_LAST_SET
REG_NOTIFY_CHANGE_SECURITY
End Enum
Private Declare Function RegNotifyChangeKeyValue Lib "advapi32" (ByVal hKey As Long, ByVal bWatchSubTree As Boolean, ByVal dwNotifyFilter As Long, ByVal hEvent As Long, ByVal fAsynchronous As Boolean) As Long
Private Declare Function RegOpenKey Lib "advapi32.dll" Alias "RegOpenKeyA" (ByVal hKey As Long, ByVal lpSubKey As String, phkResult As Long) As Long
Private Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) As Long
Private Declare Function CreateEvent Lib "kernel32" Alias "CreateEventA" (ByVal lpEventAttributes As Long, ByVal bManualReset As Long, ByVal bInitialState As Long, ByVal lpName As String) As Long
Private Declare Function ResetEvent Lib "kernel32" (ByVal hEvent As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Const WAIT_ABANDONED = &H80
Private Const WAIT_FAILED = &HFFFFFFFF
Private Const WAIT_OBJECT_0 = &H0
Private Const WAIT_TIMEOUT = &H102&
Public hEvent As Long, bExit As Boolean
Public Sub RegMonitor(hKey As ROOT_KEYS, sRegKeyPath As String, bWatchSubTree As Boolean, dwFilters As NOTIFY_EVENTS)
Dim lKeyHandle As Long, lRet As Long
hEvent = CreateEvent(0, True, False, vbNullString)
lRet = RegOpenKey(hKey, sRegKeyPath, lKeyHandle)
RegNotifyChangeKeyValue lKeyHandle, bWatchSubTree, dwFilters, hEvent, True
Do
DoEvents
lRet = WaitForSingleObject(hEvent
If bExit Then Exit Do
If lRet = WAIT_OBJECT_0 Then
MsgBox "Change!"
ResetEvent hEvent
RegNotifyChangeKeyValue lKeyHandle, bWatchSubTree, dwFilters, hEvent, True
End If
Loop
lRet = RegCloseKey(lKeyHandle)
End
End Sub
'=========Form code=========
Private Sub Command1_Click()
Dim cap As String
sChange = ""
cap = Caption
Caption = "Monitoring..."
Label1 = "Try to change HKEY_CURRENT_USER\Software
Label1 = Label1 & vbCrLf & "or any other key under HKCU\Software\VB and VBA Program Settings with RegEdit"
Call RegMonitor(HKEY_CURRENT_US
Caption = cap
End Sub
Private Sub Form_Load()
Label1 = "Application created a temporary registry key:"
Label1 = Label1 & vbCrLf & "HKEY_CURRENT_USER\Softwar
Label1 = Label1 & vbCrLf & "Press command button to start monitoring."
'Create a temporary registry key
SaveSetting "Registry Notification", "Hello", "Testing", "123"
End Sub
Private Sub Form_Unload(Cancel As Integer)
bExit = True
CloseHandle hEvent
End Sub