WIn32API レジストリの変更を検知する RegNotifyChangeKeyValue

レジストリキーの属性やエントリが変更されたことを検知するためには、RegNotifyChangeKeyValue関数を用いる。
RegNotifyChangeKeyValue関数は、レジストリが変更されたことをアプリケーションに通知してくれる。


RegNotifyChangeKeyValue関数のプロトタイプは、以下のようになっている。

LONG RegNotifyChangeKeyValue(
  HKEY hKey,             // 監視するべきキーのハンドル
  BOOL bWatchSubtree,    // サブキー監視オプション
  DWORD dwNotifyFilter,  // 通知するべき変更
  HANDLE hEvent,         // 発生させるべきイベントのハンドル
  BOOL fAsynchronous     // 変更の通知方法を示すフラグ
);


dwNotifyFilterには、以下の値を組み合わせて通知すべき変更のタイプを指定する。

説明
REG_NOTIFY_CHANGE_NAMEサブキーの追加または削除が発生するときに通知する
REG_NOTIFY_CHANGE_ATTRIBUTESキーの属性の変更が発生した時に通知する
REG_NOTIFY_CHANGE_LAST_SETキー内のレジストリエントリの変更が生じた時に通知する
REG_NOTIFY_CHANGE_SECURITYキーのセキュリティ記述しの変更が発生した際に通知する



  • イベントオブジェクトを使用したサンプルプログラム

  • RegNotifyChangeKeyValue関数を呼び出したあとに、WaitForSingleObjectでレジストリの変更通知を待機する。変更通知を受け取るとWaitForSingleObjectは制御を返し、ResetEventを呼び出すことにより、再び変更通知を待機する準備を行う。

    #include <windows.h>
    #include <stdio.h>
    
    int main()
    {
        HANDLE hEvent = NULL;
        HKEY hKey = NULL;
    
        hEvent = CreateEvent(NULL, TRUE, FALSE, TEXT("RegistryNotificationEvent"));
        if (hEvent == NULL) {
            puts("CreateEvent error");
            goto EXIT_FUNC;    
        }
        
        //レジストリの変更通知を受けるためにはKEY_NOTIFYアクセス属性が必要となる
        if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Test"), 0, KEY_NOTIFY, &hKey) != ERROR_SUCCESS) {
            puts("RegOpenKeyEx error");
            goto EXIT_FUNC;
        }
        
        for (;;) {
    
            //サブキーの追加、削除とキー内のレジストリエントリの変更を監視する
            if (RegNotifyChangeKeyValue(hKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, hEvent, TRUE) != ERROR_SUCCESS) {
                puts("RegNotifyChangeKeyValue error");
                break;
            }
    
            //ここでブロッキング状態となる
            //レジストリの変更が生じるとWaitForSingleObjectが制御を返す
            if (::WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0) {
                puts("Registry Change Notification");
            } else {
                break;
            }
    
            if (ResetEvent(hEvent) == FALSE) {
                puts("ResetEvent error");
                break;
            }
        }
    
    EXIT_FUNC:
        if (hKey != NULL) {
            RegCloseKey(hKey);
        }
        if (hEvent != NULL) {
            CloseHandle(hEvent);
        }
    
        puts("Exit");
        
        return 0;
    }





  • イベントオブジェクトを使用しないサンプルプログラム

  • イベントオブジェクトを使用しない場合は、RegNotifyChangeKeyValue関数でブロッキング状態になる。レジストリ変更通知を受け取るとRegNotifyChangeKeyValue関数は制御を返す。

    #include <windows.h>
    #include <stdio.h>
    
    int main()
    {
        HKEY hKey = NULL;
    
        //レジストリの変更通知を受けるためにはKEY_NOTIFYアクセス属性が必要となる
        if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Test"), 0, KEY_NOTIFY, &hKey) != ERROR_SUCCESS) {
            puts("RegOpenKeyEx error");
            goto EXIT_FUNC;
        }
        
        for (;;) {
    
            //ここでブロッキング状態となる
            //レジストリの変更通知を受け取ると、RegNotifyChangeKeyValueは制御を返す
            if (RegNotifyChangeKeyValue(hKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, NULL, FALSE) != ERROR_SUCCESS) {
                puts("RegNotifyChangeKeyValue error");
                break;
            }
            puts("Registry Change Notification");
        }
    
    EXIT_FUNC:
        if (hKey != NULL) {
            RegCloseKey(hKey);
        }
        
        puts("Exit");
        
        return 0;
    }




    上記のプログラム(イベントオブジェクトを使用する版/しない指版のいずれか)を実行して、監視対象のレジストリの属性やエントリ等の変更を行うと、変更の通知を受けることができる。





    参考
    http://msdn.microsoft.com/ja-jp/library/cc429920.aspx