Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

652 lines
16 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. REGEREQ.CPP
  5. Abstract:
  6. History:
  7. --*/
  8. #include "precomp.h"
  9. #include "regereq.h"
  10. #include "regcrc.h"
  11. #include <genutils.h>
  12. #include "regeprov.h"
  13. //******************************************************************************
  14. //******************************************************************************
  15. //
  16. // TIMER INSTRUCTION
  17. //
  18. //******************************************************************************
  19. //******************************************************************************
  20. CRegistryTimerInstruction::CRegistryTimerInstruction(
  21. CRegistryEventRequest* pReq)
  22. : m_pReq(pReq), m_lRef(0)
  23. {
  24. pReq->AddRef();
  25. m_Interval.SetMilliseconds(pReq->GetMsWait());
  26. }
  27. CRegistryTimerInstruction::~CRegistryTimerInstruction()
  28. {
  29. m_pReq->Release();
  30. }
  31. void CRegistryTimerInstruction::AddRef()
  32. {
  33. InterlockedIncrement(&m_lRef);
  34. }
  35. void CRegistryTimerInstruction::Release()
  36. {
  37. if(InterlockedDecrement(&m_lRef) == 0)
  38. delete this;
  39. }
  40. CWbemTime CRegistryTimerInstruction::GetNextFiringTime(CWbemTime LastFiringTime,
  41. OUT long* plFiringCount) const
  42. {
  43. CWbemTime Next = LastFiringTime + m_Interval;
  44. if(Next < CWbemTime::GetCurrentTime())
  45. {
  46. return CWbemTime::GetCurrentTime() + m_Interval;
  47. }
  48. else
  49. {
  50. return Next;
  51. }
  52. }
  53. CWbemTime CRegistryTimerInstruction::GetFirstFiringTime() const
  54. {
  55. return CWbemTime::GetCurrentTime() + m_Interval;
  56. }
  57. HRESULT CRegistryTimerInstruction::Fire(long lNumTimes, CWbemTime NextFiringTime)
  58. {
  59. m_pReq->Execute(TRUE);
  60. return S_OK;
  61. }
  62. //******************************************************************************
  63. //******************************************************************************
  64. //
  65. // TIMER INSTRUCTION
  66. //
  67. //******************************************************************************
  68. //******************************************************************************
  69. BOOL CRegistryInstructionTest::operator()(CTimerInstruction* pToTest)
  70. {
  71. CRegistryTimerInstruction* pRegInst = (CRegistryTimerInstruction*)pToTest;
  72. return (pRegInst->GetRequest() == m_pReq);
  73. }
  74. //******************************************************************************
  75. //******************************************************************************
  76. //
  77. // GENERIC REQUEST
  78. //
  79. //******************************************************************************
  80. //******************************************************************************
  81. CRegistryEventRequest::CRegistryEventRequest(CRegEventProvider* pProvider,
  82. WBEM_QL1_TOLERANCE& Tolerance,
  83. DWORD dwId, HKEY hHive, LPWSTR wszHive,
  84. LPWSTR wszKey)
  85. : m_hHive(hHive), m_wsKey(wszKey), m_pProvider(pProvider),
  86. m_wsHive(wszHive), m_lActiveCount(0), m_bNew(TRUE),
  87. m_lRef(0), m_bOK(TRUE), m_dwLastCRC(0), m_hKey(NULL), m_hEvent(NULL),
  88. m_hWaitRegistration(NULL)
  89. {
  90. if(Tolerance.m_bExact)
  91. {
  92. m_dwMsWait = 0;
  93. }
  94. else
  95. {
  96. m_dwMsWait = Tolerance.m_fTolerance * 1000;
  97. }
  98. if ( CFlexArray::no_error != m_adwIds.Add(ULongToPtr(dwId)) )
  99. {
  100. throw CX_MemoryException( );
  101. }
  102. InitializeCriticalSection(&m_cs);
  103. }
  104. CRegistryEventRequest::~CRegistryEventRequest()
  105. {
  106. if (m_hKey)
  107. {
  108. RegCloseKey(m_hKey);
  109. }
  110. if(m_hEvent)
  111. {
  112. CloseHandle(m_hEvent);
  113. }
  114. DeleteCriticalSection(&m_cs);
  115. }
  116. void CRegistryEventRequest::AddRef()
  117. {
  118. InterlockedIncrement(&m_lRef);
  119. }
  120. void CRegistryEventRequest::Release()
  121. {
  122. if(InterlockedDecrement(&m_lRef) == 0) delete this;
  123. }
  124. BOOL CRegistryEventRequest::IsSameAs(CRegistryEventRequest* pOther)
  125. {
  126. if(GetType() != pOther->GetType())
  127. return FALSE;
  128. if(m_hHive != pOther->m_hHive)
  129. return FALSE;
  130. if(!m_wsHive.EqualNoCase(pOther->m_wsHive))
  131. return FALSE;
  132. if(!m_wsKey.EqualNoCase(pOther->m_wsKey))
  133. return FALSE;
  134. return TRUE;
  135. }
  136. DWORD CRegistryEventRequest::GetPrimaryId()
  137. {
  138. return PtrToLong(m_adwIds[0]);
  139. }
  140. BOOL CRegistryEventRequest::DoesContainId(DWORD dwId)
  141. {
  142. // not called
  143. for(int i = 0; i < m_adwIds.Size(); i++)
  144. {
  145. if(PtrToLong(m_adwIds[i]) == dwId)
  146. return TRUE;
  147. }
  148. return FALSE;
  149. }
  150. HRESULT CRegistryEventRequest::Reactivate(DWORD dwId, DWORD dwMsWait)
  151. {
  152. // This is only called on active objects.
  153. CInCritSec ics(&m_cs);
  154. if(m_dwMsWait > dwMsWait)
  155. m_dwMsWait = dwMsWait;
  156. m_adwIds.Add(ULongToPtr(dwId));
  157. InterlockedIncrement(&m_lActiveCount);
  158. return WBEM_S_NO_ERROR;
  159. }
  160. HRESULT CRegistryEventRequest::Activate()
  161. {
  162. // This function doesn't need to enter a critical section
  163. // for the reasons explained in the following argument.
  164. // This reasoning might be invalidated by design changes.
  165. // This is only called on new objects before they are added
  166. // to the active request array.
  167. // Since all the independent COM client threads get access
  168. // to these objects through that array, this object is locked to
  169. // all threads but the current one.
  170. // Once RegisterWaitForSingleObject is called this object is registered
  171. // with the thread pool but it won't be accessed because no events will
  172. // occur until ResetOnChangeHandle is called by the worker thread.
  173. // When m_pProvider->EnqueueEvent(this) is called then the worker thread
  174. // has access to the object. At this point there is nothing left to do
  175. // but return.
  176. // Open the key
  177. // ============
  178. #ifdef UNICODE
  179. long lRes = RegOpenKeyEx(m_hHive, m_wsKey, 0, KEY_READ, &m_hKey);
  180. #else
  181. LPSTR szName = m_wsKey.GetLPSTR();
  182. long lRes = RegOpenKeyEx(m_hHive, szName, 0, KEY_READ, &m_hKey);
  183. delete [] szName;
  184. #endif
  185. if(lRes)
  186. {
  187. return WBEM_E_INVALID_PARAMETER;
  188. }
  189. // Create an event
  190. // ===============
  191. m_hEvent = CreateEvent(NULL, // lpEventAttributes
  192. FALSE, // bManualReset
  193. FALSE, // bInitialState
  194. NULL); // lpName
  195. RegisterWaitForSingleObject(
  196. &m_hWaitRegistration, // phNewWaitObject
  197. m_hEvent, // hObject
  198. CRegEventProvider::EnqueueEvent, // Callback
  199. this, // Context
  200. INFINITE, // dwMilliseconds
  201. WT_EXECUTEINWAITTHREAD);// dwFlags
  202. // This represents the thread pool's reference.
  203. AddRef();
  204. // It will be connected to the key by the worker thread
  205. // because when the thread that calls RegNotifyChangeKeyValue
  206. // exits the event is signaled. Therefore if this thread called
  207. // RegNotifyChangeKeyValue then we would get a spurious event when
  208. // this thread exits. When the worker thread exits all the event
  209. // subscriptions will have already been cancelled.
  210. // ==========================================================
  211. m_bNew = TRUE;
  212. CacheValue();
  213. m_pProvider->EnqueueEvent(this);
  214. return S_OK;
  215. }
  216. BOOL CRegistryEventRequest::ResetOnChangeHandle()
  217. {
  218. // This is only called from ProcessEvent which has already
  219. // acquired the lock.
  220. m_bNew = FALSE;
  221. long lRes = RegNotifyChangeKeyValue(
  222. m_hKey, // hKey
  223. (GetType() == e_RegTreeChange), // bWatchSubtree
  224. REG_NOTIFY_CHANGE_NAME |
  225. REG_NOTIFY_CHANGE_LAST_SET |
  226. REG_NOTIFY_CHANGE_ATTRIBUTES, // dwNotifyFilter
  227. m_hEvent, // hEvent
  228. TRUE); // fAsynchronous
  229. return (lRes == 0);
  230. }
  231. HANDLE CRegistryEventRequest::GetOnChangeHandle()
  232. {
  233. // not called
  234. return m_hEvent;
  235. }
  236. HRESULT CRegistryEventRequest::Deactivate(DWORD dwId)
  237. {
  238. CInCritSec ics(&m_cs);
  239. // Remove the ID from the list
  240. // ===========================
  241. bool bFoundId = false;
  242. int nIdCount = m_adwIds.Size();
  243. for(int i = 0; i < nIdCount; i++)
  244. {
  245. if(PtrToLong(m_adwIds[i]) == dwId)
  246. {
  247. m_adwIds.RemoveAt(i);
  248. bFoundId = true;
  249. break;
  250. }
  251. }
  252. if(!bFoundId || (InterlockedDecrement(&m_lActiveCount) >= 0))
  253. return WBEM_S_FALSE;
  254. // Unregister the event with the thread pool and wait for
  255. // pending requests to be processed.
  256. // We wait because this object could be released and deleted when this
  257. // function returns which would mean the thread pool holds an invalid
  258. // pointer.
  259. // When the thread pool processes a request it places it in the worker thread
  260. // queue which AddRefs the request.
  261. UnregisterWaitEx(m_hWaitRegistration, // WaitHandle
  262. INVALID_HANDLE_VALUE); // CompletionEvent
  263. m_hWaitRegistration = NULL;
  264. // This will signal m_hEvent but we just unregistered it
  265. // so nobody is waiting on it.
  266. RegCloseKey(m_hKey);
  267. m_hKey = 0;
  268. CloseHandle(m_hEvent);
  269. m_hEvent = 0;
  270. // The thread pool no longer holds a reference
  271. // so call Release on its behalf.
  272. Release();
  273. return S_OK;
  274. }
  275. HRESULT CRegistryEventRequest::ForceDeactivate(void)
  276. {
  277. CInCritSec ics(&m_cs);
  278. // deactivate the event request
  279. InterlockedExchange(&m_lActiveCount, -1);
  280. // Remove all IDs from the list
  281. int nIdCount = m_adwIds.Size();
  282. m_adwIds.Empty();
  283. // Unregister the event with the thread pool and wait for
  284. // pending requests to be processed.
  285. // We wait because this object could be released and deleted when this
  286. // function returns which would mean the thread pool holds an invalid
  287. // pointer.
  288. // When the thread pool processes a request it places it in the worker thread
  289. // queue which AddRefs the request.
  290. UnregisterWaitEx(m_hWaitRegistration, // WaitHandle
  291. INVALID_HANDLE_VALUE); // CompletionEvent
  292. m_hWaitRegistration = NULL;
  293. // This will signal m_hEvent but we just unregistered it
  294. // so nobody is waiting on it.
  295. RegCloseKey(m_hKey);
  296. m_hKey = 0;
  297. CloseHandle(m_hEvent);
  298. m_hEvent = 0;
  299. // The thread pool no longer holds a reference
  300. // so call Release on its behalf.
  301. Release();
  302. return S_OK;
  303. }
  304. HRESULT CRegistryEventRequest::Execute(BOOL bOnTimer)
  305. {
  306. // If called by the timer, we need to check if anything actually changed
  307. // =====================================================================
  308. if(bOnTimer || GetType() == e_RegValueChange)
  309. {
  310. DWORD dwNewCRC;
  311. HRESULT hres = ComputeCRC(dwNewCRC);
  312. if(FAILED(hres))
  313. {
  314. return hres;
  315. }
  316. if(dwNewCRC == m_dwLastCRC)
  317. {
  318. // No real change. Return
  319. // ======================
  320. return S_FALSE;
  321. }
  322. m_dwLastCRC = dwNewCRC;
  323. }
  324. // If here, a real change has occurred
  325. // ===================================
  326. IWbemClassObject* pEvent;
  327. HRESULT hres = CreateNewEvent(&pEvent);
  328. if(FAILED(hres))
  329. {
  330. return hres;
  331. }
  332. hres = m_pProvider->RaiseEvent(pEvent);
  333. pEvent->Release();
  334. return hres;
  335. }
  336. HRESULT CRegistryEventRequest::SetCommonProperties(IWbemClassObject* pEvent)
  337. {
  338. // Set the hive name
  339. // =================
  340. VARIANT v;
  341. VariantInit(&v);
  342. V_VT(&v) = VT_BSTR;
  343. V_BSTR(&v) = SysAllocString(m_wsHive);
  344. pEvent->Put(REG_HIVE_PROPERTY_NAME, 0, &v, NULL);
  345. VariantClear(&v);
  346. return WBEM_S_NO_ERROR;
  347. }
  348. void CRegistryEventRequest::ProcessEvent()
  349. {
  350. CInCritSec ics(&m_cs);
  351. if(IsActive())
  352. {
  353. // New requests are immediately queued in order for the worker
  354. // thread to initialize them. They don't represent actual events.
  355. // We need to save the new status because ResetOnChangeHandle
  356. // erases it.
  357. BOOL bIsNew = IsNew();
  358. ResetOnChangeHandle();
  359. if (!bIsNew)
  360. {
  361. Execute(FALSE);
  362. }
  363. }
  364. }
  365. //******************************************************************************
  366. //******************************************************************************
  367. //
  368. // VALUE REQUEST
  369. //
  370. //******************************************************************************
  371. //******************************************************************************
  372. HRESULT CRegistryValueEventRequest::CreateNewEvent(IWbemClassObject** ppEvent)
  373. {
  374. // Create an instance
  375. // ==================
  376. IWbemClassObject* pEvent;
  377. m_pProvider->m_pValueClass->SpawnInstance(0, &pEvent);
  378. // Set the hive property
  379. // =====================
  380. SetCommonProperties(pEvent);
  381. // Set the key
  382. // ===========
  383. VARIANT v;
  384. VariantInit(&v);
  385. V_VT(&v) = VT_BSTR;
  386. V_BSTR(&v) = SysAllocString(m_wsKey);
  387. pEvent->Put(REG_KEY_PROPERTY_NAME, 0, &v, NULL);
  388. VariantClear(&v);
  389. // Set the value
  390. // =============
  391. V_VT(&v) = VT_BSTR;
  392. V_BSTR(&v) = SysAllocString(m_wsValue);
  393. pEvent->Put(REG_VALUE_PROPERTY_NAME, 0, &v, NULL);
  394. VariantClear(&v);
  395. *ppEvent = pEvent;
  396. return WBEM_S_NO_ERROR;
  397. }
  398. HRESULT CRegistryValueEventRequest::ComputeCRC(DWORD& dwCRC)
  399. {
  400. #ifdef UNICODE
  401. HRESULT hres = CRegCRC::ComputeValueCRC(m_hKey, m_wsValue,
  402. STARTING_CRC32_VALUE, dwCRC);
  403. #else
  404. LPSTR szValue = m_wsValue.GetLPSTR();
  405. HRESULT hres = CRegCRC::ComputeValueCRC(m_hKey, szValue,
  406. STARTING_CRC32_VALUE, dwCRC);
  407. delete [] szValue;
  408. #endif
  409. return hres;
  410. }
  411. HRESULT CRegistryValueEventRequest::Execute(BOOL bOnTimer)
  412. {
  413. // Since NT does not allow per-value change registration, CRC needs to be
  414. // computed no matter what
  415. // ======================================================================
  416. return CRegistryEventRequest::Execute(TRUE);
  417. }
  418. void CRegistryValueEventRequest::CacheValue()
  419. {
  420. ComputeCRC(m_dwLastCRC);
  421. }
  422. BOOL CRegistryValueEventRequest::IsSameAs(CRegistryEventRequest* pOther)
  423. {
  424. if(!CRegistryEventRequest::IsSameAs(pOther))
  425. return FALSE;
  426. CRegistryValueEventRequest* pValueOther =
  427. (CRegistryValueEventRequest*)pOther;
  428. if(!m_wsValue.EqualNoCase(pValueOther->m_wsValue))
  429. return FALSE;
  430. return TRUE;
  431. }
  432. //******************************************************************************
  433. //******************************************************************************
  434. //
  435. // KEY REQUEST
  436. //
  437. //******************************************************************************
  438. //******************************************************************************
  439. HRESULT CRegistryKeyEventRequest::CreateNewEvent(IWbemClassObject** ppEvent)
  440. {
  441. // Create an instance
  442. // ==================
  443. IWbemClassObject* pEvent;
  444. m_pProvider->m_pKeyClass->SpawnInstance(0, &pEvent);
  445. // Set the hive property
  446. // =====================
  447. SetCommonProperties(pEvent);
  448. // Set the key
  449. // ===========
  450. VARIANT v;
  451. VariantInit(&v);
  452. V_VT(&v) = VT_BSTR;
  453. V_BSTR(&v) = SysAllocString(m_wsKey);
  454. pEvent->Put(REG_KEY_PROPERTY_NAME, 0, &v, NULL);
  455. VariantClear(&v);
  456. *ppEvent = pEvent;
  457. return WBEM_S_NO_ERROR;
  458. }
  459. HRESULT CRegistryKeyEventRequest::ComputeCRC(DWORD& dwCRC)
  460. {
  461. HRESULT hres = CRegCRC::ComputeKeyCRC(m_hKey, STARTING_CRC32_VALUE, dwCRC);
  462. return hres;
  463. }
  464. //******************************************************************************
  465. //******************************************************************************
  466. //
  467. // TREE REQUEST
  468. //
  469. //******************************************************************************
  470. //******************************************************************************
  471. HRESULT CRegistryTreeEventRequest::CreateNewEvent(IWbemClassObject** ppEvent)
  472. {
  473. // Create an instance
  474. // ==================
  475. IWbemClassObject* pEvent;
  476. m_pProvider->m_pTreeClass->SpawnInstance(0, &pEvent);
  477. // Set the hive property
  478. // =====================
  479. SetCommonProperties(pEvent);
  480. // Set the root
  481. // ============
  482. VARIANT v;
  483. VariantInit(&v);
  484. V_VT(&v) = VT_BSTR;
  485. V_BSTR(&v) = SysAllocString(m_wsKey);
  486. pEvent->Put(REG_ROOT_PROPERTY_NAME, 0, &v, NULL);
  487. VariantClear(&v);
  488. *ppEvent = pEvent;
  489. return WBEM_S_NO_ERROR;
  490. }
  491. HRESULT CRegistryTreeEventRequest::ComputeCRC(DWORD& dwCRC)
  492. {
  493. HRESULT hres = CRegCRC::ComputeTreeCRC(m_hKey, STARTING_CRC32_VALUE, dwCRC);
  494. return hres;
  495. }