Leaked source code of windows server 2003
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.

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