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.

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