Registry Change Notifications

[Previous] [Next]

Another way to more effectively use the registry is to take advantage of registry change notifications. An application can be efficiently notified of changes made within a registry key by using the RegNotifyChangeKeyValue function. This function allows you to tell the system what type of changes you want to be notified of and whether or not you wish to be notified of changes made within subkeys. Here is the function prototype:

 LONG RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubtree, DWORD dwNotifyFilter, HANDLE hEvent, BOOL fAsynchronous); 

The hkey parameter identifies the key for which you want to receive change notifications. The fWatchSubtree parameter indicates whether you want to be notified of changes within the entire tree below the specified key. The dwNotifyFilter parameter indicates which changes you want to be notified of. The dwNotifyFilter parameter can take any combination of the flags listed in Table 5-5.

Table 5-5. Flags that can be passed for RegNotifyChangeKeyValue's dwNotifyFilter parameter

Notification Flags Description
REG_NOTIFY_CHANGE_NAME Notification occurs when a subkey is added or deleted.
REG_NOTIFY_CHANGE_ATTRIBUTES Notification occurs when the attributes of the key, including the security descriptor information, changes.
REG_NOTIFY_CHANGE_LAST_SET Notification occurs when the value of the key, including the addition or deletion of values, changes.
REG_NOTIFY_CHANGE_SECURITY Notification occurs when the security descriptor of the key changes.

The RegNotifyChangeKeyValue function can be used in one of two ways: synchronously or asynchronously. To use the function synchronously, pass FALSE as the value of fAsynchronous. In a synchronous call to RegNotifyChangeKeyValue, the calling thread is suspended until a registry notification occurs. If you want to use the function asynchronously, you must pass a valid event handle in the hEvent parameter and TRUE for the fAsynchronous parameter. Calling the function asynchronously causes the function to return immediately. The system will automatically signal the event kernel object when the next registry change (matching the specified filter) occurs.

I prefer the asynchronous feature of RegNotifyChangeKeyValue because it does not waste threads in your process. Remember that whether you are using the function asynchronously or not, each call to RegNotifyChangeKeyValue is good for only a single notification. The function must be called repeatedly for you to receive future notifications.

NOTE
If the thread that called RegNotifyChangeKeyValue terminates, the system cancels the request for notification. This is typically not a problem, because commonly the thread waiting on the event is the same thread that called RegNotifyChangeKeyValue.

If the thread that called RegNotifyChangeKeyValue does terminate before a change notification occurs, the system signals the event, releasing any threads waiting on that event.

NOTE
To cause a thread to return from a synchronous call to RegNotifyChangeKeyValue without making a change to the key, your application must close the handle to the registry key.

The RegNotify Sample Application

The RegNotify sample application ("05 RegNotify.exe"), shown in Listing 52, demonstrates the asynchronous use of the RegNotifyChangeKeyValue function. The source code and resource files for the application are in the 05-RegNotify directory on the companion CD. The program simply monitors notifications for a registry key specified by the user.

When RegNotify is executed, the user enters a registry key for which he wants to receive automatic change notifications. The user then clicks the Watch button to begin the notification process for the specified registry key. Figure 5-4 shows the RegNotify sample application after new values have been added to the key being watched.

Figure 5-4. The dialog box for the RegNotify sample application after three new values have been added to HKLM\SOFTWARE\RegNotify

The notification process works like this: The RegNotify application creates a second thread, which enters into a loop that calls RegNotifyChangeKeyValue repeatedly for the selected key, enabling display of the value information in the read-only edit control. Each time a notification occurs, the event is signaled, causing WaitForSingleObjectEx to return WAIT_OBJECT_0. A return value of WAIT_OBJECT_0 causes the function to loop again for another notification.

When the user closes the application, the primary thread posts a user-mode asynchronous procedure call (APC) to the notification thread, which causes WaitForSingleObjectEx to exit with the value WAIT_IO_COMPLETION. The loop exits, causing the notification thread to exit.

NOTE
Using an APC as a form of interthread communication is sometimes desirable because it can be more efficient. It does not require the creation of a kernel object such as a semaphore or an event. When you use an APC for interthread communication, you frequently must create an APC callback function that is used as nothing other than a placeholder function for an APC.

If you have not seen this technique in the past, the empty placeholder function can be initially confusing. For more information on this technique and other interthread communication mechanisms, see Chapter 2.

Listing 5-2. The RegNotify sample application

 

RegNotify.cpp

/****************************************************************************** Module: RegNotify.cpp Notices: Copyright (c) 2000 Jeffrey Richter ******************************************************************************/ #include "..\CmnHdr.h" // See Appendix A. #include <WindowsX.h> #include <Process.h> // For _beginthreadex #include "Resource.h" #define UILAYOUT_IMPL #include "..\ClassLib\UILayout.h" // See Appendix B. /////////////////////////////////////////////////////////////////////////////// CUILayout g_UILayout; // Repositions controls when dialog box size changes. /////////////////////////////////////////////////////////////////////////////// // We are using this function in place of an event object to let the thread // know that it is time to exit its primary loop. void WINAPI DoNothingAPC(ULONG_PTR dwParam) { } /////////////////////////////////////////////////////////////////////////////// DWORD WINAPI RegSubkeyWatcher(PVOID pv) { HWND hwnd = (HWND) pv; // Create our event for notification HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); TCHAR szSubkey[200]; // Get the Reg Key that we are going to create or open for watching GetDlgItemText(hwnd, IDC_REGKEY, szSubkey, chDIMOF(szSubkey)); // Get our registry key to watch. HKEY hkey = NULL; RegCreateKeyEx(HKEY_LOCAL_MACHINE, szSubkey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_NOTIFY | KEY_QUERY_VALUE, NULL, &hkey, NULL); do { DWORD dwIndex = 0, cbValName; BYTE bData[1024]; TCHAR szValName[100]; cbValName = chDIMOF(szValName); DWORD dwType, cbData = chDIMOF(bData); TCHAR szRegVals[20 * 1024] = { 0 }; // RegEnumValue to enumerate the values in the key while (ERROR_SUCCESS == RegEnumValue(hkey, dwIndex++, szValName, (cbValName = chDIMOF(szValName), &cbValName), NULL, &dwType, bData, (cbData = chDIMOF(bData), &cbData))) { PTSTR p = szRegVals + lstrlen(szRegVals); wsprintf(p, TEXT("\r\n%s\t"), szValName); p = szRegVals + lstrlen(szRegVals); // Handle the different types switch (dwType) { case REG_DWORD: wsprintf(p, TEXT("0x%08x"), * (PDWORD) bData); break; case REG_EXPAND_SZ: case REG_LINK: case REG_MULTI_SZ: case REG_RESOURCE_LIST: case REG_SZ: wsprintf(p, TEXT("%s"), bData); break; case REG_NONE: case REG_DWORD_BIG_ENDIAN: default: wsprintf(p, TEXT("Unknown type")); break; case REG_BINARY: for (DWORD x = 0; x < cbData; x++) wsprintf(p + lstrlen(p), TEXT("%02X "), bData[x]); break; } } // Set the display SetDlgItemText(hwnd, IDC_REGVALUES, &szRegVals[2]); // skip "\r\n" // Set up the notification... notice we have to do this each time. // It is also important that the thread that makes the call to // RegNotifyChangeKeyValue be the one that waits on the event. RegNotifyChangeKeyValue(hkey, FALSE, REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY, hEvent, TRUE); // Wait forever for the event or the APC } while (WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == WAIT_OBJECT_0); // We are done with the event and key CloseHandle(hEvent); RegCloseKey(hkey); return(0); } /////////////////////////////////////////////////////////////////////////////// BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) { chSETDLGICONS(hwnd, IDI_REGNOTIFY); // Set up the resizeing of the controls g_UILayout.Initialize(hwnd); g_UILayout.AnchorControl(CUILayout::AP_TOPLEFT, CUILayout::AP_BOTTOMRIGHT, IDC_REGVALUES, FALSE); g_UILayout.AnchorControl(CUILayout::AP_TOPLEFT, CUILayout::AP_TOPRIGHT, IDC_REGKEY, FALSE); SetDlgItemText(hwnd, IDC_REGKEY, TEXT("SOFTWARE\\RegNotify")); return(TRUE); } /////////////////////////////////////////////////////////////////////////////// void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { static HANDLE s_hThread = NULL; switch (id) { case IDCANCEL: if (s_hThread != NULL) { // Queue the useless APC function to signal the exit of our // other thread QueueUserAPC(DoNothingAPC, s_hThread, 0); // Wait for the thread to exit WaitForSingleObject(s_hThread, INFINITE); CloseHandle(s_hThread); s_hThread = NULL; } EndDialog(hwnd, id); break; case IDOK: // Disable our button EnableWindow(hwndCtl, FALSE); // Start the notification thread s_hThread = chBEGINTHREADEX(NULL, 0, RegSubkeyWatcher, hwnd, 0, NULL); break; } } /////////////////////////////////////////////////////////////////////////////// void Dlg_OnSize(HWND hwnd, UINT state, int cx, int cy) { // Reposition the child controls g_UILayout.AdjustControls(cx, cy); } /////////////////////////////////////////////////////////////////////////////// void Dlg_OnGetMinMaxInfo(HWND hwnd, PMINMAXINFO pMinMaxInfo) { // Return minimum size of dialog box g_UILayout.HandleMinMax(pMinMaxInfo); } /////////////////////////////////////////////////////////////////////////////// INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog); chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand); chHANDLE_DLGMSG(hwnd, WM_SIZE, Dlg_OnSize); chHANDLE_DLGMSG(hwnd, WM_GETMINMAXINFO, Dlg_OnGetMinMaxInfo); } return(FALSE); } /////////////////////////////////////////////////////////////////////////////// int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, LPTSTR pszCmdLine, int) { DialogBox(hinstExe, MAKEINTRESOURCE(IDD_REGNOTIFY), NULL, Dlg_Proc); return(0); } //////////////////////////////// End of File //////////////////////////////////



Programming Server-Side Applications for Microsoft Windows 2000
Programming Server-Side Applications for Microsoft Windows 2000 (Microsoft Programming)
ISBN: 0735607532
EAN: 2147483647
Year: 2000
Pages: 126

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net