2025-11-27 16:46:48 +09:00

291 lines
13 KiB
C++

// ==========================================================================
// Class Specification : COXRegistryWatcher
// ==========================================================================
// Header file : OXRegistryWatcher.h
// Version: 9.3
// //////////////////////////////////////////////////////////////////////////
// Properties :
// NO Abstract class (does not have any objects)
// YES Derived from CObject
// NO Is a Cwnd.
// NO Two stage creation (constructor & Create())
// NO Has a message map
// NO Needs a resource (template)
// NO Persistent objects (saveable on disk)
// NO Uses exceptions
// //////////////////////////////////////////////////////////////////////////
// Description :
// This class can be used to organize Registry change notifications.
// It notifies the caller about changes to the attributes or contents of a specified Registry key.
// All notifications are handled by virtual function, which can be overridden in derived classes.
// COXRegistryWatcher class can also convert notifications to a window message. This message
// can be sent to a specified window and translated there (e.g. by PreTranslateMessage()).
// Note that COXRegistryWatcher doesn't notify the caller if the specified key is deleted.
// Example :
// COXRegistryWatcher RegWatch;
// if ( ::RegOpenKeyEx(hKey, sKeyName, 0, KEY_NOTIFY, &hKeyAdd) == ERROR_SUCCESS && hKeyAdd )
// {
// if ( RegWatch.EnableWindowNotification(RegWatch.AddWatch(hKeyAdd, TRUE), this) )
// TRACE1("Watched Key : %s\n", sKeyName);
// }
// Remark :
// Registry watch is carried out by the separate worker thread.
// Therefore COXRegistryWatcher's Registry watching doesn't "hung" your programs.
// Prerequisites (necessary conditions):
/////////////////////////////////////////////////////////////////////////////
#ifndef __OXREGISTRYWATCHER_H__
#define __OXREGISTRYWATCHER_H__
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#include "OXDllExt.h"
#include "OXMainRes.h"
#include "OXRegistryWatchNotifier.h"
// //////////////////////////////////////////////////////////////////////////
// Definitions of error codes.
#define OX_FACILITY_REGISTRY_WATCHER 0x221
#define OX_STATUS_SEVERITY_SUCCESS 0x0
#define OX_STATUS_SEVERITY_ERROR 0x3
#define OX_CODE_REGISTRY_WATCHER_ERROR_SUCCESS 1
#define OX_CODE_REGISTRY_WATCHER_NO_HKEY 2
#define OX_CODE_REGISTRY_WATCHER_THREAD_FAILURE 3
#define OX_CODE_REGISTRY_WATCHER_EVENT_FAILURE 4
#define OX_CODE_REGISTRY_WATCHER_EMPTY_WATCHER 5
#define OX_CODE_REGISTRY_WATCHER_INCORRECT_HKEY 6
#define OX_CODE_REGISTRY_WATCHER_ALREADY_STARTED 7
#define OX_CODE_REGISTRY_WATCHER_ALREADY_STOPPED 8
#define OX_CODE_REGISTRY_WATCHER_VERSION_FAILURE 9
#define OX_CODE_REGISTRY_WATCHER_NO_NOTIFIER 10
#define OX_CODE_REGISTRY_WATCHER_INCORRECT_ID 11
#define OX_CODE_REGISTRY_WATCHER_SYNCHRO_FAILURE 12
// The operation completed successfully.
#define OX_REGISTRY_WATCHER_ERROR_SUCCESS MAKE_HRESULT(OX_STATUS_SEVERITY_SUCCESS,\
OX_FACILITY_REGISTRY_WATCHER, OX_CODE_REGISTRY_WATCHER_ERROR_SUCCESS)
// Registry key is not specifying.
#define OX_REGISTRY_WATCHER_NO_HKEY MAKE_HRESULT(OX_STATUS_SEVERITY_ERROR,\
OX_FACILITY_REGISTRY_WATCHER, OX_CODE_REGISTRY_WATCHER_NO_HKEY)
// Failure to start or process the worker thread.
#define OX_REGISTRY_WATCHER_THREAD_FAILURE MAKE_HRESULT(OX_STATUS_SEVERITY_ERROR,\
OX_FACILITY_REGISTRY_WATCHER, OX_CODE_REGISTRY_WATCHER_THREAD_FAILURE)
// Failure of notification event initialization.
#define OX_REGISTRY_WATCHER_EVENT_FAILURE MAKE_HRESULT(OX_STATUS_SEVERITY_ERROR,\
OX_FACILITY_REGISTRY_WATCHER, OX_CODE_REGISTRY_WATCHER_EVENT_FAILURE)
// No watched keys (empty "watch queue").
#define OX_REGISTRY_WATCHER_EMPTY_WATCHER MAKE_HRESULT(OX_STATUS_SEVERITY_ERROR,\
OX_FACILITY_REGISTRY_WATCHER, OX_CODE_REGISTRY_WATCHER_EMPTY_WATCHER)
// Registry key is not watched by this COXRegistryWatcher object.
#define OX_REGISTRY_WATCHER_INCORRECT_HKEY MAKE_HRESULT(OX_STATUS_SEVERITY_ERROR,\
OX_FACILITY_REGISTRY_WATCHER, OX_CODE_REGISTRY_WATCHER_INCORRECT_HKEY)
// Starting thread is already started.
#define OX_REGISTRY_WATCHER_ALREADY_STARTED MAKE_HRESULT(OX_STATUS_SEVERITY_ERROR,\
OX_FACILITY_REGISTRY_WATCHER, OX_CODE_REGISTRY_WATCHER_ALREADY_STARTED)
// Stoping thread is already stoped.
#define OX_REGISTRY_WATCHER_ALREADY_STOPPED MAKE_HRESULT(OX_STATUS_SEVERITY_ERROR,\
OX_FACILITY_REGISTRY_WATCHER, OX_CODE_REGISTRY_WATCHER_ALREADY_STOPPED)
// Failure to retrieve the Windows version.
#define OX_REGISTRY_WATCHER_VERSION_FAILURE MAKE_HRESULT(OX_STATUS_SEVERITY_ERROR,\
OX_FACILITY_REGISTRY_WATCHER, OX_CODE_REGISTRY_WATCHER_VERSION_FAILURE)
// Can't to find specified notifier.
#define OX_REGISTRY_WATCHER_NO_NOTIFIER MAKE_HRESULT(OX_STATUS_SEVERITY_ERROR,\
OX_FACILITY_REGISTRY_WATCHER, OX_CODE_REGISTRY_WATCHER_NO_NOTIFIER)
// Incorrect notifier ID.
#define OX_REGISTRY_WATCHER_INCORRECT_ID MAKE_HRESULT(OX_STATUS_SEVERITY_ERROR,\
OX_FACILITY_REGISTRY_WATCHER, OX_CODE_REGISTRY_WATCHER_INCORRECT_ID)
// Failure of synchronization event setting.
#define OX_REGISTRY_WATCHER_SYNCHRO_FAILURE MAKE_HRESULT(OX_STATUS_SEVERITY_ERROR,\
OX_FACILITY_REGISTRY_WATCHER, OX_CODE_REGISTRY_WATCHER_SYNCHRO_FAILURE)
// //////////////////////////////////////////////////////////////////////////
class OX_CLASS_DECL COXRegistryWatcher : public CObject
{
// Data members -------------------------------------------------------------
public:
// Flags to specify which type of changes should be reported (for AddWatch()).
const static DWORD OXRegistryWatchChangeName; // Subkey was added or deleted.
const static DWORD OXRegistryWatchChangeAttributes; // Changes to the attributes of the key.
const static DWORD OXRegistryWatchChangeLastSet; // Changes to a value of the key.
const static DWORD OXRegistryWatchChangeSecurity; // Changes to the security descriptor of the key.
protected:
CEvent m_EventWatchLoop;
CEvent m_EventWatchRestart;
CEvent m_EventWatchBuildBegin;
CEvent m_EventWatchBuildEnd;
HRESULT m_hResultError;
DWORD m_dwWatchesNumber;
CWinThread* m_pNotificationThread;
COXRegistryWatchNotifier* m_pRegistryWatchNotifier;
private:
// Member functions ---------------------------------------------------------
public:
COXRegistryWatcher();
// --- In :
// --- Out :
// --- Returns :
// --- Effect : Constructs the COXRegistryWatcher object.
virtual ~COXRegistryWatcher();
// --- In :
// --- Out :
// --- Returns :
// --- Effect : Removes all watched keys and destroys the COXRegistryWatcher object.
BOOL IsWatchingSupported();
// --- In :
// --- Out :
// --- Returns : TRUE - if Registry key watching is supported, FALSE - otherwise.
// --- Effect : This function returns whether Registry key watching is supported.
// This is only supported on Windows NT version 4.0 and higher.
DWORD AddWatch(HKEY hRegKey, BOOL bWatchSubtree = FALSE,
DWORD dwWatchFilter = OXRegistryWatchChangeName | OXRegistryWatchChangeLastSet);
// --- In : hRegKey : Registry key to be watched.
// bWatchSubtree : Flag that indicates whether to report changes in the specified key
// and all of its subkeys or only in the specified key. If this parameter
// is TRUE, the class reports changes in the key and its subkeys.
// If the parameter is FALSE, the class reports changes only in the key.
// dwWatchFilter : Specifies a combination of flags that control which changes should be
// reported. Flags are described above in the "Data members - public:"
// section of COXRegistryWatcher Class Specification.
// --- Out :
// --- Returns : If the function succeeds - ID of added notifier; if the function fails - 0.
// To get extended error information, call GetLastError() method of this class.
// --- Effect : Adds Registry key watch. When hRegKey changes, class calls virtual function
// OnNotify(), which can be overridden in your derived class.
// You can add unlimited number of keys to watch.
virtual BOOL OnNotify(COXRegistryWatchNotifier* pRegWatchNotifier);
// --- In : pRegWatchNotifier : Copy of the received parameters in the form of a
// pointer to COXRegistryWatchNotifier object.
// --- Out :
// --- Returns : Indicates whether this notification should be ignored (TRUE) or whether the
// object may continue handling the event (FALSE). The last option (FALSE) is
// necessary if the event is to be translated into a window message.
// --- Effect : This function is called when a Registry change notification is received by
// specified Registry watch object. It can be overriden in derived classes.
BOOL GetWatchIDsFromKey(HKEY hRegKey, CDWordArray& IDs);
// --- In : hRegKey : Watched Registry key.
// IDs : Array to store indexes of notifiers linked with specified key.
// --- Out : IDs : Array of indexes of notifiers linked with specified key.
// --- Returns : FALSE, if IDs array is empty; TRUE otherwise.
// --- Effect : Retrieves indexes of notifiers (COXRegistryWatchNotifier objects) that
// linked to specified Registry key.
DWORD COXRegistryWatcher::GetNotifCount();
// --- In :
// --- Out :
// --- Returns : Number of notifiers. If no notifiers added, returns 0.
// --- Effect : Returns number of successfully added by AddWatch() function notifiers
// (COXRegistryWatchNotifier objects), in other words - returns number of
// watched Registry keys.
BOOL RemoveWatch(DWORD dwID);
// --- In : dwID : Notifier ID (watched Registry key, that was added by AddWatch()).
// --- Out :
// --- Returns : TRUE - if the function succeeds, FALSE - if the function fails.
// To get extended error information, call GetLastError() method of this class.
// --- Effect : Removes the specified notifier (watch of linked Registry key).
BOOL RemoveAllWatches();
// --- In :
// --- Out :
// --- Returns : TRUE - if the function succeeds, FALSE - if the function fails.
// To get extended error information, call GetLastError() method of this class.
// --- Effect : Removes all notifiers (watches on all current watched keys).
BOOL EnableWindowNotification(DWORD dwID, CWnd* pWnd, BOOL bPost = TRUE);
// --- In : dwID : ID of notifier (watched Registry key, that was added by AddWatch()).
// pWnd : Points to the CWnd class object, that represents window,
// which will receive the notification message when Registry key changes.
// bPost : If TRUE, message posts (by default), if FALSE, message sends.
// --- Out :
// --- Returns : TRUE - if the function succeeds, FALSE - if the function fails.
// To get extended error information, call GetLastError() method of this class.
// --- Effect : Connects a future notification of a Registry watch to a message
// to a particular window. When a notification is received for that
// particular key, a specific message is posted/sent to the specified window.
// This message is WM_OX_REGISTRY_NOTIFY, wParam is index of received
// notification object (object can be retrieved by GetWatchNotifier()),
// and lParam is a handle of watched Registry key (HKEY).
BOOL DisableWindowNotification(DWORD dwID);
// --- In : dwID : ID of notifier (watched Registry key, that was added by AddWatch()).
// --- Out :
// --- Returns : TRUE - if the function succeeds, FALSE - if the function fails.
// To get extended error information, call GetLastError() method of this class.
// --- Effect : Removes connection between specified notification and window.
BOOL DisableAllWindowNotifications();
// --- In :
// --- Out :
// --- Returns : TRUE - if the function succeeds, FALSE - if the function fails.
// To get extended error information, call GetLastError() method of this class.
// --- Effect : Removes all connections between notifications of Registry keys and windows.
COXRegistryWatchNotifier* GetWatchNotifier(DWORD dwID, DWORD* pdwQueueIndex = NULL);
// --- In : dwID : ID of notification object (COXRegistryWatchNotifier).
// pdwQueueIndex : Address of buffer for index of this object in "watch queue".
// This parameter can be NULL (default).
// --- Out : pdwQueueIndex : Index of this object in "watch queue" (if pdwQueueIndex != NULL).
// --- Returns : Pointer to COXRegistryWatchNotifier object.
// When no object is linked to specified ID, NULL is returned.
// --- Effect : Returns a specific Registry watch notifier object.
// This function can be used for notifier ID validity check.
HRESULT GetLastError() const;
// --- In :
// --- Out :
// --- Returns : Code of the last error. Codes are described above in the
// "Definitions of error codes" section of Class Specification.
// --- Effect : Returns the error code of the last error that has occurred.
protected:
void AfterNotify(COXRegistryWatchNotifier* pRegWatchNotifier);
static UINT RegistryWatchThreadFunction(LPVOID pParam);
BOOL StartWatchThread();
BOOL StopWatchThread();
BOOL IsWatchStarted();
DWORD FindNewID();
private:
};
#endif // __OXREGISTRYWATCHER_H__
// ==========================================================================