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.

1260 lines
36 KiB

  1. //***************************************************************************
  2. //
  3. // (c) 1997-1999 by Microsoft Corp.
  4. //
  5. // REFRESHR.CPP
  6. //
  7. // Mapped NT5 Perf Counter Provider
  8. //
  9. // raymcc 02-Dec-97 Created.
  10. // raymcc 20-Feb-98 Updated to use new initializer.
  11. // bobw 8-Jub-98 optimized for use with NT Perf counters
  12. //
  13. //***************************************************************************
  14. #include "wpheader.h"
  15. #include <stdio.h>
  16. #include "oahelp.inl"
  17. #define __WBEMSECURITY 1
  18. // HRESULT CNt5PerfProvider::CheckImpersonationLevel (void);
  19. // BOOL CNt5PerfProvider::HasPermission (void);
  20. // Timeout for our wait calls
  21. #define REFRESHER_MUTEX_WAIT_TIMEOUT 10000
  22. class CMutexReleaseMe
  23. {
  24. private:
  25. HANDLE m_hMutex;
  26. public:
  27. CMutexReleaseMe( HANDLE hMutex ) : m_hMutex( hMutex ) {};
  28. ~CMutexReleaseMe() { if ( NULL != m_hMutex ) ReleaseMutex( m_hMutex ); };
  29. };
  30. //***************************************************************************
  31. //
  32. // RefresherCacheEl::RefresherCacheEl
  33. //
  34. // Constructor
  35. //
  36. //***************************************************************************
  37. // ok
  38. RefresherCacheEl::RefresherCacheEl()
  39. {
  40. m_dwPerfObjIx = 0;
  41. m_pClassMap = NULL;
  42. m_pSingleton = NULL;
  43. m_lSingletonId = 0;
  44. m_plIds = NULL; // array of ID's
  45. m_lEnumArraySize = 0; // size of ID array in elements
  46. m_pHiPerfEnum = NULL;
  47. m_lEnumId = 0;
  48. }
  49. //***************************************************************************
  50. //
  51. // RefresherCacheEl::~RefresherCacheEl()
  52. //
  53. // Destructor
  54. //
  55. //***************************************************************************
  56. // ok
  57. RefresherCacheEl::~RefresherCacheEl()
  58. {
  59. LONG nNumInstances;
  60. int i;
  61. delete m_pClassMap;
  62. if (m_pSingleton != NULL) {
  63. m_pSingleton->Release();
  64. m_pSingleton = NULL;
  65. m_lSingletonId = 0;
  66. }
  67. nNumInstances = m_aInstances.Size();
  68. for (i = 0; i < nNumInstances; i++) {
  69. delete (CachedInst *) m_aInstances[i];
  70. }
  71. nNumInstances = m_aEnumInstances.Size();
  72. if (nNumInstances> 0) {
  73. IWbemObjectAccess *pAccess;
  74. for (i = 0; i < nNumInstances ; i++) {
  75. pAccess = (IWbemObjectAccess *)(m_aEnumInstances.GetAt(i));
  76. if (pAccess != NULL) {
  77. pAccess->Release();
  78. }
  79. }
  80. m_aEnumInstances.Empty();
  81. }
  82. if (m_plIds != NULL) {
  83. delete (m_plIds);
  84. m_plIds = NULL;
  85. m_lEnumArraySize = 0;
  86. }
  87. if (m_pHiPerfEnum != NULL) {
  88. m_pHiPerfEnum->Release();
  89. m_pHiPerfEnum = NULL;
  90. }
  91. }
  92. //***************************************************************************
  93. //
  94. // CNt5Refresher constructor
  95. //
  96. //***************************************************************************
  97. // ok
  98. CNt5Refresher::CNt5Refresher(CNt5PerfProvider *pPerfProviderArg)
  99. {
  100. assert (pPerfProviderArg != NULL);
  101. m_ClsidType = pPerfProviderArg->m_OriginClsid;
  102. m_pPerfProvider = pPerfProviderArg;
  103. m_pPerfProvider = NULL; // for testing of local class map
  104. if (m_pPerfProvider != NULL) {
  105. m_pPerfProvider->AddRef();
  106. }
  107. m_hAccessMutex = CreateMutex (NULL, TRUE, NULL);
  108. m_dwGetGetNextClassIndex = 0;
  109. m_lRef = 0; // COM Ref Count
  110. m_lProbableId = 1; // Used for new IDs
  111. m_aCache.Empty(); // clear and reset the array
  112. RELEASE_MUTEX (m_hAccessMutex);
  113. }
  114. //***************************************************************************
  115. //
  116. // CNt5Refresher destructor
  117. //
  118. //***************************************************************************
  119. // ok
  120. CNt5Refresher::~CNt5Refresher()
  121. {
  122. int nNumElements;
  123. int i;
  124. PRefresherCacheEl pCacheEl;
  125. assert (m_lRef == 0);
  126. // Make sure we get access to the mutex before we try and clean things up.
  127. // If we don't get it in a reasonable time, something's up. Since we're
  128. // destructing, we'll just quietly let stuff go.
  129. if ( WaitForSingleObject( m_hAccessMutex, REFRESHER_MUTEX_WAIT_TIMEOUT ) == WAIT_OBJECT_0 )
  130. {
  131. // This will auto-release the mutex in case something bad happens
  132. CMutexReleaseMe mrm( m_hAccessMutex );
  133. nNumElements = m_aCache.Size();
  134. for (i = 0; i < nNumElements; i++) {
  135. pCacheEl = (PRefresherCacheEl)m_aCache[i];
  136. // We want to call this once for each instance
  137. for ( int n = 0; n < pCacheEl->m_aInstances.Size(); n++ )
  138. {
  139. m_PerfObj.RemoveClass (pCacheEl->m_pClassMap->m_pClassDef);
  140. }
  141. // If we have a Singleton value, RemoveClass should be
  142. // called once more
  143. if ( NULL != pCacheEl->m_pSingleton )
  144. {
  145. m_PerfObj.RemoveClass (pCacheEl->m_pClassMap->m_pClassDef);
  146. }
  147. // And finally if we have an enumerator, remove the class
  148. // once more.
  149. if ( NULL != pCacheEl->m_pHiPerfEnum )
  150. {
  151. m_PerfObj.RemoveClass (pCacheEl->m_pClassMap->m_pClassDef);
  152. }
  153. delete pCacheEl;
  154. }
  155. if (m_pPerfProvider != NULL) {
  156. m_pPerfProvider->Release();
  157. m_pPerfProvider = NULL;
  158. }
  159. }
  160. CloseHandle (m_hAccessMutex);
  161. }
  162. //***************************************************************************
  163. //
  164. // CNt5Refresher::Refresh
  165. //
  166. // Executed to refresh a set of instances bound to the particular
  167. // refresher.
  168. //
  169. //***************************************************************************
  170. // ok
  171. HRESULT CNt5Refresher::Refresh(/* [in] */ long lFlags)
  172. {
  173. HRESULT hrReturn = WBEM_S_NO_ERROR;
  174. HRESULT hReturn = S_OK;
  175. BOOL bRes;
  176. UNREFERENCED_PARAMETER(lFlags);
  177. BOOL bNeedCoImpersonate = FALSE;
  178. //
  179. // this is ugly
  180. // wmicookr is not impersonating, because
  181. // it relys on other provider to do that
  182. // but, it calls the IWbemRefresher::Refresh when it's inside winmgmt or wmiprvse
  183. // and it calls it from an UN-Impersonated thread
  184. // so, we need that the provider calls CoImpersonateClient
  185. // on a Refresh invocation, that is expensive in general,
  186. // only if the provider has been invoked through the Server CLSID
  187. //
  188. BOOL fRevert;
  189. if (CNt5PerfProvider::CLSID_SERVER == m_ClsidType)
  190. {
  191. #ifdef __WBEMSECURITY
  192. hReturn = CoImpersonateClient(); // make sure we're legit.
  193. fRevert = SUCCEEDED( hReturn );
  194. // The following error appears to occur when we are in-proc and there is no
  195. // proxy/stub, so we are effectively impersonating already
  196. if ( RPC_E_CALL_COMPLETE == hReturn ) {
  197. hReturn = S_OK;
  198. }
  199. if (S_OK == hReturn) {
  200. hReturn = CNt5PerfProvider::CheckImpersonationLevel();
  201. }
  202. // Check Registry security here.
  203. if ((hReturn != S_OK) || (!CNt5PerfProvider::HasPermission())) {
  204. // if Impersonation level is incorrect or
  205. // the caller doesn't have permission to read
  206. // from the registry, then they cannot continue
  207. hReturn = WBEM_E_ACCESS_DENIED;
  208. }
  209. #else
  210. hReturn = S_OK;
  211. #endif
  212. }
  213. if (hReturn == S_OK)
  214. {
  215. // Make sure we get access to the mutex before we continue. If we can't
  216. // get to it, something's wrong, so we'll just assume we are busy.
  217. if ( WaitForSingleObject( m_hAccessMutex, REFRESHER_MUTEX_WAIT_TIMEOUT ) == WAIT_OBJECT_0 )
  218. {
  219. // This will auto-release the mutex in case something bad happens
  220. CMutexReleaseMe mrm( m_hAccessMutex );
  221. bRes = PerfHelper::RefreshInstances(this);
  222. if (!bRes) {
  223. hrReturn = WBEM_E_FAILED;
  224. }
  225. }
  226. else
  227. {
  228. hrReturn = WBEM_E_REFRESHER_BUSY;
  229. }
  230. }
  231. if (CNt5PerfProvider::CLSID_SERVER == m_ClsidType)
  232. {
  233. #ifdef __WBEMSECURITY
  234. // Revert if we successfuly impersonated the user
  235. if ( fRevert )
  236. {
  237. CoRevertToSelf();
  238. }
  239. #endif
  240. }
  241. return hrReturn;
  242. }
  243. //***************************************************************************
  244. //
  245. // CNt5Refresher::AddRef
  246. //
  247. // Standard COM AddRef().
  248. //
  249. //***************************************************************************
  250. // ok
  251. ULONG CNt5Refresher::AddRef()
  252. {
  253. return InterlockedIncrement(&m_lRef);
  254. }
  255. //***************************************************************************
  256. //
  257. // CNt5Refresher::Release
  258. //
  259. // Standard COM Release().
  260. //
  261. //***************************************************************************
  262. // ok
  263. ULONG CNt5Refresher::Release()
  264. {
  265. long lRef = InterlockedDecrement(&m_lRef);
  266. if(lRef == 0)
  267. delete this;
  268. return lRef;
  269. }
  270. //***************************************************************************
  271. //
  272. // CNt5Refresher::QueryInterface
  273. //
  274. // Standard COM QueryInterface().
  275. //
  276. //***************************************************************************
  277. // ok
  278. HRESULT CNt5Refresher::QueryInterface(REFIID riid, void** ppv)
  279. {
  280. if (riid == IID_IUnknown || riid == IID_IWbemRefresher)
  281. {
  282. *ppv = (IWbemRefresher *) this;
  283. AddRef();
  284. return S_OK;
  285. }
  286. else return E_NOINTERFACE;
  287. }
  288. //***************************************************************************
  289. //
  290. // CNt5Refresher::RemoveObject
  291. //
  292. // Removes an object from the refresher. Since we don't know
  293. // by ID alone which class it is, we loop through all the ones we
  294. // have until somebody claims it and returns TRUE for a removal.(
  295. //
  296. //***************************************************************************
  297. // ok
  298. BOOL CNt5Refresher::RemoveObject(LONG lId)
  299. {
  300. BOOL bReturn = FALSE;
  301. BOOL bRes;
  302. PRefresherCacheEl pCacheEl;
  303. int nNumElements;
  304. // Make sure we get access to the mutex before we continue. If we can't
  305. // get to it, something's wrong, so we'll just assume we are busy.
  306. if ( WaitForSingleObject( m_hAccessMutex, REFRESHER_MUTEX_WAIT_TIMEOUT ) == WAIT_OBJECT_0 )
  307. {
  308. // This will auto-release the mutex in case something bad happens
  309. CMutexReleaseMe mrm( m_hAccessMutex );
  310. nNumElements = m_aCache.Size();
  311. for (int i = 0; i < nNumElements; i++)
  312. {
  313. pCacheEl = PRefresherCacheEl(m_aCache[i]);
  314. assert (pCacheEl != NULL);
  315. bRes = pCacheEl->RemoveInst(lId);
  316. if (bRes == TRUE) {
  317. // found the matching instance so
  318. // de register this with the perf library
  319. m_PerfObj.RemoveClass (pCacheEl->m_pClassMap->m_pClassDef);
  320. bReturn = TRUE;
  321. break;
  322. }
  323. }
  324. }
  325. else
  326. {
  327. SetLastError( (ULONG) WBEM_E_REFRESHER_BUSY );
  328. bReturn = FALSE;
  329. }
  330. return bReturn;
  331. }
  332. //***************************************************************************
  333. //
  334. // CNt5Refresher::FindSingletonInst
  335. //
  336. // Based on a perf object identification, locates a singleton WBEM
  337. // instance of that class within this refresher and returns the pointer
  338. // to it and its WBEM class info.
  339. //
  340. // Note that the <dwPerfObjIx> maps directly to a WBEM Class entry.
  341. //
  342. // To save execution time, we don't AddRef() the return value and the
  343. // caller doesn't Release().
  344. //
  345. //***************************************************************************
  346. // ok
  347. BOOL CNt5Refresher::FindSingletonInst(
  348. IN DWORD dwPerfObjIx,
  349. OUT IWbemObjectAccess **pInst,
  350. OUT CClassMapInfo **pClsMap
  351. )
  352. {
  353. BOOL bReturn = FALSE;
  354. PRefresherCacheEl pCacheEl;
  355. int l = 0;
  356. int u = m_aCache.Size() - 1;
  357. int m;
  358. // Binary search the cache.
  359. // ========================
  360. while (l <= u) {
  361. m = (l + u) / 2;
  362. pCacheEl = PRefresherCacheEl(m_aCache[m]);
  363. if (dwPerfObjIx < pCacheEl->m_dwPerfObjIx) {
  364. u = m - 1;
  365. } else if (dwPerfObjIx > pCacheEl->m_dwPerfObjIx) {
  366. l = m + 1;
  367. } else {
  368. *pClsMap = pCacheEl->m_pClassMap;
  369. *pInst = pCacheEl->m_pSingleton; // No AddRef() caller doesn't
  370. // change ref count
  371. bReturn = TRUE;
  372. break;
  373. }
  374. }
  375. // Not found
  376. // =========
  377. return bReturn;
  378. }
  379. //***************************************************************************
  380. //
  381. // CNt5Refresher::FindInst
  382. //
  383. // Based on a perf object identification, locates a WBEM instance of
  384. // that class within this refresher and returns the pointer to it.
  385. //
  386. // Note that the <dwPerfObjIx> maps directly to a WBEM Class entry.
  387. //
  388. // To save execution time, we don't AddRef() the return value and the
  389. // caller doesn't Release().
  390. //
  391. //***************************************************************************
  392. // ok
  393. BOOL CNt5Refresher::FindInst(
  394. IN DWORD dwPerfObjIx,
  395. IN LPWSTR pszInstName,
  396. OUT IWbemObjectAccess **pInst,
  397. OUT CClassMapInfo **pClsMap
  398. )
  399. {
  400. BOOL bReturn = FALSE;
  401. IWbemObjectAccess *pTmp;
  402. PRefresherCacheEl pCacheEl;
  403. int l = 0;
  404. int u = m_aCache.Size() - 1;
  405. int m;
  406. // Binary search the cache.
  407. // ========================
  408. while (l <= u) {
  409. m = (l + u) / 2;
  410. pCacheEl = PRefresherCacheEl(m_aCache[m]);
  411. if (dwPerfObjIx < pCacheEl->m_dwPerfObjIx) {
  412. u = m - 1;
  413. } else if (dwPerfObjIx > pCacheEl->m_dwPerfObjIx) {
  414. l = m + 1;
  415. } else {
  416. // We found the class. Now do we have the instance?
  417. // =================================================
  418. pTmp = pCacheEl->FindInst(pszInstName);
  419. if (pTmp == 0) {
  420. bReturn = FALSE; // Didn't have it.
  421. } else {
  422. *pInst = pTmp;
  423. *pClsMap = pCacheEl->m_pClassMap;
  424. bReturn = TRUE;
  425. }
  426. break;
  427. }
  428. }
  429. // Not found
  430. // =========
  431. return bReturn;
  432. }
  433. //***************************************************************************
  434. //
  435. // CNt5Refresher::GetObjectIds
  436. //
  437. // Gets a list of all the perf object Ids corresponding to the instances
  438. // in the refresher.
  439. //
  440. // Caller uses operator delete to deallocate the returned array.
  441. //
  442. //***************************************************************************
  443. // ok
  444. BOOL CNt5Refresher::GetObjectIds(
  445. DWORD *pdwNumIds,
  446. DWORD **pdwIdList
  447. )
  448. {
  449. DWORD *pdwIds;
  450. int nNumElements;
  451. BOOL bReturn;
  452. nNumElements = m_aCache.Size();
  453. pdwIds = new DWORD[nNumElements ];
  454. if (pdwIds != NULL) {
  455. for (int i = 0; i < nNumElements; i++) {
  456. pdwIds[i] = PRefresherCacheEl(m_aCache[i])->m_dwPerfObjIx;
  457. }
  458. *pdwIdList = pdwIds;
  459. *pdwNumIds = nNumElements;
  460. bReturn = TRUE;
  461. } else {
  462. // unable to create buffer
  463. bReturn = FALSE;
  464. }
  465. return bReturn;
  466. }
  467. //***************************************************************************
  468. //
  469. // CNt5Refresher::FindUnusedId
  470. //
  471. // Finds an ID not in use for new objects to be added to the refresher.
  472. //
  473. //***************************************************************************
  474. // ok
  475. LONG CNt5Refresher::FindUnusedId()
  476. {
  477. PRefresherCacheEl pEl;
  478. PCachedInst pInst;
  479. int nRetries = 0x100000; // A hundred thousand retries
  480. LONG lReturn = -1;
  481. int i;
  482. int i2;
  483. int nNumElements;
  484. int nNumInstances;
  485. // assume the object is locked for access
  486. Restart:
  487. while (nRetries--) {
  488. i = 0;
  489. nNumElements = m_aCache.Size();
  490. while(i < nNumElements) {
  491. pEl = PRefresherCacheEl(m_aCache[i]);
  492. // test enum Id first
  493. if (pEl->m_lEnumId == m_lProbableId) {
  494. m_lProbableId++;
  495. goto Restart;
  496. }
  497. i2 = 0;
  498. nNumInstances = pEl->m_aInstances.Size();
  499. while (i2 < nNumInstances) {
  500. pInst = (PCachedInst) pEl->m_aInstances[i2];
  501. if (pInst->m_lId == m_lProbableId) {
  502. m_lProbableId++;
  503. goto Restart;
  504. }
  505. i2++;
  506. }
  507. i++;
  508. }
  509. lReturn = m_lProbableId;
  510. break;
  511. }
  512. return lReturn;
  513. }
  514. //***************************************************************************
  515. //
  516. // RefresherCacheEl::RemoveInst
  517. //
  518. // Removes the requested instances from the cache element for a particular
  519. // class.
  520. //
  521. //***************************************************************************
  522. // ok
  523. BOOL RefresherCacheEl::RemoveInst(LONG lId)
  524. {
  525. BOOL bReturn = FALSE;
  526. int i;
  527. PCachedInst pInst;
  528. int nNumInstances;
  529. if (lId == m_lEnumId) {
  530. // then clean out the enumerator for this object
  531. nNumInstances = m_aEnumInstances.Size();
  532. if (nNumInstances> 0) {
  533. IWbemObjectAccess *pAccess;
  534. for (i = 0; i < nNumInstances ; i++) {
  535. pAccess = (IWbemObjectAccess *)(m_aEnumInstances.GetAt(i));
  536. if (pAccess != NULL) {
  537. pAccess->Release();
  538. }
  539. }
  540. m_aEnumInstances.Empty();
  541. }
  542. if (m_plIds != NULL) {
  543. delete (m_plIds);
  544. m_plIds = NULL;
  545. m_lEnumArraySize = 0;
  546. }
  547. if (m_pHiPerfEnum != NULL) {
  548. m_pHiPerfEnum->Release();
  549. m_pHiPerfEnum = NULL;
  550. }
  551. // Now, if this is a singleton (m_pSingleton != NULL),
  552. // then check if m_aInstances is empty. If so, then
  553. // no instances are referencing the singleton object
  554. // so we can free up its resources.
  555. if ( NULL != m_pSingleton && 0 == m_aInstances.Size() )
  556. {
  557. m_pSingleton->Release();
  558. m_pSingleton = NULL;
  559. }
  560. return TRUE;
  561. } else {
  562. // walk the instances to find a match
  563. nNumInstances = m_aInstances.Size();
  564. for (i = 0; i < nNumInstances; i++) {
  565. pInst = (PCachedInst) m_aInstances[i];
  566. if (lId == pInst->m_lId) {
  567. delete pInst;
  568. m_aInstances.RemoveAt(i);
  569. bReturn = TRUE;
  570. break;
  571. }
  572. }
  573. // Now, if we removed an instance, m_aInstances is empty
  574. // and this is a singleton (m_pSingleton != NULL), then
  575. // check if m_pHiPerfEnum is NULL, meaning no Enumerator
  576. // exists, so none of its instances will be referencing
  577. // the singleton object, so we can free up its resources.
  578. if ( NULL != m_pSingleton
  579. && bReturn
  580. && 0 == m_aInstances.Size()
  581. && NULL == m_pHiPerfEnum )
  582. {
  583. m_pSingleton->Release();
  584. m_pSingleton = NULL;
  585. }
  586. if ( bReturn )
  587. {
  588. }
  589. }
  590. return bReturn;
  591. }
  592. //***************************************************************************
  593. //
  594. // CNt5Refresher::AddEnum
  595. //
  596. // Creates an enumerator for the specified class
  597. // to it.
  598. //
  599. //***************************************************************************
  600. // ?
  601. BOOL CNt5Refresher::AddEnum (
  602. IN IWbemHiPerfEnum *pEnum, // enum interface pointer
  603. IN CClassMapInfo *pClsMap, // Class of object
  604. OUT LONG *plId // id for new enum
  605. )
  606. {
  607. BOOL bRes = FALSE;
  608. LONG lStatus;
  609. LONG lNewId;
  610. PRefresherCacheEl pWorkEl;
  611. int iReturn;
  612. // Make sure we get access to the mutex before we continue. If we can't
  613. // get to it, something's wrong, so we'll just assume we are busy.
  614. if ( WaitForSingleObject( m_hAccessMutex, REFRESHER_MUTEX_WAIT_TIMEOUT ) == WAIT_OBJECT_0 )
  615. {
  616. // This will auto-release the mutex in case something bad happens
  617. CMutexReleaseMe mrm( m_hAccessMutex );
  618. lNewId = FindUnusedId();
  619. if (lNewId != -1) {
  620. // First, find the cache element corresponding to this object.
  621. // ===========================================================
  622. pWorkEl = GetCacheEl(pClsMap);
  623. // If <pWorkEl> is NULL, we didn't have anything in the cache
  624. // and have to add a new one.
  625. // ==========================================================
  626. if (pWorkEl == NULL) {
  627. bRes = AddNewCacheEl(pClsMap, &pWorkEl);
  628. }
  629. if (pWorkEl != NULL) {
  630. if (pWorkEl->m_pHiPerfEnum == NULL) {
  631. // then we can init it as it hasn't been opened
  632. pEnum->AddRef();
  633. pWorkEl->m_pHiPerfEnum = pEnum;
  634. pWorkEl->m_lEnumId = lNewId;
  635. assert (pWorkEl->m_aEnumInstances.Size() == 0L);
  636. bRes = TRUE;
  637. if (pClsMap->IsSingleton()) {
  638. LONG lNumObjInstances;
  639. // then create the singleton IWbemObjectAccess entry here
  640. lNumObjInstances = 1;
  641. // If we do NOT have a singleton pointer, make it so.
  642. if ( NULL == pWorkEl->m_pSingleton )
  643. {
  644. // add the new IWbemObjectAccess pointers
  645. IWbemClassObject *pClsObj;
  646. pWorkEl->m_pClassMap->m_pClassDef->SpawnInstance(0, &pClsObj);
  647. pClsObj->QueryInterface(IID_IWbemObjectAccess, (LPVOID *) &pWorkEl->m_pSingleton);
  648. pClsObj->Release(); // We only need the IWbemObjectAccess pointer
  649. // We don't really care about the singleton id anymore
  650. // pWorkEl->m_lSingletonId = pWorkEl->m_plIds[0];
  651. }
  652. if (pWorkEl->m_aEnumInstances.Size() < lNumObjInstances) {
  653. // alloc and init the ID array
  654. if (pWorkEl->m_plIds != NULL) {
  655. delete (pWorkEl->m_plIds);
  656. }
  657. pWorkEl->m_lEnumArraySize = lNumObjInstances;
  658. pWorkEl->m_plIds = new LONG[lNumObjInstances];
  659. if (pWorkEl->m_plIds != NULL) {
  660. pWorkEl->m_plIds[0] = 0;
  661. // AddRef the singleton class and place it in the enuminstances array
  662. pWorkEl->m_pSingleton->AddRef();
  663. iReturn = pWorkEl->m_aEnumInstances.Add (pWorkEl->m_pSingleton);
  664. if (iReturn == CFlexArray::no_error) {
  665. // Add the singleton object to the enumerator. Then, all we have to
  666. // do is update this object and we will, by default update the
  667. // enumerator, since the number of objects in it will always
  668. // be one.
  669. pWorkEl->m_pHiPerfEnum->AddObjects(
  670. 0,
  671. 1,
  672. pWorkEl->m_plIds,
  673. (IWbemObjectAccess __RPC_FAR *__RPC_FAR *)pWorkEl->m_aEnumInstances.GetArrayPtr());
  674. }
  675. else {
  676. SetLastError((ULONG) WBEM_E_OUT_OF_MEMORY);
  677. bRes = FALSE;
  678. }
  679. } else {
  680. SetLastError ((ULONG)WBEM_E_OUT_OF_MEMORY);
  681. bRes = FALSE;
  682. }
  683. }
  684. assert (pWorkEl->m_aEnumInstances.Size() >= lNumObjInstances);
  685. }
  686. // load provider library since all went OK so far
  687. lStatus = m_PerfObj.AddClass (pClsMap->m_pClassDef, FALSE);
  688. if (lStatus == ERROR_SUCCESS) {
  689. // return new ID & successful status
  690. *plId = lNewId;
  691. bRes = TRUE;
  692. } else {
  693. // set error: Class or library failed to load
  694. SetLastError ((ULONG)WBEM_E_PROVIDER_FAILURE);
  695. bRes = FALSE;
  696. }
  697. } else {
  698. // this class already has an enumerator
  699. // what to do here?
  700. // for now we'll return the id of the existing one
  701. SetLastError ((ULONG)WBEM_E_ILLEGAL_OPERATION);
  702. bRes = FALSE;
  703. }
  704. }
  705. }
  706. } // IF WaitForSingleObject
  707. else
  708. {
  709. bRes = FALSE;
  710. // We're locked out of the mutex
  711. SetLastError ((ULONG)WBEM_E_REFRESHER_BUSY);
  712. }
  713. return bRes;
  714. }
  715. //***************************************************************************
  716. //
  717. // CNt5Refresher::AddObject
  718. //
  719. // Adds the requested object to the refresher and assigns an ID
  720. // to it.
  721. //
  722. //***************************************************************************
  723. // ?
  724. BOOL CNt5Refresher::AddObject(
  725. IN IWbemObjectAccess **ppObj, // Object to add
  726. IN CClassMapInfo *pClsMap, // Class of object
  727. OUT LONG *plId // The id of the object added
  728. )
  729. {
  730. BOOL bRes = FALSE;
  731. LONG lStatus;
  732. LONG lNewId;
  733. PRefresherCacheEl pWorkEl;
  734. // Make sure we get access to the mutex before we continue. If we can't
  735. // get to it, something's wrong, so we'll just assume we are busy.
  736. if ( WaitForSingleObject( m_hAccessMutex, REFRESHER_MUTEX_WAIT_TIMEOUT ) == WAIT_OBJECT_0 )
  737. {
  738. // This will auto-release the mutex in case something bad happens
  739. CMutexReleaseMe mrm( m_hAccessMutex );
  740. lNewId = FindUnusedId();
  741. if (lNewId != -1) {
  742. // First, find the cache element corresponding to this object.
  743. // ===========================================================
  744. pWorkEl = GetCacheEl(pClsMap);
  745. // If <pWorkEl> is NULL, we didn't have anything in the cache
  746. // and have to add a new one.
  747. // ==========================================================
  748. if (pWorkEl == NULL) {
  749. bRes = AddNewCacheEl(pClsMap, &pWorkEl);
  750. }
  751. if (pWorkEl != NULL) {
  752. // If here, we have successfully added a new cache element.
  753. // ========================================================
  754. bRes = pWorkEl->InsertInst(ppObj, lNewId);
  755. if (bRes) {
  756. // load provider library since all went OK so far
  757. lStatus = m_PerfObj.AddClass (pClsMap->m_pClassDef, FALSE);
  758. if (lStatus == ERROR_SUCCESS) {
  759. // return new ID & successful status
  760. *plId = lNewId;
  761. bRes = TRUE;
  762. } else {
  763. // set error: Class or library failed to load
  764. SetLastError ((ULONG)WBEM_E_PROVIDER_FAILURE);
  765. bRes = FALSE;
  766. }
  767. }
  768. }
  769. }
  770. } // IF acquired mutex
  771. else
  772. {
  773. bRes = FALSE;
  774. // Return a busy error
  775. SetLastError ((ULONG)WBEM_E_REFRESHER_BUSY);
  776. }
  777. return bRes;
  778. }
  779. //***************************************************************************
  780. //
  781. // CNt5Refresher::AddNewCacheEl
  782. //
  783. // Adds a new cache element in the proper position so that a binary
  784. // search on perf object id can occur later.
  785. //
  786. //***************************************************************************
  787. // ok
  788. BOOL CNt5Refresher::AddNewCacheEl(
  789. IN CClassMapInfo *pClsMap,
  790. PRefresherCacheEl *pOutput
  791. )
  792. {
  793. // assumes the object is locked for access
  794. PRefresherCacheEl pWorkEl;
  795. PRefresherCacheEl pNew = 0;
  796. int i;
  797. int nNumElements;
  798. BOOL bReturn = FALSE;
  799. * pOutput = NULL;
  800. pNew = new RefresherCacheEl;
  801. if (pNew != NULL) {
  802. pNew->m_dwPerfObjIx = pClsMap->GetObjectId();
  803. pNew->m_pClassMap = pClsMap->CreateDuplicate();
  804. if (pNew->m_pClassMap != NULL) {
  805. nNumElements = m_aCache.Size();
  806. for (i = 0; i < nNumElements; i++) {
  807. // walk through the list of cache elements
  808. // and find the first entry that has a
  809. // larger index then the one we are adding
  810. pWorkEl = PRefresherCacheEl(m_aCache[i]);
  811. if (pNew->m_dwPerfObjIx < pWorkEl->m_dwPerfObjIx) {
  812. m_aCache.InsertAt(i, pNew);
  813. *pOutput = pNew;
  814. bReturn = TRUE;
  815. break;
  816. }
  817. }
  818. if (i == nNumElements) {
  819. // this entry is larger than anyone in the list
  820. // so Add it to the end.
  821. // =====-===============
  822. m_aCache.Add(pNew);
  823. *pOutput = pNew;
  824. bReturn = TRUE;
  825. }
  826. }
  827. else {
  828. // cannot duplicate ClassMap,
  829. // delte allocated object and return false
  830. delete pNew;
  831. }
  832. } else {
  833. // return false
  834. }
  835. return bReturn;
  836. }
  837. //***************************************************************************
  838. //
  839. // CNt5Refresher::GetCacheEl
  840. //
  841. //***************************************************************************
  842. // ok
  843. PRefresherCacheEl CNt5Refresher::GetCacheEl(
  844. CClassMapInfo *pClsMap
  845. )
  846. {
  847. // assumes the structure is locked for access
  848. PRefresherCacheEl pReturn = NULL;
  849. PRefresherCacheEl pWorkEl;
  850. int i;
  851. int nNumElements;
  852. DWORD dwObjectIdToFind;
  853. if (pClsMap != NULL) {
  854. dwObjectIdToFind = pClsMap->GetObjectId();
  855. nNumElements = m_aCache.Size();
  856. for (i = 0; i < nNumElements; i++) {
  857. pWorkEl = PRefresherCacheEl(m_aCache[i]);
  858. if (pWorkEl->m_pClassMap->GetObjectId() == dwObjectIdToFind) {
  859. pReturn = pWorkEl;
  860. break;
  861. }
  862. }
  863. }
  864. return pReturn;
  865. }
  866. //***************************************************************************
  867. //
  868. // RefresherCacheEl::FindInstance
  869. //
  870. // Finds an instance in the current cache element for a particular instance.
  871. // For this to work, the instances have to be sorted by name.
  872. //
  873. //***************************************************************************
  874. // ok
  875. IWbemObjectAccess *RefresherCacheEl::FindInst(
  876. LPWSTR pszInstName
  877. )
  878. {
  879. // Binary search the cache.
  880. // ========================
  881. int l = 0;
  882. int u = m_aInstances.Size() - 1;
  883. int m;
  884. CachedInst *pInst;
  885. while (l <= u) {
  886. m = (l + u) / 2;
  887. pInst = PCachedInst(m_aInstances[m]);
  888. if (_wcsicmp(pszInstName, pInst->m_pName) < 0) {
  889. u = m - 1;
  890. } else if (_wcsicmp(pszInstName, pInst->m_pName) > 0) {
  891. l = m + 1;
  892. } else {
  893. // We found the instance.
  894. // ======================
  895. return pInst->m_pInst;
  896. }
  897. }
  898. // Not found
  899. // =========
  900. return NULL;
  901. }
  902. //***************************************************************************
  903. //
  904. // Inserts a new instance.
  905. //
  906. //***************************************************************************
  907. //
  908. BOOL RefresherCacheEl::InsertInst(IWbemObjectAccess **ppNew, LONG lNewId)
  909. {
  910. // Save the value passed in
  911. IWbemObjectAccess* pNew = *ppNew;
  912. IWbemClassObject *pObj;
  913. VARIANT v;
  914. PCachedInst pNewInst;
  915. DWORD dwInstanceNameLength;
  916. PCachedInst pTest;
  917. BOOL bReturn = FALSE;
  918. HRESULT hRes;
  919. int nNumInstances;
  920. // Check for singleton.
  921. // ====================
  922. if (m_pClassMap->IsSingleton()) {
  923. // If we don't already have an object, use the one passed in. Otherwise
  924. // we will replace it.
  925. if ( NULL == m_pSingleton )
  926. {
  927. m_pSingleton = pNew;
  928. m_pSingleton->AddRef();
  929. // We don't really need the id anymore
  930. // m_lSingletonId = lNewId;
  931. }
  932. else
  933. {
  934. // Now we're sneaking around by replacing *ppNew with the
  935. // singleton we already have. We must release *ppNew in
  936. // order to get away with this.
  937. (*ppNew)->Release();
  938. // We need to AddRef() this because *ppNew is now referencing it
  939. m_pSingleton->AddRef();
  940. *ppNew = m_pSingleton;
  941. pNew = m_pSingleton;
  942. }
  943. // Now we will Add this instance just like any other
  944. pNewInst = new CachedInst;
  945. // assert (pNewInst != NULL);
  946. if ( pNewInst != NULL )
  947. {
  948. // For singletons, none of the other pointers
  949. // should matter.
  950. pNewInst->m_lId = lNewId;
  951. pNewInst->m_pInst = pNew;
  952. pNewInst->m_pInst->AddRef();
  953. // We are saving the name just to be safe (It will
  954. // really only be an "@", and I don't believe it
  955. // will be accessed anywhere else. I hope...)
  956. pNewInst->m_pName = Macro_CloneLPWSTR(L"@");
  957. // assert (pNewInst->m_pName != NULL);
  958. if ( NULL != pNewInst->m_pName )
  959. {
  960. // We can just add this in, since any entries will all be the
  961. // same anyway.
  962. m_aInstances.Add(pNewInst);
  963. bReturn = TRUE;
  964. }
  965. else // Memory Allocation failed
  966. {
  967. bReturn = FALSE;
  968. SetLastError ((DWORD)WBEM_E_OUT_OF_MEMORY);
  969. delete(pNewInst);
  970. }
  971. }
  972. else // Memory allocation failed
  973. {
  974. bReturn = FALSE;
  975. SetLastError ((DWORD)WBEM_E_OUT_OF_MEMORY);
  976. }
  977. } else {
  978. VariantInit(&v);
  979. // For multi-instance, get the instance name.
  980. // ==========================================
  981. hRes = pNew->QueryInterface(IID_IWbemClassObject, (LPVOID *) &pObj);
  982. assert (hRes == NO_ERROR);
  983. if (hRes == NO_ERROR) {
  984. hRes = pObj->Get(CBSTR(cszName), 0, &v, 0, 0);
  985. assert (hRes == NO_ERROR);
  986. if (hRes == NO_ERROR) {
  987. if (v.vt == VT_BSTR) {
  988. bReturn = TRUE;
  989. } else {
  990. bReturn = FALSE;
  991. // the object passed in should have an instance name
  992. SetLastError ((DWORD)WBEM_E_INVALID_OBJECT_PATH);
  993. }
  994. }
  995. pObj->Release();
  996. if (bReturn) {
  997. // Construct the new instance.
  998. // ===========================
  999. pNewInst = new CachedInst;
  1000. // assert (pNewInst != NULL);
  1001. if (pNewInst != NULL) {
  1002. pNewInst->m_lId = lNewId;
  1003. pNewInst->m_pInst = pNew;
  1004. pNewInst->m_pInst->AddRef();
  1005. pNewInst->m_pName = Macro_CloneLPWSTR(V_BSTR(&v));
  1006. // assert (pNewInst->m_pName != NULL);
  1007. if (pNewInst->m_pName != NULL) {
  1008. dwInstanceNameLength = lstrlenW (pNewInst->m_pName) + 1;
  1009. // parse the instance string now to save processing time later
  1010. pNewInst->m_szParentName = new WCHAR[dwInstanceNameLength];
  1011. // assert (pNewInst->m_szParentName != NULL);
  1012. pNewInst->m_szInstanceName = new WCHAR[dwInstanceNameLength];
  1013. // assert (pNewInst->m_szInstanceName != NULL);
  1014. if ((pNewInst->m_szParentName != NULL) &&
  1015. (pNewInst->m_szInstanceName != NULL)) {
  1016. // break the instance name into components
  1017. bReturn = PerfHelper::ParseInstanceName (pNewInst->m_pName,
  1018. pNewInst->m_szInstanceName,
  1019. pNewInst->m_szParentName ,
  1020. &pNewInst->m_dwIndex);
  1021. if (bReturn) {
  1022. bReturn = FALSE; // to prime it.
  1023. // Now place the name in the instance cache element.
  1024. // =================================================
  1025. nNumInstances = m_aInstances.Size();
  1026. for (int i = 0; i < nNumInstances; i++) {
  1027. // see if it belongs in the list
  1028. pTest = PCachedInst(m_aInstances[i]);
  1029. if (_wcsicmp(V_BSTR(&v), pTest->m_pName) < 0) {
  1030. m_aInstances.InsertAt(i, pNewInst);
  1031. bReturn = TRUE;
  1032. // once it's been added,
  1033. // there's no point in continuing
  1034. break;
  1035. }
  1036. }
  1037. if (!bReturn) {
  1038. // this goes at the end of the list
  1039. m_aInstances.Add(pNewInst);
  1040. bReturn = TRUE;
  1041. } else {
  1042. // unable to create instance
  1043. SetLastError ((DWORD)WBEM_E_INVALID_OBJECT_PATH);
  1044. }
  1045. }
  1046. }
  1047. // clean up if there's an error
  1048. if (!bReturn) {
  1049. if (pNewInst->m_szParentName != NULL) {
  1050. delete (pNewInst->m_szParentName);
  1051. }
  1052. if (pNewInst->m_szInstanceName != NULL) {
  1053. delete pNewInst->m_szInstanceName;
  1054. }
  1055. delete (pNewInst->m_pName);
  1056. bReturn = FALSE;
  1057. delete (pNewInst);
  1058. }
  1059. } else {
  1060. // unable to alloc memory
  1061. bReturn = FALSE;
  1062. SetLastError ((DWORD)WBEM_E_OUT_OF_MEMORY);
  1063. delete (pNewInst);
  1064. }
  1065. } else {
  1066. // unable to alloc memory
  1067. bReturn = FALSE;
  1068. SetLastError ((DWORD)WBEM_E_OUT_OF_MEMORY);
  1069. }
  1070. } else {
  1071. // return FALSE
  1072. }
  1073. } else {
  1074. // return FALSE
  1075. }
  1076. VariantClear(&v);
  1077. }
  1078. return bReturn;
  1079. }