[WinAPI] Cum monitorizez o cheie din registry?

Folosire Windows API in programe C/C++ (forum moderat)
Post Reply
User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

[WinAPI] Cum monitorizez o cheie din registry?

Post by Ovidiu Cucu » 19 Oct 2007, 21:29

Intrebare
Cum pot sa monitorizez un o cheie din registry sa vad, de exemplu, cand o valoare a fost adaugata, stearsa, sau modificata?

Raspuns
Simplu, cu ajutorul functiei RegNotifyChangeKeyValue.

Exemplu

Code: Select all

struct WATCHDOGTHREADPARAM
{
   HKEY hKey;
   LPCTSTR pszSubKey;
   DWORD dwThreadID;
};   

DWORD WINAPI RegistryValuesWatchDogThread(LPVOID lpParam)
{
   WATCHDOGTHREADPARAM* pWdtp = (WATCHDOGTHREADPARAM*)lpParam;

   DWORD dwRet      = 0;
   HKEY   hWatchKey = NULL;

   LONG nRet = ::RegOpenKeyEx(pWdtp->hKey, 
                              pWdtp->pszSubKey, 0, KEY_NOTIFY, &hWatchKey);
   if(ERROR_SUCCESS != nRet)
   {
      // Handle error
      return nRet;
   }
   // infinite loop; exit on any error.
   while(true)
   {
      // Watch the registry key for a value add, delete, or change.
      DWORD  dwFilter = REG_NOTIFY_CHANGE_LAST_SET;
      
      nRet = ::RegNotifyChangeKeyValue(hWatchKey, TRUE, dwFilter, NULL, FALSE);
      if(ERROR_SUCCESS != nRet)
      {
         // Handle error
         ::RegCloseKey(hWatchKey);
         return nRet;
      }
      // Bark, bark!!! A value was added, deleted, or changed.
      // Loop to watch again.
   }
   ::RegCloseKey(hWatchKey);
   return 0;
}
   // ... somewhere ...
   static __declspec(thread) WATCHDOGTHREADPARAM wdtp;
   wdtp.dwThreadID = ::GetCurrentThreadId();
   wdtp.hKey = HKEY_CURRENT_USER;
   wdtp.pszSubKey = _T("software\\microsoft\\notepad");

   HANDLE hWatchThread = ::CreateThread(NULL, 0, RegistryValuesWatchDogThread, 
                                        &wdtp, CREATE_SUSPENDED, NULL);
   ::SetThreadPriority(hWatchThread, THREAD_PRIORITY_BELOW_NORMAL);
   ::ResumeThread(hWatchThread);

<< Back to Windows API Index



User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

[WinAPI] Cum monitorizez o cheie din registry?

Post by Ovidiu Cucu » 24 Oct 2007, 01:06

In primul exemplu, am pus ultimul argument al functiei RegNotifyChangeKeyValue (fAsynchronous) pe FALSE. Asta inseamna ca se comporta ca o "functie wait" si nu se trece mai departe pana cand nu este semnalata modificarea corespunzatoare.
O alta posibilitate este de a pasa TRUE in fAsynchronous si un handle de event in parametrul hEvent.
In acest caz functia intoarce imediat, iar mai departe se poate folosi WaitForSingleObject sau WaitForMultipleObjects.

Exemplu

Code: Select all

#include <windows.h>
#include <TCHAR.H>

#define WM_APP_REGISTRY_CHANGED (WM_APP+1)

struct WATCHDOGTHREADPARAM
{
   HKEY hKey;
   LPCTSTR pszSubKey;
   DWORD dwThreadID;
};   

DWORD WINAPI RegistryValuesWatchDogThread(LPVOID lpParam)
{
   WATCHDOGTHREADPARAM* pWdtp = (WATCHDOGTHREADPARAM*)lpParam;
   
   const int nEventsCount = 4;
   HKEY   hWatchKey[nEventsCount];
   HANDLE hEvents[nEventsCount];

   // infinite loop; exit on any error.
   while(true)
   {
      DWORD  dwFilter = REG_NOTIFY_CHANGE_NAME;
      for(int nIndex = 0; nIndex < nEventsCount; nIndex++)
      {
         // open a key for each 
         LONG nRet = ::RegOpenKeyEx(pWdtp->hKey, 
                                    pWdtp->pszSubKey, 0, KEY_NOTIFY, &hWatchKey[nIndex]);
         if(ERROR_SUCCESS != nRet)
         {
            // Handle error, close open key handles, then return
            for(int i = 0; i < nIndex; i++) 
               ::RegCloseKey(hWatchKey[nIndex]);
            return nRet;
         }
         // create an event for each change filter value
         hEvents[nIndex] = ::CreateEvent(NULL, TRUE, FALSE, NULL);
         // call RegNotifyChangeKeyValue and pass an event handle
         nRet = ::RegNotifyChangeKeyValue(hWatchKey[nIndex], TRUE, dwFilter, 
                                          hEvents[nIndex], TRUE);
         if(ERROR_SUCCESS != nRet)
         {
            // Handle error, close open key handles, then return
            for(int i = 0; i <= nIndex; i++) 
               ::RegCloseKey(hWatchKey[nIndex]);
            return nRet;
         }
         // (a little bit tricky code) REG_NOTIFY_CHANGE_NAME to REG_NOTIFY_CHANGE_SECURITY 
         // have values 0x1, 0x2, 0x4, and 0x8, respectively.
         dwFilter <<= 1;
      }
      // wait for one of the four events to be signaled
      DWORD dwRet = ::WaitForMultipleObjects(nEventsCount, hEvents, FALSE, INFINITE);
      UINT nChange = 0;

      if(WAIT_OBJECT_0 == dwRet) //  a subkey is added, deleted, or renamed
         nChange = REG_NOTIFY_CHANGE_NAME; 
      else if((WAIT_OBJECT_0  + 1) == dwRet) // key attributes are changed
         nChange = REG_NOTIFY_CHANGE_ATTRIBUTES; 
      else if((WAIT_OBJECT_0  + 2) == dwRet) // a value is changed
         nChange = REG_NOTIFY_CHANGE_LAST_SET;
      else if((WAIT_OBJECT_0  + 3) == dwRet) // security descriptor of the key is changed
         nChange = REG_NOTIFY_CHANGE_SECURITY;

      // notify the "parent" thread
      ::PostThreadMessage(pWdtp->dwThreadID, WM_APP_REGISTRY_CHANGED, (WPARAM)nChange, 0);
      
      // close event and registry key handles 
      for(nIndex = 0; nIndex < nEventsCount; nIndex++)
      {
         ::CloseHandle(hEvents[nIndex]);
         ::RegCloseKey(hWatchKey[nIndex]);
      }
      // loop to watch again.
   }
   return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
   static __declspec(thread) WATCHDOGTHREADPARAM wdtp;
   wdtp.dwThreadID = ::GetCurrentThreadId();
   wdtp.hKey = HKEY_CURRENT_USER;
   wdtp.pszSubKey = _T("software\\microsoft\\notepad");

   HANDLE hWatchThread = ::CreateThread(NULL, 0, RegistryValuesWatchDogThread, 
                                        &wdtp, CREATE_SUSPENDED, NULL);
   ::SetThreadPriority(hWatchThread, THREAD_PRIORITY_BELOW_NORMAL);
   ::ResumeThread(hWatchThread);
// ....
// ....
}

<< Back to Windows API Index

Post Reply