Delphi实现对注册表的监视和扫描
监视注册表相关项的改变要用到一个API:RegNotifyChangeKeyValue。
LONG RegNotifyChangeKeyValue(
 HKEY hKey, // 要监视的一个项的句柄 
  BOOL bWatchSubtree, // 是否监视此项的子键 
  DWORD dwNotifyFilter, // 监视哪些变化 
  HANDLE hEvent, // 接受注册表变化事件的事件对象句柄 
  BOOL fAsynchronous // 注册表变化前报告还是注册表变化后才报告 
  );
注意上面的hEvent是接受注册表变化事件的事件对象句柄,我们要用API:CreateEvent来创建一个系统事件对象。
HANDLE CreateEvent(
 LPSECURITY_ATTRIBUTES lpEventAttributes, // SECURITY_ATTRIBUTES结构
  BOOL bManualReset, // 是否自动重置 
  BOOL bInitialState, // 是否设置初始状态
  LPCTSTR lpName // 事件对象的名称
  );
新建一个工程,添加一个ListBox,两个Button。
//先写个监视注册表的例子
                      //监视HKEY_CURRENT_USER\Software项下所有子键
                      procedure TForm1.Button1Click(Sender: TObject);
                      var
  hNotify : THandle;
  hKeyx : HKEY;
  dwRes : DWORD;
  begin
  hNotify := CreateEvent( nil, //不使用SECURITY_ATTRIBUTES结构
  FALSE, //不自动重置
  TRUE, //设置初始状态
  ''RegistryNotify'' //事件对象的名称
  );
 if hNotify = 0 then
  begin
  Showmessage(''CreateEvent failed.'');
  exit;
  end;
 if RegOpenKeyEx( HKEY_CURRENT_USER, //跟键
  ''Software'', //子键
  0, //reserved
  KEY_NOTIFY, //监视用
  hKeyx //保存句柄
  ) <> ERROR_SUCCESS then
  begin
  CloseHandle( hNotify );
  Showmessage(''RegOpenKeyEx failed.'');
  exit;
  end;
 if RegNotifyChangeKeyValue( hKeyx, //监视子键句柄
  TRUE, //监视此项的子键
  REG_NOTIFY_CHANGE_NAME or REG_NOTIFY_CHANGE_LAST_SET,
  hNotify, //接受注册表变化事件的事件对象句柄
  TRUE //注册表变化前报告
  ) <> ERROR_SUCCESS then
  begin
  CloseHandle( hNotify );
  RegCloseKey( hKeyx );
  Showmessage(''RegNotifyChangeKeyValue failed'');
  exit;
  end;
 dwRes := WaitForSingleObject( hNotify, 60 * 1000 ); //监视一分钟
  if dwRes = 0 then
  Showmessage( ''Registry will be changed.'' );
 CloseHandle( hNotify );
  RegCloseKey( hKeyx );
  end;
要注意的是,API: WaitForSingleObject要等到注册表变化事件发生或者超时才会返回,在此期间我们的程序将失去响应。解决的办法是新建一个线程,在新线程中监视注册表。
对注册表进行扫描要用到另外两个API: RegEnumKey和RegEnumValue。
 LONG RegEnumKey(
  HKEY hKey, // 要扫描的注册表项目句柄
  DWORD dwIndex, // 要扫描的subkey序号
  LPTSTR lpName, // 要扫描的subkey名称
  LPDWORD lpcbName, // 要扫描的subkey名称占用空间
  );
此函数的使用方法是: 首先给dwIndex赋值0, 调用RegEnumKey; 然后Inc(dwIndex), 再调用RegEnumKey,直到返回值为ERROR_NO_MORE_ITEMS,表示没有更多的子项了。
//扫描注册表的例子
                      //只演示了如何枚举HKEY_CURRENT_USER\Software下的一层子项
                      procedure TForm1.Button2Click(Sender: TObject);
                      var
  buf : array [0..255] of char;
  iRes : integer;
  hKeyx : HKEY;
  dwIndex, dwSize : DWORD;
  begin
  if RegOpenKeyEx( HKEY_CURRENT_USER, ''Software'', 0, KEY_READ or
  KEY_ENUMERATE_SUB_KEYS, hKeyx ) <> ERROR_SUCCESS then
  begin
  Showmessage(''RegOpenKeyEx failed.'');
  exit;
  end;
 dwIndex := 0;
  repeat
  dwSize := 255;
  iRes := RegEnumKey( hKeyx, dwIndex, buf, dwSize );
  if iRes = ERROR_NO_MORE_ITEMS then
  break
  else if iRes = ERROR_SUCCESS then
  begin
  Listbox1.Items.Add( buf );
  Inc( dwIndex );
  end;
  until iRes <> ERROR_SUCCESS;
 RegCloseKey( hKeyx );
                      end;
	
