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.

648 lines
22 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. History:
  6. --*/
  7. // RefreshCooker.cpp
  8. #include "precomp.h"
  9. #include <wbemint.h>
  10. #include <comdef.h>
  11. #include <autoptr.h>
  12. #include "Refresher.h"
  13. #include "CookerUtils.h"
  14. ////////////////////////////////////////////////////////////////////////////
  15. //
  16. // CRefresher
  17. // ==========
  18. //
  19. // The refresher class implements both the IWbemRefresher and the
  20. // IWMIRefreshableCooker interfaces. It contains an instance cache and
  21. // an enumerator cache as well as maintaining an internal refresher to
  22. // track the raw data.
  23. //
  24. ////////////////////////////////////////////////////////////////////////////
  25. CRefresher::CRefresher() :
  26. m_pRefresher( NULL ),
  27. m_pConfig( NULL ),
  28. m_lRef( 0 ),
  29. m_bOK( FALSE ),
  30. m_dwRefreshId(0)
  31. {
  32. #ifdef _VERBOSE
  33. DbgPrintfA(0,"------------ CRefresher %08x \n",this);
  34. #endif
  35. WMISTATUS dwStatus = WBEM_NO_ERROR;
  36. // Initialize the internal refresher
  37. // =================================
  38. dwStatus = CoCreateInstance( CLSID_WbemRefresher,
  39. NULL,
  40. CLSCTX_INPROC_SERVER,
  41. IID_IWbemRefresher,
  42. (void**) &m_pRefresher );
  43. // Get the refresher configuration interface
  44. // =========================================
  45. if ( SUCCEEDED( dwStatus ) )
  46. {
  47. dwStatus = m_pRefresher->QueryInterface( IID_IWbemConfigureRefresher, (void**)&m_pConfig );
  48. }
  49. m_bOK = SUCCEEDED( dwStatus );
  50. }
  51. CRefresher::~CRefresher()
  52. {
  53. if (m_pRefresher ) m_pRefresher->Release();
  54. if ( m_pConfig ) m_pConfig->Release();
  55. }
  56. ///////////////////////////////////////////////////////////////////////////////
  57. //
  58. // Private methods
  59. //
  60. ///////////////////////////////////////////////////////////////////////////////
  61. WMISTATUS CRefresher::SearchCookingClassCache(
  62. WCHAR* wszCookingClass,
  63. /*out*/ CWMISimpleObjectCooker* & pObjectCooker_out )
  64. ///////////////////////////////////////////////////////////////////////////////
  65. //
  66. // SearchCookingClassCache enumerates the cache looking for a class name
  67. // that matches the wszCookingClass parameter
  68. //
  69. // Parameters:
  70. // wszCookingClass - The name of the WMI cooking class
  71. // ppObjectCooker - The instance of the object cooker
  72. //
  73. ///////////////////////////////////////////////////////////////////////////////
  74. {
  75. WMISTATUS dwStatus = WBEM_E_NOT_FOUND;
  76. CWMISimpleObjectCooker* pObjectCooker = NULL;
  77. // Enumerate through the cache looking for the record
  78. m_CookingClassCache.BeginEnum();
  79. while ( S_OK == m_CookingClassCache.Next( &pObjectCooker ) )
  80. {
  81. // Compare the names
  82. // =================
  83. if ( 0 == wbem_wcsicmp( pObjectCooker->GetCookingClassName(), wszCookingClass ) )
  84. {
  85. pObjectCooker_out = pObjectCooker;
  86. dwStatus = WBEM_NO_ERROR;
  87. break;
  88. }
  89. }
  90. m_CookingClassCache.EndEnum();
  91. return dwStatus;
  92. }
  93. WMISTATUS CRefresher::CreateObjectCooker(
  94. WCHAR* wszCookingClassName,
  95. IWbemObjectAccess* pCookingAccess,
  96. IWbemObjectAccess* pRawAccess,
  97. CWMISimpleObjectCooker** ppObjectCooker,
  98. IWbemServices * pNamespace)
  99. ///////////////////////////////////////////////////////////////////////////////
  100. //
  101. // CreateObjectCooker will create and initialize a new object cooker and add
  102. // it to the cache
  103. //
  104. // Parameters:
  105. // pNamespace - The namespace pointer where the objects are located
  106. // pCookingAccess - The WMI cooking object in need of a cooker
  107. // wszCookingClassName
  108. // - The name of the cooking class
  109. // ppObjectCooker - The parameter to pass back the new object cooker
  110. //
  111. ///////////////////////////////////////////////////////////////////////////////
  112. {
  113. if (NULL == ppObjectCooker) return WBEM_E_INVALID_PARAMETER;
  114. CWMISimpleObjectCooker* pObjectCooker = NULL;
  115. WCHAR* wszRawClassName;
  116. long lID;
  117. pObjectCooker = new CWMISimpleObjectCooker( wszCookingClassName, pCookingAccess, pRawAccess, pNamespace );
  118. if ( NULL == pObjectCooker ) return WBEM_E_OUT_OF_MEMORY;
  119. WMISTATUS dwStatus = pObjectCooker->GetLastHR();
  120. // Add the object cooker to the cache
  121. if ( SUCCEEDED( dwStatus ) )
  122. {
  123. dwStatus = m_CookingClassCache.Add( pObjectCooker, wszCookingClassName, &lID );
  124. }
  125. if (FAILED(dwStatus))
  126. {
  127. delete pObjectCooker;
  128. pObjectCooker = NULL;
  129. }
  130. *ppObjectCooker = pObjectCooker;
  131. return dwStatus;
  132. }
  133. WMISTATUS CRefresher::AddRawInstance(
  134. IWbemServices* pService,
  135. IWbemContext * pCtx,
  136. IWbemObjectAccess* pCookingInst,
  137. IWbemObjectAccess** ppRawInst )
  138. ///////////////////////////////////////////////////////////////////////////////
  139. //
  140. // AddRawInstance is called to add the corresponding raw instance of a
  141. // cooked object to the internal refresher. We first extract the key value
  142. // from the cooked object and create the raw instance path using the raw
  143. // class name
  144. //
  145. // Parameters:
  146. // pService - The namespace pointer where the objects are located
  147. // pCookingInst - The WMI cooking instance
  148. // ppRawInst - The WMI raw instance that was added to the internal
  149. // refresher
  150. //
  151. ///////////////////////////////////////////////////////////////////////////////
  152. {
  153. WMISTATUS dwStatus = WBEM_NO_ERROR;
  154. IWbemClassObject* pObj = NULL; // The alternate representation of pCookingInst
  155. _variant_t varRelPath; // The RELPATH value
  156. WCHAR* wszRawClassName = NULL; // The name of the raw class
  157. // Get the fully specified instance path for the cooking object
  158. // ============================================================
  159. pCookingInst->QueryInterface( IID_IWbemClassObject, (void**)&pObj );
  160. CReleaseMe arObj( pObj );
  161. dwStatus = pObj->Get( L"__RELPATH", 0, &varRelPath, NULL, NULL );
  162. if ( SUCCEEDED( dwStatus ) )
  163. {
  164. // Verify the property type
  165. // ========================
  166. if ( varRelPath.vt != VT_BSTR )
  167. {
  168. dwStatus = WBEM_E_TYPE_MISMATCH;
  169. }
  170. if ( SUCCEEDED( dwStatus ) )
  171. {
  172. IWbemClassObject* pRawInst = NULL;
  173. WCHAR* wszKeys = NULL;
  174. WCHAR* wszRawInst = NULL;
  175. // Extract the key name
  176. // ====================
  177. wszKeys = wcsstr( varRelPath.bstrVal, L"=" ) + 1;
  178. // Get the raw class name
  179. // ======================
  180. dwStatus = GetRawClassName( pCookingInst, &wszRawClassName );
  181. if (SUCCEEDED(dwStatus))
  182. {
  183. wmilib::auto_buffer<WCHAR> adRawClassName( wszRawClassName );
  184. // Append the key to the raw class name
  185. // ====================================
  186. size_t length = wcslen( wszRawClassName ) + wcslen( wszKeys ) + 10;
  187. wszRawInst = new WCHAR[ length ];
  188. if (!wszRawInst)
  189. return WBEM_E_OUT_OF_MEMORY;
  190. wmilib::auto_buffer<WCHAR> adRawInst( wszRawInst );
  191. StringCchPrintfW( wszRawInst, length , L"%s=%s", wszRawClassName, wszKeys );
  192. // Add a raw instance to the internal refresher
  193. // ============================================
  194. dwStatus = m_pConfig->AddObjectByPath( pService, wszRawInst, 0, pCtx, &pRawInst, NULL );
  195. CReleaseMe arRawInst( pRawInst );
  196. if (SUCCEEDED(dwStatus)) {
  197. // Return the IWbemObjectAccess interface of the raw instance
  198. // ==========================================================
  199. dwStatus = pRawInst->QueryInterface( IID_IWbemObjectAccess, (void**)ppRawInst );
  200. }
  201. }
  202. }
  203. }
  204. return dwStatus;
  205. }
  206. WMISTATUS CRefresher::AddRawEnum(
  207. IWbemServices* pNamespace,
  208. IWbemContext * pCtx,
  209. WCHAR * wszRawClassName,
  210. IWbemHiPerfEnum** ppRawEnum,
  211. long* plID )
  212. ///////////////////////////////////////////////////////////////////////////////
  213. //
  214. // AddRawEnum is called to add the corresponding raw enumerator to the
  215. // internal refrehser. In order to add the raw enumerator to the refresher,
  216. // we must determine the raw class name, therefore, we must create a
  217. // cooking class in order to get the AutoCook_RawClass qualifier.
  218. //
  219. // Parameters:
  220. // pNamespace - The namespace pointer where the objects are located
  221. // wszRawClassName - The name of the cooking class
  222. // ppRawEnum - The raw WMI enumerator that was added to the
  223. // internal refresher
  224. // plID - The refresher ID of the raw enumerator
  225. //
  226. ///////////////////////////////////////////////////////////////////////////////
  227. {
  228. // Add the Raw enumerator to the internal refresher
  229. WMISTATUS dwStatus = m_pConfig->AddEnum( pNamespace, wszRawClassName, 0, pCtx, ppRawEnum, plID );
  230. #ifdef _VERBOSE
  231. DbgPrintfA(0,"wszRawClassName %S pEnum %08x hr %08x\n",wszRawClassName,*ppRawEnum,dwStatus);
  232. #endif
  233. return dwStatus;
  234. }
  235. ///////////////////////////////////////////////////////////////////////////////
  236. //
  237. // COM methods
  238. //
  239. ///////////////////////////////////////////////////////////////////////////////
  240. STDMETHODIMP CRefresher::QueryInterface(REFIID riid, void** ppv)
  241. ///////////////////////////////////////////////////////////////////////////////
  242. //
  243. // Standard QueryInterface
  244. //
  245. // Parameters:
  246. // riid - the ID of the requested interface
  247. // ppv - a pointer to the interface pointer
  248. //
  249. ///////////////////////////////////////////////////////////////////////////////
  250. //ok
  251. {
  252. if (NULL == ppv) return E_POINTER;
  253. if(riid == IID_IUnknown)
  254. *ppv = (LPVOID)(IUnknown*)(IWMIRefreshableCooker*)this;
  255. else if(riid == IID_IWMIRefreshableCooker)
  256. *ppv = (LPVOID)(IWMIRefreshableCooker*)this;
  257. else if(riid == IID_IWbemRefresher)
  258. *ppv = (LPVOID)(IWbemRefresher*)this;
  259. else
  260. {
  261. *ppv = NULL;
  262. return E_NOINTERFACE;
  263. }
  264. ((IUnknown*)*ppv)->AddRef();
  265. return S_OK;
  266. }
  267. STDMETHODIMP_(ULONG) CRefresher::AddRef()
  268. {
  269. return InterlockedIncrement(&m_lRef);
  270. }
  271. STDMETHODIMP_(ULONG) CRefresher::Release()
  272. {
  273. long lRef = InterlockedDecrement(&m_lRef);
  274. if(lRef == 0) delete this;
  275. return lRef;
  276. }
  277. STDMETHODIMP CRefresher::AddInstance(
  278. /*[in] */ IWbemServices* pNamespace, // The object's namespace
  279. /*[in] */ IWbemContext * pCtx, // The Context
  280. /*[in] */ IWbemObjectAccess* pCookingInstance, // Cooking class definition
  281. /*[in] */ IWbemObjectAccess* pRefreshableRawInstance, // Raw instance
  282. /*[out] */ IWbemObjectAccess** ppRefreshableInstance, // Cooking instance
  283. /*[out] */ long* plId )
  284. ///////////////////////////////////////////////////////////////////////////////
  285. //
  286. // AddInstance is called to add a WMI cooking instance to the refresher. The
  287. // refreshable instance is a clone of the WMI instance that is passed in
  288. // by pCookingInstance. Once the instance is cloned, the corresponding raw
  289. // instance is added to the internal refresher, and then the cloned
  290. // cooked instance and the refreshable raw instance are added to the object
  291. // cooker. If a cooker does not already exist in the cooker cache, one
  292. // is created.
  293. //
  294. // Parameters:
  295. // pNamespace - The namespace where the objects are located
  296. // pCtx - IWbemContext implementation
  297. // pCookingInstance - The instance to be cooked
  298. // pRefreshableRawInstance
  299. // - U N U S E D P A R A M
  300. // ppRefreshableInstance
  301. // - The refreshable cooking instance passed back to
  302. // the client
  303. // plId - The ID of the instance
  304. //
  305. ///////////////////////////////////////////////////////////////////////////////
  306. {
  307. HRESULT hResult = S_OK;
  308. CWMISimpleObjectCooker* pObjectCooker = NULL;
  309. IWbemObjectAccess* pInternalRawInst = NULL; // The raw instance for the short term local refresher solution
  310. // For now, we expect that the pRefreshableRawInstance parameter will be NULL
  311. // since we are using an internal refresher to manage the raw instances
  312. // ==========================================================================
  313. if ( NULL == pNamespace || NULL == pCookingInstance || NULL != pRefreshableRawInstance )
  314. {
  315. return WBEM_E_INVALID_PARAMETER;
  316. }
  317. IWbemClassObject* pNewClassObj = NULL;
  318. IWbemClassObject* pClassObj = pCookingInstance;
  319. pClassObj->AddRef();
  320. CReleaseMe arClassObj( pClassObj );
  321. hResult = pClassObj->Clone( &pNewClassObj );
  322. if (SUCCEEDED(hResult))
  323. {
  324. CReleaseMe arNewClassObj( pNewClassObj );
  325. hResult = pNewClassObj->QueryInterface( IID_IWbemObjectAccess, (void**)ppRefreshableInstance );
  326. // Add the instance to the object cooker
  327. if ( SUCCEEDED( hResult ) )
  328. {
  329. // Get the raw instance (add it to the internal refresher)
  330. hResult = AddRawInstance( pNamespace, pCtx, *ppRefreshableInstance, &pInternalRawInst );
  331. CReleaseMe arInternalRawInst( pInternalRawInst );
  332. // Retrieve the class cooker
  333. if ( SUCCEEDED( hResult ) )
  334. {
  335. WCHAR* wszClassName = NULL;
  336. // Get the cooked class' name
  337. hResult = GetClassName( pCookingInstance, &wszClassName );
  338. wmilib::auto_buffer<WCHAR> adaClassName( wszClassName );
  339. if ( SUCCEEDED( hResult ) )
  340. {
  341. // Search for an existing cooking cache object
  342. hResult = SearchCookingClassCache( wszClassName, pObjectCooker );
  343. // If it does not exist, create a new one
  344. if ( FAILED ( hResult ) )
  345. {
  346. hResult = CreateObjectCooker( wszClassName, pCookingInstance, pInternalRawInst, &pObjectCooker, pNamespace );
  347. }
  348. }
  349. }
  350. }
  351. // Add the cooking instance
  352. if ( SUCCEEDED( hResult ) )
  353. {
  354. hResult = pObjectCooker->SetCookedInstance( *ppRefreshableInstance, plId );
  355. if ( SUCCEEDED( hResult ) )
  356. {
  357. // Add the raw instance to the cooker
  358. hResult = pObjectCooker->BeginCooking( *plId, pInternalRawInst, m_dwRefreshId );
  359. }
  360. }
  361. }
  362. return hResult;
  363. }
  364. STDMETHODIMP CRefresher::AddEnum(
  365. /*[in] */ IWbemServices* pNamespace,
  366. /*[in] */ IWbemContext * pContext,
  367. /*[in, string] */ LPCWSTR wszCookingClass,
  368. /*[in] */ IWbemHiPerfEnum* pRefreshableEnum,
  369. /*[out] */ long* plId )
  370. ///////////////////////////////////////////////////////////////////////////////
  371. //
  372. // AddEnum is called whenever a new cooked enumerator is added to the
  373. // refresher. WMI passes an IWbemHiPerfEnum object to the provider which
  374. // will be used for the cooked enumerator. The corresponding raw enumerator
  375. // is obtained when the added to the internal refresher. Both of these
  376. // enumerators as well as a cooking class template is added to the
  377. // enumerator cache.
  378. //
  379. // Parameters:
  380. // pNamespace - The namespace where the objects are located
  381. // wszCookingClass - The name of the enumerators' cooking class
  382. // pRefreshableEnum
  383. // - The enumerator to be used for the cooked classes
  384. // plId - The ID of the enumerator
  385. //
  386. ///////////////////////////////////////////////////////////////////////////////
  387. {
  388. HRESULT hResult = WBEM_NO_ERROR;
  389. IWbemHiPerfEnum* pRawEnum = NULL;
  390. long lRawID = 0;
  391. // Verify our 'in' parameters
  392. // ==========================
  393. if ( NULL == pNamespace || NULL == wszCookingClass || NULL == pRefreshableEnum )
  394. {
  395. hResult = WBEM_E_INVALID_PARAMETER;
  396. }
  397. if ( SUCCEEDED( hResult ) )
  398. {
  399. // Get the cooking object
  400. // ======================
  401. IWbemClassObject* pCookedObject = NULL;
  402. IWbemClassObject* pRawObject = NULL;
  403. BSTR strCookedClassName = SysAllocString( wszCookingClass );
  404. if (NULL == strCookedClassName) return WBEM_E_OUT_OF_MEMORY;
  405. CSysFreeMe afCookedClassName( strCookedClassName );
  406. hResult = pNamespace->GetObject( strCookedClassName, 0, NULL, &pCookedObject, NULL );
  407. CReleaseMe arCookedObject( pCookedObject );
  408. if ( SUCCEEDED( hResult ) )
  409. {
  410. WCHAR* wszRawClassName = NULL;
  411. hResult = GetRawClassName( pCookedObject, &wszRawClassName );
  412. wmilib::auto_buffer<WCHAR> adRawClassName( wszRawClassName );
  413. if ( SUCCEEDED( hResult ))
  414. {
  415. BSTR strRawClassName = SysAllocString(wszRawClassName);
  416. if (NULL == strRawClassName) return WBEM_E_OUT_OF_MEMORY;
  417. CSysFreeMe sfm(strRawClassName);
  418. hResult = pNamespace->GetObject( strRawClassName, 0, NULL, &pRawObject, NULL );
  419. if ( SUCCEEDED( hResult ) )
  420. {
  421. CReleaseMe arRawObject( pRawObject );
  422. // Add the raw enumerator to our internal refresher
  423. // ================================================
  424. hResult = AddRawEnum( pNamespace, pContext, wszRawClassName, &pRawEnum, &lRawID );
  425. CReleaseMe arRawEnum( pRawEnum );
  426. if ( SUCCEEDED( hResult ) )
  427. {
  428. // Add the cooked enumerator to the enumerator cache
  429. // =================================================
  430. hResult = m_EnumCache.AddEnum(
  431. wszCookingClass,
  432. pCookedObject, // this is acquired by CWMISimpleObjectCooker and CEnumeratorManager
  433. pRawObject,
  434. pRefreshableEnum,
  435. pRawEnum,
  436. lRawID,
  437. (DWORD*)plId );
  438. // set the three bits
  439. *plId |= WMI_COOKED_ENUM_MASK;
  440. }
  441. }
  442. }
  443. }
  444. }
  445. return hResult;
  446. }
  447. STDMETHODIMP CRefresher:: Remove(
  448. /*[in] */ long lId )
  449. ///////////////////////////////////////////////////////////////////////////////
  450. //
  451. // Remove is used to remove an object from the refresher. Depending on the
  452. // object, the corresponding removal is performed.
  453. //
  454. // Parameters:
  455. // lID - The ID of the object to be removed
  456. //
  457. ///////////////////////////////////////////////////////////////////////////////
  458. {
  459. HRESULT hResult = S_OK;
  460. // Is it an instance ID?
  461. // =====================
  462. if ( lId == ( lId & ~WMI_COOKED_ENUM_MASK ) )
  463. {
  464. CWMISimpleObjectCooker* pCooker = NULL;
  465. hResult = m_CookingClassCache.BeginEnum();
  466. while ( S_OK == m_CookingClassCache.Next( &pCooker ) )
  467. {
  468. pCooker->Remove( lId );
  469. }
  470. hResult = m_CookingClassCache.EndEnum();
  471. }
  472. else
  473. {
  474. long RawId;
  475. hResult = m_EnumCache.RemoveEnum( (lId & ~WMI_COOKED_ENUM_MASK) , &RawId );
  476. if (SUCCEEDED(hResult)){
  477. m_pConfig->Remove(RawId,0);
  478. }
  479. }
  480. return hResult;
  481. }
  482. STDMETHODIMP CRefresher::Refresh()
  483. ///////////////////////////////////////////////////////////////////////////////
  484. //
  485. // Refresh is called when the refreshers' objects are to be updated. The
  486. // instances are updated by explicitly enumerating through the instance
  487. // cache. The enumerators' refresh is performed with the enumerator
  488. // cache.
  489. //
  490. // Parameters: (none)
  491. //
  492. ///////////////////////////////////////////////////////////////////////////////
  493. {
  494. HRESULT hResult = S_OK;
  495. CWMISimpleObjectCooker* pCooker = NULL;
  496. // Refresh the internal refresher
  497. // ==============================
  498. m_dwRefreshId++;
  499. hResult = m_pRefresher->Refresh( 0L );
  500. if ( SUCCEEDED( hResult ) )
  501. {
  502. // INSTANCES: Update the instance values for every class
  503. // =====================================================
  504. hResult = m_CookingClassCache.BeginEnum();
  505. while ( S_OK == m_CookingClassCache.Next( &pCooker ) )
  506. {
  507. // And update all of the instances
  508. // ===============================
  509. pCooker->Recalc(m_dwRefreshId);
  510. }
  511. hResult = m_CookingClassCache.EndEnum();
  512. // ENUMERATORS: Merge and update the values for items in the enumerator
  513. // ====================================================================
  514. if ( SUCCEEDED( hResult ) )
  515. {
  516. hResult = m_EnumCache.Refresh(m_dwRefreshId);
  517. }
  518. }
  519. return hResult;
  520. }
  521. STDMETHODIMP CRefresher::Refresh( long lFlags )
  522. ///////////////////////////////////////////////////////////////////////////////
  523. //
  524. // This is the IWbemRefresher::Refresh implementation and is simply a call
  525. // through.
  526. //
  527. ///////////////////////////////////////////////////////////////////////////////
  528. {
  529. HRESULT hResult = WBEM_NO_ERROR;
  530. hResult = Refresh();
  531. return hResult;
  532. }