I have written a couple of articles about my trials at getting CeRegGetNotificationInfo() to work (see Windows CE: CeRegGetNotificationInfo() Doesn’t Seem to Work and Windows CE: CeRegGetNotificationInfo() Doesn’t Seem to Work Part 2). Well, I have it working and think that I understand its limits now. Special thanks to Luca Calligaris, colleague and fellow MVP for his assistance in figuring this out. My hope is that our work will help others out when they need to monitor for changes to the registry.
We figured the following out. I will state some things as facts, but frankly I don’t know for sure.
1.       CeRegGetNotificationInfo()returns zero on success. Note that this is contrary to the documentation.
2.       CeRegGetNotificationInfo() only returns results for the key being watched, it does not return results for the sub-tree.
3.       CeRegGetNotificationInfo() does return non-zero on catastrophic failure, like passing in all zeros.
4.       If something goes wrong in CeRegGetNotificationInfo() it does not write anything to the data structure passed in. This means that you should clear the structure before calling CeRegGetNotificationInfo().
5.       CeRegGetNotificationInfo() will only return data if FILE_NOTIFY_CHANGE_CEGETINFO is included in the dwNotifyFilter parameter.
Now the code, which is not much different from the original that I posted, but this does work. For this, I am including the code from Windows CE: Monitor for Registry Changes again, but with an important modification. This time FILE_NOTIFY_CHANGE_CEGETINFO has been added to the dwNotifyFilter parameter.  This time I also change the bWatchSubTree to MONITOR_KEY because CeRegGetNotificationInfo() doesn’t work with the sub tree. By doesn’t work, I mean it doesn’t return any data.
I also put the code for CeRegGetNotificationInfo() in a separate function, mainly so that the code is more readable (but isn’t that one of the reasons to use functions?)
#include <Windows.h>
#include <winreg.h>
 
 
#define MONITOR_TREE              TRUE
#define MONITOR_KEY                                FALSE
 
 
int WINAPI WinMain(     HINSTANCE hInstance,
                                                HINSTANCE hPrevInstance,
                                                LPTSTR    lpCmdLine,
                                                int       nCmdShow)
{
                HKEY hkDrivers;
                HANDLE hFind;
                DWORD Status;
 
                RETAILMSG( 1, (TEXT("RegMon Started\r\n")));
                if( ERROR_SUCCESS != RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("Drivers"), 0, 0, &hkDrivers ) )
                {
                                RETAILMSG( 1, (TEXT("Failed to open HKLM\\Drivers\r\n")));
                                return 0;
                }
 
                hFind = CeFindFirstRegChange( hkDrivers, MONITOR_KEY, FILE_NOTIFY_CHANGE_CEGETINFO | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET );
 
                if( hFind != INVALID_HANDLE_VALUE )
                {
                                do{
                                                Status = WaitForSingleObject( hFind, INFINITE );
                                                if( Status == WAIT_OBJECT_0 )
                                                {
                                                                HandleRegNotify( hFind );
                                                                CeFindNextRegChange( hFind );
                                                }
                                                else if( Status == WAIT_FAILED )
                                                                break;
 
                                } while( 1 );
 
                                CeFindCloseRegChange( hFind );
                }
 
                RETAILMSG( 1, (TEXT("RegMon Done\r\n")));
                return 1;
}
 
 
 
Now HandleRegNotify() which is called when a registry change is signaled.   When it is called, it:
1.       Calls CeRegGetNotificationInfo() to find out how much data is available
2.       Allocates space for the data
3.       Calls CeRegGetNotificationInfo() to get the data
4.       Outputs the data on the debug serial port
void HandleRegNotify( HANDLE hFind )
{
                REG_NOTIFY_INFORMATION *RegInfo = NULL;
                REG_NOTIFY_INFORMATION *NextRegInfo;
                DWORD BytesAvailable;
                DWORD BytesReturned;
 
                // Call once to find out how many bytes of data are available
                if( !CeRegGetNotificationInfo( hFind, 0, NULL, 0, NULL, &BytesAvailable ) )
                {
                                DWORD Error = GetLastError();
                                if( Error != 0 && Error != ERROR_INSUFFICIENT_BUFFER )
                                                RETAILMSG( 1, (TEXT("CeRegGetNotificationInfo failed %d\r\n"), Error ));
                }
 
                if( BytesAvailable != 0 )
                {
                                RegInfo = (REG_NOTIFY_INFORMATION *)malloc( BytesAvailable );
                                if( RegInfo )
                                {
                                                // Set the newly allocated buffer to zero. If anything goes wrong,
                                                // CeRegGetNotificationInfo won't set the data.
                                                memset( RegInfo, 0, BytesAvailable );
                                                if( !CeRegGetNotificationInfo( hFind, 0, RegInfo, BytesAvailable, &BytesReturned, &BytesAvailable ) )
                                                {
                                                                NextRegInfo = RegInfo;
                                                                do
                                                                {
                                                                                switch( NextRegInfo->Action )
                                                                                {
                                                                                                case FILE_ACTION_ADDED:
                                                                                                                RETAILMSG( 1, (TEXT("Action Added\r\n")));
                                                                                                                break;
                                                                                                case FILE_ACTION_MODIFIED:
                                                                                                                RETAILMSG( 1, (TEXT("Action Modified\r\n")));
                                                                                                                break;
                                                                                                case FILE_ACTION_REMOVED:
                                                                                                                RETAILMSG( 1, (TEXT("Action Deleted\r\n")));
                                                                                                                break;
                                                                                                default:
                                                                                                                RETAILMSG( 1, (TEXT("Action NONE\r\n")));
                                                                                                                break;
                                                                                }
                                                                                if( NextRegInfo->RegNameLength )
                                                                                {
                                                                                                TCHAR *RegStr = (TCHAR *)malloc((NextRegInfo->RegNameLength + 1 ) * sizeof(TCHAR));
                                                                                                wcsncpy( RegStr, NextRegInfo->RegName, NextRegInfo->RegNameLength );
                                                                                                RegStr[ NextRegInfo->RegNameLength ] = '\0';
                                                                                                RETAILMSG( 1, (TEXT("Changed %s\r\n"), RegStr ));
                                                                                                free( RegStr );
                                                                                }
                                                                                NextRegInfo = (REG_NOTIFY_INFORMATION*)( (DWORD)NextRegInfo + NextRegInfo->NextEntryOffset );
                                                                }while( NextRegInfo->NextEntryOffset );
                                                }
                                                else
                                                                RETAILMSG( 1, (TEXT("CeRegGetNotificationInfo failed %d\r\n"), GetLastError() ));
                                                free( RegInfo );
                                                RegInfo = NULL;
                                }
                }
}
 
 
Copyright © 2009 – Bruce Eitman
All Rights Reserved