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.

683 lines
16 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. History:
  6. --*/
  7. // WMIObjCooker.cpp
  8. #include "precomp.h"
  9. #include "WMIObjCooker.h"
  10. #include "RawCooker.h"
  11. #include <comdef.h>
  12. ///////////////////////////////////////////////////////////////////////////////
  13. //
  14. // Helper Functions
  15. // ================
  16. //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. WMISTATUS GetPropValue( CProperty* pProp, IWbemObjectAccess* pInstance, __int64* pnResult )
  19. {
  20. WMISTATUS dwStatus = WBEM_NO_ERROR;
  21. unsigned __int64 nResult = 0;
  22. DWORD dwRes = 0;
  23. switch( pProp->GetType() )
  24. {
  25. case CIM_UINT32:
  26. {
  27. dwStatus = pInstance->ReadDWORD( pProp->GetHandle(), &dwRes );
  28. if (pnResult) {
  29. *pnResult = dwRes;
  30. }
  31. }break;
  32. case CIM_UINT64:
  33. {
  34. dwStatus = pInstance->ReadQWORD( pProp->GetHandle(), &nResult );
  35. if (pnResult) {
  36. *pnResult = nResult;
  37. }
  38. }break;
  39. default:
  40. dwStatus = WBEM_E_TYPE_MISMATCH;
  41. }
  42. return dwStatus;
  43. }
  44. //////////////////////////////////////////////////////////////
  45. //
  46. // CWMISimpleObjectCooker
  47. //
  48. //////////////////////////////////////////////////////////////
  49. CWMISimpleObjectCooker::CWMISimpleObjectCooker( WCHAR* wszCookingClassName,
  50. IWbemObjectAccess* pCookingClass,
  51. IWbemObjectAccess* pRawClass,
  52. IWbemServices * pNamespace ) :
  53. m_lRef( 1 ),
  54. m_pCookingClass( NULL ),
  55. m_wszClassName(NULL),
  56. m_pNamespace(NULL),
  57. m_dwPropertyCacheSize( 16 ),
  58. m_dwNumProperties( 0 ),
  59. m_NumInst(0),
  60. m_InitHR(WBEM_E_INITIALIZATION_FAILURE)
  61. {
  62. #ifdef _VERBOSE
  63. {
  64. char pBuff[128];
  65. wsprintfA(pBuff,"Cooker %p\n",this);
  66. OutputDebugStringA(pBuff);
  67. }
  68. #endif
  69. if (pNamespace){
  70. m_pNamespace = pNamespace;
  71. m_pNamespace->AddRef();
  72. }
  73. m_InitHR = SetClass( wszCookingClassName, pCookingClass, pRawClass );
  74. if (m_pNamespace){
  75. m_pNamespace->Release();
  76. m_pNamespace = NULL;
  77. }
  78. }
  79. CWMISimpleObjectCooker::~CWMISimpleObjectCooker()
  80. {
  81. Reset();
  82. // Release the cooking class
  83. // =========================
  84. if ( m_pCookingClass ){
  85. m_pCookingClass->Release();
  86. }
  87. if (m_pNamespace){
  88. m_pNamespace->Release();
  89. }
  90. // Delete the property cache
  91. // =========================
  92. for (DWORD i=0;i<m_apPropertyCache.size();i++){
  93. CCookingProperty* pCookProp = m_apPropertyCache[i];
  94. if (pCookProp)
  95. delete pCookProp;
  96. }
  97. if (m_wszClassName)
  98. delete [] m_wszClassName;
  99. #ifdef _VERBOSE
  100. {
  101. char pBuff[128];
  102. wsprintfA(pBuff,"~Cooker %p istances left %d\n",this,m_NumInst);
  103. OutputDebugStringA(pBuff);
  104. }
  105. #endif
  106. }
  107. //////////////////////////////////////////////////////////////
  108. //
  109. // COM methods
  110. //
  111. //////////////////////////////////////////////////////////////
  112. STDMETHODIMP CWMISimpleObjectCooker::QueryInterface(REFIID riid, void** ppv)
  113. //////////////////////////////////////////////////////////////
  114. //
  115. // Standard QueryInterface
  116. //
  117. // Parameters:
  118. // riid - the ID of the requested interface
  119. // ppv - a pointer to the interface pointer
  120. //
  121. //////////////////////////////////////////////////////////////
  122. //ok
  123. {
  124. if(riid == IID_IUnknown)
  125. *ppv = (LPVOID)(IUnknown*)(IWMISimpleCooker*)this;
  126. else if(riid == IID_IWMISimpleCooker)
  127. *ppv = (LPVOID)(IWMISimpleCooker*)this;
  128. else return E_NOINTERFACE;
  129. ((IUnknown*)*ppv)->AddRef();
  130. return S_OK;
  131. }
  132. STDMETHODIMP_(ULONG) CWMISimpleObjectCooker::AddRef()
  133. //////////////////////////////////////////////////////////////
  134. //
  135. // Standard COM AddRef
  136. //
  137. //////////////////////////////////////////////////////////////
  138. //ok
  139. {
  140. return InterlockedIncrement(&m_lRef);
  141. }
  142. STDMETHODIMP_(ULONG) CWMISimpleObjectCooker::Release()
  143. //////////////////////////////////////////////////////////////
  144. //
  145. // Standard COM Release
  146. //
  147. //////////////////////////////////////////////////////////////
  148. //ok
  149. {
  150. long lRef = InterlockedDecrement(&m_lRef);
  151. if(lRef == 0)
  152. delete this;
  153. return lRef;
  154. }
  155. STDMETHODIMP CWMISimpleObjectCooker::SetClass(
  156. /*[in] */ WCHAR* wszCookingClassName,
  157. /*[in] */ IWbemObjectAccess *pCookingClassAccess,
  158. /*[in] */ IWbemObjectAccess *pRawClass )
  159. {
  160. HRESULT hResult = S_OK;
  161. IWbemClassObject * pClass = NULL;
  162. // Cannot override the original cooking class for now
  163. // ==================================================
  164. if ( ( NULL != m_pCookingClass ) || ( NULL == pCookingClassAccess ) )
  165. hResult = E_FAIL;
  166. // what we put here MUST be a class, Singletons are OK
  167. if (m_pNamespace)
  168. {
  169. _variant_t VarGenus;
  170. hResult = pCookingClassAccess->Get(L"__GENUS",0,&VarGenus,NULL,NULL);
  171. if (SUCCEEDED(hResult))
  172. {
  173. if ((CIM_SINT32 == V_VT(&VarGenus)) &&
  174. WBEM_GENUS_CLASS == V_I4(&VarGenus))
  175. {
  176. }
  177. else
  178. {
  179. BSTR BstrName = SysAllocString(wszCookingClassName);
  180. if (BstrName)
  181. {
  182. CAutoFree sfm(BstrName);
  183. m_pNamespace->GetObject(BstrName,0,NULL,&pClass,NULL);
  184. }
  185. else
  186. {
  187. hResult = WBEM_E_OUT_OF_MEMORY;
  188. }
  189. }
  190. }
  191. }
  192. IWbemClassObject * pCookingClassAccess2;
  193. pCookingClassAccess2 = (pClass)?pClass:pCookingClassAccess;
  194. // Verify and process the cooking class
  195. // ====================================
  196. if ( SUCCEEDED( hResult ) )
  197. {
  198. BOOL bRet;
  199. bRet = IsCookingClass( pCookingClassAccess );
  200. if ( bRet ){
  201. // Save the class
  202. // ==============
  203. m_pCookingClass = pCookingClassAccess;
  204. m_pCookingClass->AddRef();
  205. } else {
  206. hResult = WBEM_E_INVALID_CLASS;
  207. }
  208. // Set the class name
  209. // ==================
  210. if ( SUCCEEDED( hResult ) )
  211. {
  212. m_wszClassName = new WCHAR[ wcslen( wszCookingClassName ) + 1 ];
  213. wcscpy( m_wszClassName, wszCookingClassName );
  214. }
  215. // Initialize the cooking properties
  216. // =================================
  217. if ( SUCCEEDED( hResult ) )
  218. {
  219. hResult = SetProperties( pCookingClassAccess2, pRawClass );
  220. }
  221. }
  222. if (pClass){
  223. pClass->Release();
  224. }
  225. return hResult;
  226. }
  227. WMISTATUS CWMISimpleObjectCooker::SetProperties( IWbemClassObject* pCookingClassObject, IWbemObjectAccess *pRawClass )
  228. {
  229. WMISTATUS dwStatus = WBEM_NO_ERROR;
  230. BSTR strPropName = NULL;
  231. long lHandle = 0;
  232. CIMTYPE ct;
  233. BOOL bAtLeastOne = FALSE;
  234. IWbemObjectAccess * pCookingClassAccess = NULL;
  235. dwStatus = pCookingClassObject->QueryInterface(IID_IWbemObjectAccess ,(void **)&pCookingClassAccess);
  236. if (FAILED(dwStatus))
  237. {
  238. return dwStatus;
  239. }
  240. CAutoRelease rm(pCookingClassAccess );
  241. // get only once the qualifier set
  242. IWbemQualifierSet* pCookingClassQSet = NULL;
  243. dwStatus = pCookingClassObject->GetQualifierSet(&pCookingClassQSet);
  244. if (FAILED(dwStatus))
  245. {
  246. return dwStatus;
  247. }
  248. CAutoRelease rm1(pCookingClassQSet);
  249. //
  250. // should we be using [TimeStamp|Frequency]_[Time|Sys100ns|Object] ?
  251. //
  252. BOOL bUseWellKnownIfNeeded = FALSE;
  253. dwStatus = pCookingClassQSet->Get(WMI_COOKER_AUTOCOOK_RAWDEFAULT,0,NULL,NULL);
  254. // we have already verified version and property, just test if it's there
  255. if ( SUCCEEDED(dwStatus) )
  256. {
  257. bUseWellKnownIfNeeded = TRUE;
  258. }
  259. else // do not propagate this error
  260. {
  261. dwStatus = WBEM_NO_ERROR;
  262. }
  263. // Enumerate and save the autocook properties
  264. // ==========================================
  265. pCookingClassObject->BeginEnumeration( WBEM_FLAG_NONSYSTEM_ONLY );
  266. while ( WBEM_S_NO_ERROR == pCookingClassObject->Next(0,&strPropName,NULL,&ct,NULL) &&
  267. SUCCEEDED(dwStatus))
  268. {
  269. CAutoFree afPropName( strPropName );
  270. DWORD dwCounterType = 0;
  271. DWORD dwReqProp = 0;
  272. // Determine if it is an autocook property
  273. // =======================================
  274. if ( IsCookingProperty( strPropName, pCookingClassObject, &dwCounterType, &dwReqProp ) )
  275. {
  276. m_dwNumProperties++;
  277. // The property is an autocook; save the Name, ObjectAccess handle, type and cooking object
  278. // ========================================================================================
  279. dwStatus = pCookingClassAccess->GetPropertyHandle( strPropName, &ct, &lHandle );
  280. if ( SUCCEEDED( dwStatus ) )
  281. {
  282. #ifdef _VERBOSE
  283. {
  284. char pBuff[128];
  285. wsprintfA(pBuff,"%S %08x %08x\n",strPropName,dwCounterType,dwReqProp);
  286. OutputDebugStringA(pBuff);
  287. }
  288. #endif
  289. CCookingProperty* pProperty = new CCookingProperty( strPropName,
  290. dwCounterType,
  291. lHandle,
  292. ct,
  293. dwReqProp,
  294. bUseWellKnownIfNeeded);
  295. // Initialize the property object
  296. // ==============================
  297. IWbemQualifierSet* pCookingPropQualifierSet = NULL;
  298. dwStatus = pCookingClassObject->GetPropertyQualifierSet( strPropName, &pCookingPropQualifierSet );
  299. CAutoRelease arQualifierSet( pCookingPropQualifierSet );
  300. if ( SUCCEEDED( dwStatus ) )
  301. {
  302. dwStatus = pProperty->Initialize( pCookingPropQualifierSet, pRawClass, pCookingClassQSet );
  303. }
  304. // If everything worked out then add the property to the cache
  305. // ===========================================================
  306. if ( SUCCEEDED( dwStatus ) )
  307. {
  308. bAtLeastOne = TRUE;
  309. try
  310. {
  311. m_apPropertyCache.push_back(pProperty);
  312. }
  313. catch (...)
  314. {
  315. dwStatus = WBEM_E_OUT_OF_MEMORY;
  316. }
  317. }
  318. else
  319. {
  320. delete pProperty;
  321. }
  322. }
  323. }
  324. }
  325. pCookingClassObject->EndEnumeration();
  326. if (!bAtLeastOne && (SUCCEEDED(dwStatus))){
  327. dwStatus = WBEM_E_INVALID_CLASS;
  328. }
  329. return dwStatus;
  330. }
  331. STDMETHODIMP CWMISimpleObjectCooker::SetCookedInstance(
  332. /*[in] */ IWbemObjectAccess *pCookedInstance,
  333. /*[out] */ long *plID)
  334. {
  335. HRESULT hResult = S_OK;
  336. CCookingInstance* pInstance = new CCookingInstance( pCookedInstance, m_apPropertyCache.size() );
  337. if (!pInstance || !pInstance->IsValid())
  338. {
  339. delete pInstance;
  340. return WBEM_E_OUT_OF_MEMORY;
  341. }
  342. for ( DWORD dwProp = 0; dwProp < m_apPropertyCache.size() && SUCCEEDED(hResult); dwProp++ )
  343. {
  344. CCookingProperty* pProp = m_apPropertyCache[dwProp];
  345. hResult = pInstance->InitProperty( dwProp, pProp->NumberOfActiveSamples(), pProp->MinSamplesRequired() );
  346. }
  347. if (FAILED(hResult))
  348. {
  349. delete pInstance;
  350. return hResult;
  351. }
  352. // Add new cooked instance
  353. // =======================
  354. hResult = m_InstanceCache.Add( (DWORD *)plID, pInstance );
  355. m_NumInst++;
  356. return hResult;
  357. }
  358. STDMETHODIMP CWMISimpleObjectCooker::BeginCooking(
  359. /*[in] */ long lId,
  360. /*[in] */ IWbemObjectAccess *pSampleInstance,
  361. /*[in] */ DWORD dwRefreshStamp)
  362. {
  363. HRESULT hResult = S_OK;
  364. CCookingInstance* pCookedInstance = NULL;
  365. // Add an initial sample to the cache
  366. // ==================================
  367. hResult = m_InstanceCache.GetData( lId, &pCookedInstance );
  368. if ( SUCCEEDED( hResult ) )
  369. {
  370. if ( NULL != pCookedInstance )
  371. {
  372. hResult = pCookedInstance->SetRawSourceInstance( pSampleInstance );
  373. if ( SUCCEEDED( hResult ) )
  374. {
  375. hResult = UpdateSamples( pCookedInstance, dwRefreshStamp );
  376. }
  377. }
  378. else
  379. {
  380. hResult = E_FAIL;
  381. }
  382. }
  383. return hResult;
  384. }
  385. STDMETHODIMP CWMISimpleObjectCooker::StopCooking(
  386. /*[in] */ long lId)
  387. {
  388. HRESULT hResult = S_OK;
  389. CCookingInstance* pInstance = NULL;
  390. // ????
  391. hResult = m_InstanceCache.GetData( lId, &pInstance );
  392. return hResult;
  393. }
  394. STDMETHODIMP CWMISimpleObjectCooker::Recalc(DWORD dwRefreshStamp)
  395. {
  396. HRESULT hResult = S_OK;
  397. CCookingInstance* pInstance = NULL;
  398. // Cook all of the instances which have a cached sample
  399. // ====================================================
  400. m_InstanceCache.BeginEnum();
  401. DWORD i=0;
  402. while ( S_OK == m_InstanceCache.Next( &pInstance ) )
  403. {
  404. // since we are inside a CritSec
  405. // we need to ensire that we call
  406. // EndEnum, that will release the Lock on the CritSec
  407. try {
  408. if ( pInstance )
  409. {
  410. hResult = CookInstance( pInstance, dwRefreshStamp );
  411. #ifdef _VERBOSE
  412. {
  413. char pBuff[128];
  414. wsprintfA(pBuff,"%S %p %d\n",pInstance->GetKey(),pInstance,i++);
  415. OutputDebugStringA(pBuff);
  416. }
  417. #endif
  418. }
  419. } catch(...){
  420. #ifdef _VERBOSE
  421. OutputDebugStringA("exception\n");
  422. #endif
  423. }
  424. }
  425. m_InstanceCache.EndEnum();
  426. return hResult;
  427. }
  428. STDMETHODIMP CWMISimpleObjectCooker::Remove(
  429. /*[in] */ long lId)
  430. {
  431. HRESULT hResult = S_OK;
  432. // Remove the specified instance from the cache
  433. // ============================================
  434. CCookingInstance * pInst = NULL;
  435. hResult = m_InstanceCache.Remove( lId, &pInst );
  436. if (pInst){
  437. delete pInst;
  438. m_NumInst--;
  439. }
  440. return hResult;
  441. }
  442. STDMETHODIMP CWMISimpleObjectCooker::Reset()
  443. {
  444. HRESULT hResult = S_OK;
  445. // Remove all of the instances from the cache
  446. // ==========================================
  447. CCookingInstance * pInstance = NULL;
  448. m_InstanceCache.BeginEnum();
  449. while ( S_OK == m_InstanceCache.Next( &pInstance ) )
  450. {
  451. if (pInstance){
  452. delete pInstance;
  453. m_NumInst--;
  454. pInstance = NULL;
  455. }
  456. }
  457. m_InstanceCache.EndEnum();
  458. hResult = m_InstanceCache.RemoveAll();
  459. return hResult;
  460. }
  461. WMISTATUS CWMISimpleObjectCooker::CookInstance( CCookingInstance* pInstance,
  462. DWORD dwRefreshStamp)
  463. {
  464. WMISTATUS dwStatus = S_OK;
  465. if ( SUCCEEDED( dwStatus ) )
  466. {
  467. dwStatus = UpdateSamples( pInstance, dwRefreshStamp );
  468. // Loop through the cooking properties
  469. // ===================================
  470. for ( DWORD dwProp = 0; dwProp < m_apPropertyCache.size(); dwProp++ )
  471. {
  472. // Update the cooking instance property
  473. // ====================================
  474. pInstance->CookProperty( dwProp, m_apPropertyCache[dwProp] );
  475. }
  476. }
  477. return dwStatus;
  478. }
  479. WMISTATUS CWMISimpleObjectCooker::UpdateSamples( CCookingInstance* pCookedInstance, DWORD dwRefreshStamp )
  480. {
  481. WMISTATUS dwStatus = WBEM_NO_ERROR;
  482. IWbemObjectAccess* pRawInstance = NULL;
  483. if ( NULL == pCookedInstance )
  484. {
  485. dwStatus = WBEM_E_INVALID_PARAMETER;
  486. }
  487. if ( SUCCEEDED( dwStatus ) )
  488. {
  489. dwStatus = pCookedInstance->GetRawSourceInstance( &pRawInstance );
  490. CAutoRelease arRawInstance( pRawInstance );
  491. if ( NULL == pRawInstance )
  492. {
  493. dwStatus = WBEM_E_FAILED;
  494. }
  495. #ifdef _VERBOSE
  496. {
  497. WCHAR pBuff[256];
  498. _variant_t Var;
  499. HRESULT hr = pRawInstance->Get(L"__RELPATH",0,&Var,NULL,NULL);
  500. wsprintfW(pBuff,L"%p hr %08x __RELPATH %s Key %s\n",pRawInstance,hr,V_BSTR(&Var),pCookedInstance->GetKey());
  501. OutputDebugStringW(pBuff);
  502. }
  503. #endif
  504. for ( DWORD dwProp = 0; ( SUCCEEDED( dwStatus ) ) && dwProp < m_apPropertyCache.size(); dwProp++ )
  505. {
  506. CCookingProperty* pProp = m_apPropertyCache[dwProp];
  507. CProperty* pRawProp = pProp->GetRawCounterProperty();
  508. CProperty* pBaseProp = pProp->GetBaseProperty();
  509. CProperty* pTimeProp = pProp->GetTimeProperty();
  510. __int64 nRawCounter = 0;
  511. __int64 nRawBase = 0;
  512. __int64 nTimeStamp = 0;
  513. dwStatus = GetPropValue( pRawProp, pRawInstance, &nRawCounter );
  514. if ( pBaseProp )
  515. {
  516. GetPropValue( pBaseProp, pRawInstance, &nRawBase );
  517. }
  518. else if (pProp->IsReq(REQ_BASE))
  519. {
  520. nRawBase = 1;
  521. }
  522. if ( pTimeProp )
  523. {
  524. GetPropValue( pTimeProp, pRawInstance, &nTimeStamp );
  525. }
  526. else if (pProp->IsReq(REQ_TIME))
  527. {
  528. LARGE_INTEGER li;
  529. QueryPerformanceCounter(&li);
  530. nTimeStamp = li.QuadPart;
  531. }
  532. dwStatus = pCookedInstance->AddSample( dwRefreshStamp, dwProp, nRawCounter, nRawBase, nTimeStamp );
  533. #ifdef _VERBOSE
  534. {
  535. char pBuff[128];
  536. wsprintfA(pBuff,"Prop %d status %08x\n"
  537. " counter %I64u base %I64u time %I64u\n",
  538. dwProp, dwStatus, nRawCounter, nRawBase, nTimeStamp);
  539. OutputDebugStringA(pBuff);
  540. }
  541. #endif
  542. }
  543. }
  544. return dwStatus;
  545. }