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.

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