Microsoft KB Archive/236570

{|
 * width="100%"|

PRB: RegNotifyChangeKeyValue Sets Long-Term Association with Key

 * }

Q236570

-

The information in this article applies to:


 * Microsoft Win32 Application Programming Interface (API), included with:
 * the operating system: Microsoft Windows NT
 * the operating system: Microsoft Windows 2000
 * Microsoft Windows 98

-

SYMPTOMS
The RegNotifyChangeKeyValue API allows an application to receive event notifications for changes within a specified registry key and its subkeys.

On Windows NT and Windows 2000 calling RegNotifyChangeKeyValue for a particular key handle causes change notifications to continue to occur for as long as the key handle is valid. This causes a second call to RegNotifyChangeKeyValue to return immediately, if any changes have occurred in the interim period between the first and second calls. If the API is being used asynchronously, the passed event handle will be signaled immediately if any interim changes have occurred.

Windows 98 does not keep track of interim changes. Calling RegNotifyChangeKeyValue only notifies you of changes occurring after the call.

RESOLUTION
You may not care about interim changes. Instead, you want to only receive notifications for future changes that occur after the calls RegNotifyChangeKeyValue.

Either of the following approaches can be used to make sure that notifications are not received for interim changes:


 * Close and reopen the key.
 * Use RegNotifyChangeKeyValue asynchronously and wait on the event using WaitForSingleObject with a zero timeout.

STATUS
This behavior is by design.

MORE INFORMATION
There are a couple of things to keep in mind when dealing with registry change notifications:

As with the file change notification APIs, RegNotifyChangeKeyValue does not return any indication as to what has changed in the registry key or its subkeys or values. The program must know the state of the keys or values prior to the notification, so that it can determine what has changed.

There is not a one-to-one relationship between changes and notifications. When a change notification is received, there actually may have been numerous registry changes.

Sample Code
Those who have worked with file change notifications, know that FindFirstChangeNotification can be used to receive only notifications for future changes in a directory. Interim file changes can then be received using FindNextChangeNotification. This ensures that notifications are not missed. Unfortunately, there are no built-in analogous functions for registry change notifications. The following sample code demonstrates how to implement these functions using the second approach listed in the "Resolution" section. The following functions are implemented:


 * RegFindFirstChange
 * RegFindNextChange
 * RegFindCloseChange

//********************************************************************** // // This program demonstrates how to work with registry change // notifications. In particular, it shows how to either receive // or ignore interim registry changes (for example, those that occur in //  the period between receiving a notification and the next call //  to RegNotifyChangeKeyValue. // //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF //  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED //  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A //  PARTICULAR PURPOSE. // //  Copyright (C) 1999 Microsoft Corporation. All rights reserved. // //**********************************************************************


 * 1) include 
 * 2) include 
 * 3) include 
 * 4) include 

// defined constants
 * 1) define MONITOR_TOPKEY HKEY_LOCAL_MACHINE
 * 2) define MONITOR_SUBKEY TEXT("Software\\Temp")

// structure used internally by RegFindFirst/NextChange typedef struct _REG_CHANGE_DATA { HKEY  hKey; BOOL  bWatchSubtree; DWORD dwNotifyFilter; } REG_CHANGE_DATA, *LPREG_CHANGE_DATA;

// function prototypes HANDLE RegFindFirstChange( HKEY hKey, BOOL bWatchSubtree,      DWORD dwNotifyFilter, LPREG_CHANGE_DATA lprcd );

BOOL RegFindNextChange( HANDLE hChange, LPREG_CHANGE_DATA lprcd );

BOOL RegFindCloseChange( HANDLE hChange );

void DisplayError( LPTSTR szAPI, DWORD dwError );

//********************************************************************** // // _tmain -- becomes main for ANSI or wmain for Unicode // // PURPOSE :     This is the entry point for the program. This function //               contains sample code demonstrating how to use the //               RegFind* functions implemented below. // // PARAMETERS:   None // // RETURN VALUE: None // //**********************************************************************

void _tmain( void ) {

DWORD dwFilter; LONG  lResult; HKEY  hKey; char  ch; HANDLE hChange   = NULL; BOOL  bContinue  = TRUE; REG_CHANGE_DATA  rcd;

// open the key to be monitored lResult = RegOpenKeyEx( MONITOR_TOPKEY, MONITOR_SUBKEY,         0, KEY_READ, &hKey );

if ( lResult != ERROR_SUCCESS ) DisplayError( "RegOpenKeyEx", lResult );

__try {

// filter for all registry changes dwFilter = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY;

while ( bContinue ) {

_tprintf( TEXT("'f' FindFirst; 'n' FindNext; 'q' Quit --> ") ); ch = _getche; _tprintf( TEXT("\n") );

switch ( ch ) {

case 'f': case 'F': // FindFirst // close old handle, if it exists if ( hChange ) RegFindCloseChange( hChange );

hChange = RegFindFirstChange( hKey, TRUE, dwFilter, &rcd ); if ( hChange == NULL ) DisplayError( TEXT("RegFindFirstChange"),                        GetLastError ); break;

case 'n': case 'N': // FindNext if ( !RegFindNextChange( hChange, &rcd ) ) DisplayError( TEXT("RegFindNextChange"),                        GetLastError ); break;

case 'q': case 'Q': // Quit

__leave; break;

}

// wait on the handle, if it exists if ( hChange ) { _tprintf( TEXT("Waiting...\n") ); WaitForSingleObject( hChange, INFINITE ); _tprintf( TEXT("Registry change notification received\n") ); }

}

} __finally {

// close change handle, if it exists if ( hChange ) RegFindCloseChange( hChange );

// close key handle RegCloseKey( hKey );

}

}

//********************************************************************** // // RegFindFirstChange // // PURPOSE:      This function begins a registry change notification //               cycle. It will never return a handle that is already //               signaled due to interim change notifications. // //               After a call to RegFindFirstChange, a call to //                RegFindNextChange ensures that interim //               notifications are not missed. // //               Since this routine allocates resources, it is //                important that each call is matched up with a //                corresponding RegFindCloseChange call to free the //               resources. // // PARAMETERS:   hKey - handle to the key to watch // //               bWatchSubtree - indicates whether or not to receive //               notifications for changes in subkeys // //               dwNotifyFilter - identifies which changes should cause //               notifications to occur // //               lprcd - pointer to a REG_CHANGE_DATA structure used //               to cycle through the changes // // RETURN VALUE: If the function succeeds, a wait able handle is //                returned. If it fails, NULL is returned and a call to //               GetLastError identifies why it failed. // //**********************************************************************

HANDLE RegFindFirstChange( HKEY hKey, BOOL bWatchSubtree,      DWORD dwNotifyFilter, LPREG_CHANGE_DATA lprcd ) {

LONG lResult; HANDLE hChange;

lprcd->hKey = hKey; lprcd->bWatchSubtree = bWatchSubtree; lprcd->dwNotifyFilter = dwNotifyFilter;

// create event to be signaled when changes occur hChange = CreateEvent( NULL, TRUE, FALSE, NULL );

// request registry change notifications lResult = RegNotifyChangeKeyValue( lprcd->hKey,        lprcd->bWatchSubtree, lprcd->dwNotifyFilter,          hChange, TRUE );

if ( lResult != ERROR_SUCCESS ) { SetLastError( lResult ); return NULL; }

// It is possible that this key handle has been used to receive // registry notifications already. Thus, you will wait with a timeout // of zero to clear interim notifications that might have occurred if ( WaitForSingleObject( hChange, 0 ) == WAIT_OBJECT_0 ) {

// There were some interim changes; they are cleared now, but // you must call the API again to request future notifications lResult = RegNotifyChangeKeyValue( lprcd->hKey,            lprcd->bWatchSubtree, lprcd->dwNotifyFilter,             hChange, TRUE );

if ( lResult != ERROR_SUCCESS ) { SetLastError( lResult ); return NULL; }  }

return hChange; }

//********************************************************************** // // RegFindNextChange // // PURPOSE:      This function queues the next registry change //               notification in a cycle. It must be preceded by a //               call to RegFindFirstChange. // //               After calling this function, the handle returned by //                RegFindFirstChange can be waited on again to get //               the next change notification. Using these functions //               in this manner, all interim change notifications will //               be caught. // // PARAMETERS:   lprcd - pointer to the same REG_CHANGE_DATA structure //               that was initialized with RegFindFirstChange // // RETURN VALUE: If the function succeeds, it returns TRUE. If it //               fails, it returns FALSE and a call to GetLastError //               identifies why it failed. // //**********************************************************************

BOOL RegFindNextChange( HANDLE hChange, LPREG_CHANGE_DATA lprcd ) { LONG lResult;

// reset the event so the handle can be waited on again if ( !ResetEvent( hChange ) ) return FALSE; // If you call this function, you want to catch interim changes, // so simply call the API again. lResult = RegNotifyChangeKeyValue( lprcd->hKey,        lprcd->bWatchSubtree, lprcd->dwNotifyFilter,          hChange, TRUE );

if ( lResult != ERROR_SUCCESS ) { SetLastError( lResult ); return FALSE; }

return TRUE; }

//********************************************************************** // // RegFindCloseChange // // PURPOSE:      This function frees the resources allocated by a call //               to RegFindFirstChange. // // PARAMETERS:   hChange - the waitable handle returned from //               RegFindFirstChange // // RETURN VALUE: Always TRUE // //**********************************************************************

BOOL RegFindCloseChange( HANDLE hChange ) {

// free event if ( hChange ) { CloseHandle( hChange ); hChange = NULL; }

return TRUE; }

//********************************************************************** // // DisplayError // // PURPOSE :     This is a helper function to display an error message //               and exit the process if a function in _tmain fails. // // PARAMETERS:   szAPI - the name of the function that failed // //               dwError - the Win32 error code indicating why the //               function failed // // RETURN VALUE: None // //**********************************************************************

void DisplayError( LPTSTR szAPI, DWORD dwError ) {

LPTSTR lpBuffer = NULL;

FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |        FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),         (LPTSTR) &lpBuffer, 0, NULL );

_tprintf( TEXT("%s failed:\n"), szAPI ); _tprintf( TEXT("   error code = %u\n"), dwError ); _tprintf( TEXT("   message    = %s\n"), lpBuffer );

LocalFree( lpBuffer ); ExitProcess(0); } Additional query words:

Keywords : kbAPI kbKernBase kbOSWinNT kbOSWin2000 kbRegistry kbSDKPlatform kbSDKWin32 kbOSWin98 kbDSupport kbGrpDSKernBase

Issue type : kbprb

Technology : kbAudDeveloper kbWin32sSearch kbWin32API