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.

1698 lines
49 KiB

  1. /*++
  2. Copyright (C) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. PROVPERF.CPP
  5. Abstract:
  6. Defines the acutal "Put" and "Get" functions for the
  7. performance counter provider. The format of the mapping
  8. string is;
  9. machine|Object|counter[|instance]
  10. Examples;
  11. local|memory|available bytes
  12. a-davj2|LogicalDisk|Free Megabytes|C:
  13. History:
  14. a-davj 9-27-95 Created.
  15. --*/
  16. #include "precomp.h"
  17. #include "provperf.h"
  18. #include "cvariant.h"
  19. // maximum amount of time to wait for exclusive access
  20. #define MAX_EXEC_WAIT 5000
  21. //***************************************************************************
  22. //
  23. // AddTesterDetails
  24. //
  25. // DESCRIPTION:
  26. //
  27. // This function is used add the counter type to the property and is useful
  28. // to wbem testers. Normal users dont want the overhead caused by this.
  29. //
  30. // PARAMETERS:
  31. //
  32. // pClassInt Object being refreshed
  33. // PropName Property Name
  34. // dwCtrType counter type
  35. //
  36. // RETURN VALUE:
  37. //
  38. // always 0
  39. //
  40. //***************************************************************************
  41. void AddTesterDetails(IWbemClassObject FAR * pClassInt,BSTR PropName,DWORD dwCtrType)
  42. {
  43. // Get the qualifier pointer for the property
  44. IWbemQualifierSet * pQualifier = NULL;
  45. // Get an Qualifier set interface.
  46. SCODE sc = pClassInt->GetPropertyQualifierSet(PropName,&pQualifier); // Get prop attribute
  47. if(FAILED(sc))
  48. return;
  49. WCHAR wcName[40];
  50. switch(dwCtrType)
  51. {
  52. case PERF_COUNTER_COUNTER:
  53. wcsncpy(wcName,L"PERF_COUNTER_COUNTER", 39);
  54. break;
  55. case PERF_COUNTER_TIMER:
  56. wcsncpy(wcName,L"PERF_COUNTER_TIMER", 39);
  57. break;
  58. case PERF_COUNTER_QUEUELEN_TYPE:
  59. wcsncpy(wcName,L"PERF_COUNTER_QUEUELEN_TYPE", 39);
  60. break;
  61. case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
  62. wcsncpy(wcName,L"PERF_COUNTER_LARGE_QUEUELEN_TYPE", 39);
  63. break;
  64. case PERF_COUNTER_BULK_COUNT:
  65. wcsncpy(wcName,L"PERF_COUNTER_BULK_COUNT", 39);
  66. break;
  67. case PERF_COUNTER_TEXT:
  68. wcsncpy(wcName,L"PERF_COUNTER_TEXT", 39);
  69. break;
  70. case PERF_COUNTER_RAWCOUNT:
  71. wcsncpy(wcName,L"PERF_COUNTER_RAWCOUNT", 39);
  72. break;
  73. case PERF_COUNTER_LARGE_RAWCOUNT:
  74. wcsncpy(wcName,L"PERF_COUNTER_LARGE_RAWCOUNT", 39);
  75. break;
  76. case PERF_COUNTER_RAWCOUNT_HEX:
  77. wcsncpy(wcName,L"PERF_COUNTER_RAWCOUNT_HEX", 39);
  78. break;
  79. case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
  80. wcsncpy(wcName,L"PERF_COUNTER_LARGE_RAWCOUNT_HEX", 39);
  81. break;
  82. case PERF_SAMPLE_FRACTION:
  83. wcsncpy(wcName,L"PERF_SAMPLE_FRACTION", 39);
  84. break;
  85. case PERF_SAMPLE_COUNTER:
  86. wcsncpy(wcName,L"PERF_SAMPLE_COUNTER", 39);
  87. break;
  88. case PERF_COUNTER_NODATA:
  89. wcsncpy(wcName,L"PERF_COUNTER_NODATA", 39);
  90. break;
  91. case PERF_COUNTER_TIMER_INV:
  92. wcsncpy(wcName,L"PERF_COUNTER_TIMER_INV", 39);
  93. break;
  94. case PERF_SAMPLE_BASE:
  95. wcsncpy(wcName,L"PERF_SAMPLE_BASE", 39);
  96. break;
  97. case PERF_AVERAGE_TIMER:
  98. wcsncpy(wcName,L"PERF_AVERAGE_TIMER", 39);
  99. break;
  100. case PERF_AVERAGE_BASE:
  101. wcsncpy(wcName,L"PERF_AVERAGE_BASE", 39);
  102. break;
  103. case PERF_AVERAGE_BULK:
  104. wcsncpy(wcName,L"PERF_AVERAGE_BULK", 39);
  105. break;
  106. case PERF_100NSEC_TIMER:
  107. wcsncpy(wcName,L"PERF_100NSEC_TIMER", 39);
  108. break;
  109. case PERF_100NSEC_TIMER_INV:
  110. wcsncpy(wcName,L"PERF_100NSEC_TIMER_INV", 39);
  111. break;
  112. case PERF_COUNTER_MULTI_TIMER:
  113. wcsncpy(wcName,L"PERF_COUNTER_MULTI_TIMER", 39);
  114. break;
  115. case PERF_COUNTER_MULTI_TIMER_INV:
  116. wcsncpy(wcName,L"PERF_COUNTER_MULTI_TIMER_INV", 39);
  117. break;
  118. case PERF_COUNTER_MULTI_BASE:
  119. wcsncpy(wcName,L"PERF_COUNTER_MULTI_BASE", 39);
  120. break;
  121. case PERF_100NSEC_MULTI_TIMER:
  122. wcsncpy(wcName,L"PERF_100NSEC_MULTI_TIMER", 39);
  123. break;
  124. case PERF_100NSEC_MULTI_TIMER_INV:
  125. wcsncpy(wcName,L"PERF_100NSEC_MULTI_TIMER_INV", 39);
  126. break;
  127. case PERF_RAW_FRACTION:
  128. wcsncpy(wcName,L"PERF_RAW_FRACTION", 39);
  129. break;
  130. case PERF_RAW_BASE:
  131. wcsncpy(wcName,L"PERF_RAW_BASE", 39);
  132. break;
  133. case PERF_ELAPSED_TIME:
  134. wcsncpy(wcName,L"PERF_ELAPSED_TIME", 39);
  135. break;
  136. case PERF_COUNTER_HISTOGRAM_TYPE:
  137. wcsncpy(wcName,L"PERF_COUNTER_HISTOGRAM_TYPE", 39);
  138. break;
  139. case PERF_COUNTER_DELTA:
  140. wcsncpy(wcName,L"PERF_COUNTER_DELTA", 39);
  141. break;
  142. case PERF_COUNTER_LARGE_DELTA:
  143. wcsncpy(wcName,L"PERF_COUNTER_LARGE_DELTA", 39);
  144. break;
  145. default:
  146. StringCchPrintfW(wcName, sizeof(wcName)/sizeof(WCHAR), L"0x%x", dwCtrType);
  147. }
  148. wcName[39] = 0;
  149. CVariant var(wcName);
  150. BSTR bstr = SysAllocString(L"CounterType");
  151. if(bstr)
  152. {
  153. sc = pQualifier->Put(bstr, var.GetVarPtr(), 0);
  154. SysFreeString(bstr);
  155. }
  156. pQualifier->Release();
  157. }
  158. //***************************************************************************
  159. //
  160. // CImpPerf::CImpPerf
  161. //
  162. // DESCRIPTION:
  163. //
  164. // Constuctor.
  165. //
  166. // PARAMETERS:
  167. //
  168. //***************************************************************************
  169. CImpPerf::CImpPerf()
  170. {
  171. StringCchCopyW(wcCLSID, sizeof(wcCLSID)/sizeof(WCHAR), L"{F00B4404-F8F1-11CE-A5B6-00AA00680C3F}");
  172. sMachine = TEXT("local");
  173. hKeyMachine = HKEY_LOCAL_MACHINE;
  174. dwLastTimeUsed = 0;
  175. hKeyPerf = HKEY_PERFORMANCE_DATA;
  176. m_TitleBuffer = NULL;
  177. m_Size = 0;
  178. m_pCounter = NULL;
  179. hExec = CreateMutex(NULL, false, NULL);
  180. m_hTermEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
  181. return;
  182. }
  183. //***************************************************************************
  184. //
  185. // CImpPerf::~CImpPerf
  186. //
  187. // DESCRIPTION:
  188. //
  189. // Destructor.
  190. //
  191. //***************************************************************************
  192. CImpPerf::~CImpPerf()
  193. {
  194. bool bGotMutex = false;
  195. if(hExec)
  196. {
  197. DWORD dwRet = WaitForSingleObject(hExec,2*MAX_EXEC_WAIT);
  198. if(dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED)
  199. bGotMutex = true;
  200. }
  201. if(bGotMutex)
  202. ReleaseMutex(hExec);
  203. FreeStuff();
  204. sMachine.Empty();
  205. if(hExec)
  206. CloseHandle(hExec);
  207. if(m_hTermEvent)
  208. CloseHandle(m_hTermEvent);
  209. }
  210. //***************************************************************************
  211. //
  212. // SCODE CImpPerf::LoadData
  213. //
  214. // DESCRIPTION:
  215. //
  216. // Loads up the perf monitor data.
  217. //
  218. // PARAMETERS:
  219. //
  220. // ProvObj Object containing the property context string.
  221. // pls Where to put the data
  222. // piObject Identifies the perf mon object
  223. // piCounter Identifies the perf mon counter
  224. // **ppNew Created data block
  225. // bJustGettingInstances Flag which indicates that we are actully
  226. // looking for the instance names.
  227. //
  228. // RETURN VALUE:
  229. //
  230. // WBEM_E_INVALID_PARAMETER Bad context string
  231. // WBEM_E_OUT_OF_MEMORY low memory
  232. // otherwise error from called function
  233. //
  234. //***************************************************************************
  235. SCODE CImpPerf::LoadData(
  236. CProvObj & ProvObj,
  237. LINESTRUCT * pls,
  238. int * piObject,
  239. int * piCounter,
  240. PERF_DATA_BLOCK **ppNew,
  241. BOOL bJustGettingInstances)
  242. {
  243. SCODE sc;
  244. BOOL bChange;
  245. if( ( ProvObj.sGetToken(0) == NULL ) || ( piObject == NULL ) || ( piCounter == NULL ) )
  246. return WBEM_E_INVALID_PARAMETER; //BAD MAPPING STRING
  247. // Determine if there has been a change in the machine being
  248. // accessed. Save the current machine and get the handles if
  249. // there was a change.
  250. bChange = lstrcmpi(sMachine,ProvObj.sGetToken(0));
  251. sMachine = ProvObj.sGetToken(0);
  252. if(bChange)
  253. {
  254. sc = dwGetRegHandles(ProvObj.sGetToken(0));
  255. if(sc != S_OK)
  256. return sc;
  257. }
  258. // build up a table of the performance strings and
  259. // their corresponding indexes. This only needs to be done
  260. // when the buffer is empty or when the machine changes.
  261. if(bChange || (m_TitleBuffer == NULL && m_pCounter == NULL))
  262. {
  263. sc = GetPerfTitleSz ();
  264. if(sc != S_OK)
  265. return sc;
  266. }
  267. // get the indexs for the object and counter names
  268. dwLastTimeUsed = GetCurrentTime();
  269. *piObject = iGetTitleIndex(ProvObj.sGetToken(1), FALSE);
  270. if(bJustGettingInstances)
  271. *piCounter = 0;
  272. else
  273. *piCounter = iGetTitleIndex(ProvObj.sGetToken(2), TRUE);
  274. if(*piObject == -1 || *piCounter == -1)
  275. {
  276. return WBEM_E_INVALID_PARAMETER; // bad mapping string
  277. }
  278. // Using the index for the object, get the perf counter data
  279. // data.
  280. sc = Cache.dwGetNew(ProvObj.sGetToken(0),*piObject,(LPSTR *)ppNew,pls);
  281. return sc;
  282. }
  283. //***************************************************************************
  284. //
  285. // SCODE CImpPerf::RefreshProperty
  286. //
  287. // DESCRIPTION:
  288. //
  289. // Gets the value of a single property from the NT performance
  290. // counter data.
  291. //
  292. // PARAMETERS:
  293. //
  294. // lFlags flags. Not currently used
  295. // pClassInt Instance object
  296. // PropName Property name
  297. // ProvObj Object containing the property context string.
  298. // pPackage Caching object
  299. // pVar Points to value to set
  300. // bTesterDetails Provide extra info for testers
  301. // RETURN VALUE:
  302. //
  303. // S_OK all is well
  304. // else probably set by LoadData or FindData.
  305. //
  306. //***************************************************************************
  307. SCODE CImpPerf::RefreshProperty(
  308. IN long lFlags,
  309. IN IWbemClassObject FAR * pClassInt,
  310. IN BSTR PropName,
  311. IN CProvObj & ProvObj,
  312. OUT IN CObject * pPackage,
  313. OUT CVariant * pVar, BOOL bTesterDetails)
  314. {
  315. DWORD dwCtrType;
  316. float fRet;
  317. SCODE sc;
  318. int iObject,iCounter;
  319. PERF_DATA_BLOCK * pNew, * pOld;
  320. DWORD dwSize;
  321. LINESTRUCT ls;
  322. void * pCountData, *pIgnore;
  323. CVariant vPerf;
  324. // The perf counter provider keeps some rather expensive data and
  325. // so it doesnt support complete reentrancy.
  326. if(hExec)
  327. {
  328. DWORD dwRet;
  329. dwRet = WaitForSingleObject(hExec,MAX_EXEC_WAIT);
  330. if(dwRet != WAIT_ABANDONED && dwRet != WAIT_OBJECT_0)
  331. return WBEM_E_FAILED;
  332. }
  333. else
  334. return WBEM_E_FAILED;
  335. // Load up the data
  336. sc = LoadData(ProvObj,&ls,&iObject,&iCounter,&pNew,FALSE);
  337. if(sc != S_OK)
  338. goto Done;
  339. // Find the desired data.
  340. sc = FindData(pNew,iObject,iCounter,ProvObj,&dwSize,&pCountData,
  341. &ls,TRUE,NULL); // find data sets the error in pMo!
  342. if(sc != S_OK)
  343. goto Done;
  344. // determine what type of counter it is
  345. dwCtrType = ls.lnCounterType & 0xc00;
  346. if(dwCtrType == PERF_TYPE_COUNTER)
  347. {
  348. // This type of counter requires time average data. Get the cache to
  349. // get two buffers which are separated by a minimum amount of time
  350. sc = Cache.dwGetPair(ProvObj.sGetToken(0),iObject,
  351. (LPSTR *)&pOld,(LPSTR *)&pNew,&ls);
  352. if(sc != S_OK)
  353. goto Done;
  354. sc = FindData(pNew,iObject,iCounter,ProvObj,&dwSize,&pCountData,&ls,TRUE,NULL);
  355. if(sc != S_OK)
  356. goto Done;
  357. sc = FindData(pOld,iObject,iCounter,ProvObj,&dwSize,&pIgnore,&ls,FALSE,NULL);
  358. if(sc != S_OK)
  359. goto Done;
  360. fRet = CounterEntry(&ls);
  361. vPerf.SetData(&fRet,VT_R4);
  362. }
  363. else if(dwCtrType == PERF_TYPE_NUMBER)
  364. {
  365. // Simple counter.
  366. fRet = CounterEntry(&ls);
  367. vPerf.SetData(&fRet,VT_R4);
  368. }
  369. else if(dwCtrType == PERF_TYPE_TEXT)
  370. {
  371. // Text. Allocate enough space to hold the text and
  372. // copy the text into temp WCHAR buffer since it is not
  373. // clear from the documentation if the data in the block
  374. // is null terminated.
  375. WCHAR * pNew = (WCHAR *)CoTaskMemAlloc(dwSize+2);
  376. if(pNew == NULL)
  377. {
  378. sc = WBEM_E_OUT_OF_MEMORY;
  379. goto Done;
  380. }
  381. memset(pNew,0,dwSize+2);
  382. if(ls.lnCounterType & 0x10000)
  383. mbstowcs(pNew,(char *)pCountData,dwSize);
  384. else
  385. memcpy(pNew,pCountData,dwSize);
  386. VARIANT * pVar = vPerf.GetVarPtr();
  387. VariantClear(pVar);
  388. pVar->vt = VT_BSTR;
  389. pVar->bstrVal = SysAllocString(pNew);
  390. if(pVar->bstrVal == NULL)
  391. sc = WBEM_E_OUT_OF_MEMORY;
  392. CoTaskMemFree(pNew);
  393. if(sc != S_OK)
  394. {
  395. goto Done;
  396. }
  397. }
  398. // Convert the data into the desired form
  399. sc = vPerf.DoPut(lFlags,pClassInt,PropName,pVar);
  400. if(bTesterDetails)
  401. AddTesterDetails(pClassInt, PropName, dwCtrType);
  402. Done:
  403. if(hExec)
  404. ReleaseMutex(hExec);
  405. return sc;
  406. }
  407. //***************************************************************************
  408. //
  409. // SCODE CImpPerf::UpdateProperty
  410. //
  411. // DESCRIPTION:
  412. //
  413. // Normally this routine is used to save properties, but NT
  414. // performance counter data is Read only.
  415. //
  416. // PARAMETERS:
  417. //
  418. // lFlags N/A
  419. // pClassInt N/A
  420. // PropName N/A
  421. // ProvObj N/A
  422. // pPackage N/A
  423. // pVar N/A
  424. //
  425. // RETURN VALUE:
  426. //
  427. // E_NOTIMPL
  428. //
  429. //***************************************************************************
  430. SCODE CImpPerf::UpdateProperty(
  431. long lFlags,
  432. IWbemClassObject FAR * pClassInt,
  433. BSTR PropName,
  434. CProvObj & ProvObj,
  435. CObject * pPackage,
  436. CVariant * pVar)
  437. {
  438. return E_NOTIMPL;
  439. }
  440. //***************************************************************************
  441. //
  442. // void CImpPerf::FreeStuff
  443. //
  444. // DESCRIPTION:
  445. //
  446. // Used to free up memory that is no longer needed as well as
  447. // freeing up registry handles.
  448. //
  449. //***************************************************************************
  450. void CImpPerf::FreeStuff(void)
  451. {
  452. if(hKeyMachine != HKEY_LOCAL_MACHINE)
  453. {
  454. RegCloseKey(hKeyMachine);
  455. hKeyMachine = NULL;
  456. }
  457. if(hKeyPerf != HKEY_PERFORMANCE_DATA)
  458. {
  459. RegCloseKey(hKeyPerf);
  460. hKeyPerf = NULL;
  461. }
  462. if(m_TitleBuffer)
  463. {
  464. delete [] m_TitleBuffer;
  465. m_TitleBuffer = NULL;
  466. }
  467. if (m_pCounter)
  468. {
  469. delete [] m_pCounter;
  470. m_pCounter = NULL;
  471. }
  472. m_Size = 0;
  473. m_IndexCache.Empty();
  474. return;
  475. }
  476. //***************************************************************************
  477. //
  478. // DWORD CImpPerf::GetPerfTitleSz
  479. //
  480. // DESCRIPTION:
  481. //
  482. // Retrieves the performance data title strings.
  483. // This call retrieves english version of the title strings.
  484. //
  485. // RETURN VALUE:
  486. //
  487. // 0 if OK
  488. // WBEM_E_OUT_OF_MEMORY if low memory
  489. // else set by RegOpenKeyEx
  490. //
  491. //***************************************************************************
  492. DWORD CImpPerf::GetPerfTitleSz ()
  493. {
  494. HKEY hKey1;
  495. DWORD Type;
  496. DWORD dwR;
  497. // Free any existing stuff
  498. if(m_TitleBuffer)
  499. {
  500. delete [] m_TitleBuffer;
  501. m_TitleBuffer = NULL;
  502. }
  503. if (m_pCounter)
  504. {
  505. delete [] m_pCounter;
  506. m_pCounter = NULL;
  507. }
  508. m_Size = 0;
  509. m_IndexCache.Empty();
  510. DWORD DataSize = 65536;
  511. DWORD nChars = DataSize/sizeof(WCHAR);
  512. wmilib::auto_buffer<WCHAR> pTitleBuffer( new WCHAR[nChars]);
  513. if (NULL == pTitleBuffer.get()) return WBEM_E_OUT_OF_MEMORY;
  514. // Find out the size of the data.
  515. dwR = RegQueryValueExW(HKEY_PERFORMANCE_TEXT,
  516. TEXT("Counter"),
  517. 0, &Type, (BYTE *)pTitleBuffer.get(), &DataSize);
  518. if (ERROR_MORE_DATA == dwR)
  519. {
  520. // Allocate more memory
  521. //
  522. nChars = DataSize/sizeof(WCHAR);
  523. pTitleBuffer.reset( new WCHAR[nChars]);
  524. if (NULL == pTitleBuffer.get()) return WBEM_E_OUT_OF_MEMORY;
  525. // Query the data
  526. //
  527. dwR = RegQueryValueEx (HKEY_PERFORMANCE_TEXT, TEXT("Counter"),
  528. 0, &Type, (BYTE *)pTitleBuffer.get(), &DataSize);
  529. }
  530. if(dwR == ERROR_ACCESS_DENIED) return WBEM_E_ACCESS_DENIED;
  531. if (dwR) return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwR);
  532. //
  533. // now parse the string, and set-up the arrays
  534. // string will be parsed backwards
  535. // expected fomat is
  536. // L"12345678\0description\0\0"
  537. //
  538. WCHAR * pEnd = pTitleBuffer.get()+nChars;
  539. // points to the last char
  540. pEnd--;
  541. while (*pEnd == L'\0') pEnd--;
  542. while (*pEnd) pEnd--;
  543. // past the zero after the last index
  544. pEnd--;
  545. while (*pEnd) pEnd--;
  546. // this should point to the last index as a string
  547. pEnd++;
  548. DWORD LastValidIndex = _wtoi(pEnd);
  549. if (0 == LastValidIndex) return WBEM_E_FAILED;
  550. LastValidIndex+=2; // just to be safe
  551. wmilib::auto_buffer<WCHAR *> pCounter( new WCHAR*[LastValidIndex]);
  552. if (NULL == pCounter.get()) return WBEM_E_OUT_OF_MEMORY;
  553. memset(pCounter.get(),0,LastValidIndex*sizeof(WCHAR *));
  554. DWORD IndexCounter;
  555. WCHAR * pStartCounter = pTitleBuffer.get();
  556. WCHAR * LimitMultiCounter = pTitleBuffer.get() + nChars;
  557. while ((*pStartCounter) && (pStartCounter < LimitMultiCounter))
  558. {
  559. IndexCounter = _wtoi(pStartCounter);
  560. while(*pStartCounter)
  561. pStartCounter++;
  562. pStartCounter++; // points to the string
  563. if (IndexCounter && (IndexCounter < LastValidIndex))
  564. {
  565. pCounter[IndexCounter] = (WCHAR *)(((ULONG_PTR)pStartCounter)|1);
  566. }
  567. // skip the string
  568. while(*pStartCounter) pStartCounter++;
  569. pStartCounter++; // points to the next number
  570. }
  571. m_TitleBuffer = pTitleBuffer.release();
  572. m_pCounter = pCounter.release();
  573. m_Size = LastValidIndex;
  574. EliminateRanges();
  575. return dwR;
  576. }
  577. void CImpPerf::EliminateRanges()
  578. {
  579. // the index1 is the span of the system reserved indexes
  580. WCHAR * pString = m_pCounter[1];
  581. DWORD SystemIndexes = 0;
  582. if (pString)
  583. {
  584. SystemIndexes = 1 + _wtoi((WCHAR *)((ULONG_PTR)pString & (~1)));
  585. }
  586. for (DWORD i = 0; i<min(SystemIndexes,m_Size); i++)
  587. {
  588. ULONG_PTR p = (ULONG_PTR)m_pCounter[i];
  589. if (p)
  590. {
  591. p &= (~1L);
  592. m_pCounter[i] = (WCHAR *)p;
  593. }
  594. }
  595. OnDeleteObjIf0<CImpPerf,void(CImpPerf:: *)(void),&CImpPerf::MakeAllValid> AllValid(this);
  596. HKEY hKey;
  597. LONG lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  598. L"SYSTEM\\CurrentControlSet\\Services",
  599. 0,
  600. KEY_ENUMERATE_SUB_KEYS,
  601. &hKey);
  602. if (ERROR_SUCCESS != lRet) return;
  603. OnDelete<HKEY,LONG(*)(HKEY),RegCloseKey> regClMe(hKey);
  604. DWORD BaseSize = 256;
  605. wmilib::auto_buffer<WCHAR> pKeyName(new WCHAR[BaseSize]);
  606. if (NULL == pKeyName.get()) return;
  607. DWORD FullKeySize = 256 + 13; // add length_of "\\performance"
  608. wmilib::auto_buffer<WCHAR> pFullKeyName(new WCHAR[FullKeySize]);
  609. if (NULL == pFullKeyName.get()) return;
  610. DWORD dwEnumIndex = 0;
  611. LONG lRes;
  612. while (TRUE)
  613. {
  614. DWORD dwRequiredSize = BaseSize;
  615. lRes = RegEnumKeyExW(hKey,dwEnumIndex,pKeyName.get(),&dwRequiredSize,
  616. NULL, NULL, NULL, NULL);
  617. if (ERROR_SUCCESS == lRes)
  618. {
  619. if (BaseSize > FullKeySize)
  620. {
  621. pFullKeyName.reset(new WCHAR[BaseSize + 13]);
  622. if (NULL == pFullKeyName.get()) return;
  623. FullKeySize = BaseSize + 13;
  624. }
  625. StringCchCopyW(pFullKeyName.get(),FullKeySize,pKeyName.get());
  626. StringCchCatW(pFullKeyName.get(),FullKeySize,L"\\Performance");
  627. HKEY hKeySec;
  628. LONG lResInner = RegOpenKeyExW(hKey,pFullKeyName.get(),
  629. 0,
  630. KEY_READ,
  631. &hKeySec);
  632. if (ERROR_SUCCESS != lResInner)
  633. {
  634. //DbgPrintfA(0,"KEY: %S ERR: %08x\n",pFullKeyName.get(),lResInner);
  635. dwEnumIndex++;
  636. continue;
  637. }
  638. OnDelete<HKEY,LONG(*)(HKEY),RegCloseKey> regClMe2(hKeySec);
  639. DWORD FirstCounter;
  640. DWORD LastCounter;
  641. DWORD dwSize = sizeof(DWORD);
  642. DWORD dwType;
  643. lResInner = RegQueryValueExW(hKeySec,
  644. L"First Counter",
  645. 0,
  646. &dwType,
  647. (BYTE*)&FirstCounter,
  648. &dwSize);
  649. if (ERROR_SUCCESS != lResInner || REG_DWORD != dwType) goto end_internal;
  650. dwSize = sizeof(DWORD);
  651. lResInner = RegQueryValueExW(hKeySec,
  652. L"Last Counter",
  653. 0,
  654. &dwType,
  655. (BYTE*)&LastCounter,
  656. &dwSize);
  657. if (ERROR_SUCCESS != lResInner || REG_DWORD != dwType) goto end_internal;
  658. //DbgPrintfA(0,"PerfLib %S First %d Last %d\n",pKeyName.get(),FirstCounter,LastCounter);
  659. if (FirstCounter > m_Size) goto end_internal;
  660. if (LastCounter > m_Size) goto end_internal;
  661. for (DWORD i=FirstCounter; i<=LastCounter;i++)
  662. {
  663. ULONG_PTR p = (ULONG_PTR)m_pCounter[i];
  664. if (p)
  665. {
  666. p &= (~1L);
  667. m_pCounter[i] = (WCHAR *)p;
  668. }
  669. };
  670. end_internal:
  671. dwEnumIndex++;
  672. continue;
  673. }
  674. else if (ERROR_MORE_DATA == lRes)
  675. {
  676. BaseSize += 256;
  677. pKeyName.reset(new WCHAR[BaseSize]);
  678. if (NULL == pKeyName.get()) return; // fall back to the regular case
  679. continue;
  680. }
  681. else if (ERROR_NO_MORE_ITEMS == lRes)
  682. {
  683. break; // exit the loop;
  684. }
  685. else
  686. {
  687. return; // not a known error
  688. }
  689. }
  690. AllValid.dismiss();
  691. /*
  692. for (DWORD i = 0; i< m_Size; i++)
  693. {
  694. ULONG_PTR p = (ULONG_PTR)m_pCounter[i];
  695. if (p)
  696. {
  697. if ((ULONG_PTR)p & 1L)
  698. {
  699. DbgPrintfA(0,"Eliminated Index %d - %S\n",i,(WCHAR *)((ULONG_PTR)p & (~1)));
  700. }
  701. }
  702. }
  703. */
  704. }
  705. //
  706. // this function is used if we cannot estabilish which indexes are valid
  707. //
  708. ////////////////////////////////////////////////////////////
  709. void CImpPerf::MakeAllValid()
  710. {
  711. for (DWORD i = 0; i< m_Size; i++)
  712. {
  713. ULONG_PTR p = (ULONG_PTR)m_pCounter[i];
  714. if (p)
  715. {
  716. p &= (~1L);
  717. m_pCounter[i] = (WCHAR *)p;
  718. }
  719. }
  720. }
  721. //***************************************************************************
  722. //
  723. // DWORD CImpPerf::dwGetRegHandles
  724. //
  725. // DESCRIPTION:
  726. //
  727. // Sets the handles for the local computer and the performance
  728. // information.
  729. //
  730. // PARAMETERS:
  731. //
  732. // pMachine Machine name
  733. //
  734. // RETURN VALUE:
  735. //
  736. // S_OK all is well
  737. // otherwise return is from RegConnectRegistry
  738. //***************************************************************************
  739. DWORD CImpPerf::dwGetRegHandles(
  740. const TCHAR * pMachine)
  741. {
  742. DWORD dwRet;
  743. TCHAR pTemp[256];
  744. if(pMachine == NULL)
  745. return WBEM_E_INVALID_PARAMETER;
  746. StringCchCopyW(pTemp, 256, pMachine);
  747. // if the current handles are to a remote machine, then free them
  748. if(!lstrcmpi(sMachine,TEXT("local")))
  749. {
  750. if(hKeyPerf && hKeyPerf != HKEY_PERFORMANCE_DATA)
  751. RegCloseKey(hKeyPerf);
  752. if(hKeyMachine)
  753. RegCloseKey(hKeyMachine);
  754. hKeyPerf = hKeyMachine = NULL;
  755. }
  756. // Determine if the target is remote or local
  757. if(lstrcmpi(pMachine,TEXT("local")))
  758. {
  759. // Remote, connect up
  760. dwRet = RegConnectRegistry(pTemp,HKEY_PERFORMANCE_DATA,
  761. &hKeyPerf);
  762. if(dwRet != S_OK) // could not remote connect
  763. return dwRet;
  764. dwRet = RegConnectRegistry(pTemp,HKEY_LOCAL_MACHINE,
  765. &hKeyMachine);
  766. if(dwRet != S_OK)
  767. {
  768. RegCloseKey(hKeyPerf);
  769. hKeyPerf = hKeyMachine = NULL;
  770. return dwRet;
  771. }
  772. }
  773. else
  774. {
  775. hKeyMachine = HKEY_LOCAL_MACHINE;
  776. hKeyPerf = HKEY_PERFORMANCE_DATA;
  777. }
  778. return 0;
  779. }
  780. //***************************************************************************
  781. //
  782. // int CImpPerf::iGetTitleIndex
  783. //
  784. // DESCRIPTION:
  785. //
  786. // Looks for the name in the buffer containing the names and
  787. // returns the index. The buffer is a series of strings with a double
  788. // null at the end. Each counter or object is represented by a pair of
  789. // strings with the first having the number and the second having the
  790. // text. This code goes through the pairs, storing the number string and
  791. // checking the text vs the input. If a match, then the number is returned.
  792. //
  793. // PARAMETERS:
  794. //
  795. // pSearch String to be found in buffer
  796. //
  797. // RETURN VALUE:
  798. //
  799. // integer that goes with the string. -1 if not found
  800. //
  801. //***************************************************************************
  802. int CImpPerf::iGetTitleIndex(
  803. const TCHAR * pSearch, BOOL addDups)
  804. {
  805. int iRet = -1;
  806. if(pSearch == NULL) return -1;
  807. DWORD Index = m_IndexCache.Find(pSearch);
  808. if(Index != -1) return Index;
  809. for (DWORD i = 0; i< m_Size; i++)
  810. {
  811. ULONG_PTR p = (ULONG_PTR)m_pCounter[i];
  812. if (p)
  813. {
  814. if (!(p & 1)) // a pointer is valid if it DOES NOT have the low bit set
  815. {
  816. if (0 == wbem_wcsicmp(pSearch,m_pCounter[i]))
  817. {
  818. m_IndexCache.Add(m_pCounter[i], i);
  819. //DbgPrintfA(0,"%d - %S\n",i,m_pCounter[i]);
  820. if(addDups == FALSE)
  821. return i;
  822. if(iRet == -1)
  823. iRet = i;
  824. }
  825. }
  826. }
  827. }
  828. return iRet;
  829. }
  830. //***************************************************************************
  831. //
  832. // SCODE CImpPerf::FindData
  833. //
  834. // DESCRIPTION:
  835. //
  836. // Finds the counter in the data block. Note that the steps are quite
  837. // involved and an understanding of the structure of performance data
  838. // is probably required. See chap 66 of the Win32 Programmers Ref.
  839. //
  840. //
  841. // PARAMETERS:
  842. //
  843. // pData Data block to be searched
  844. // iObj Int which identifies the object
  845. // iCount Int which identifies the counter
  846. // ProvObj Object containing the parsed context string
  847. // pdwSize Size of data
  848. // **ppRetData points to data
  849. // pls Line structure
  850. // bNew If true, indicates that we are searching the newest
  851. // sample of data.
  852. // pInfo If set, points to an collection object which
  853. // contains a list of instance names. By being set
  854. // the function doesnt look for actual data, instead
  855. // it is used just to get the instance names.
  856. //
  857. // RETURN VALUE:
  858. //
  859. // S_OK all is well
  860. // WBEM_E_FAILED couldnt find the data in the block
  861. //
  862. //***************************************************************************
  863. SCODE CImpPerf::FindData(
  864. IN PERF_DATA_BLOCK * pData,
  865. IN int iObj,
  866. IN int iCount,
  867. IN CProvObj & ProvObj,
  868. OUT DWORD * pdwSize,
  869. OUT void **ppRetData,
  870. OUT PLINESTRUCT pls,
  871. IN BOOL bNew,
  872. OUT CEnumPerfInfo * pInfo)
  873. {
  874. try
  875. {
  876. int iIndex;
  877. BOOL bEqual;
  878. DWORD dwSize = 0;
  879. DWORD dwType,dwTypeBase = 0;
  880. *ppRetData = NULL;
  881. void * pVoid = NULL, * pVoidBase = NULL;
  882. PPERF_OBJECT_TYPE pObj = NULL;
  883. PPERF_COUNTER_DEFINITION pCount = NULL;
  884. PPERF_COUNTER_DEFINITION pCountBase= NULL;
  885. PPERF_INSTANCE_DEFINITION pInst = NULL;
  886. // Some objects, such as disks, have what are called instances and in
  887. // that case the provider string will have an extra token with the
  888. // instance name in it.
  889. WCHAR wInstName[MAX_PATH];
  890. wInstName[0] = 0;
  891. WCHAR * pwInstName = wInstName;
  892. long lDuplicateNum = 0;
  893. // If there is an instance name, convert it to WCHAR. Also, the
  894. // instance name may be of the for "[123]chars" and in this case the
  895. // didits between "[]" are converted to a number and the actual name
  896. // starts after the ']'.
  897. if(ProvObj.iGetNumTokens() > 3)
  898. {
  899. if(lstrlen(ProvObj.sGetToken(3)) > MAX_PATH -1)
  900. return WBEM_E_FAILED;
  901. #ifdef UNICODE
  902. StringCchCopyW(wInstName, MAX_PATH, ProvObj.sGetToken(3));
  903. #else
  904. mbstowcs(wInstName, ProvObj.sGetToken(3), MAX_PATH-1);
  905. #endif
  906. if(wInstName[0] == L'[')
  907. {
  908. lDuplicateNum = _wtol(&wInstName[1]);
  909. for(pwInstName = &wInstName[1]; *pwInstName && *pwInstName != L']';
  910. pwInstName++); // INTENTIONAL SEMI!
  911. if(*pwInstName == L']')
  912. pwInstName++;
  913. }
  914. }
  915. else
  916. {
  917. // if there is not an instance name and the argument for enumeration is null, then we have a
  918. // bad path
  919. if(pInfo == NULL)
  920. return WBEM_E_INVALID_OBJECT_PATH;
  921. }
  922. // Go through the list of objects and find the one
  923. // that matches iObj
  924. pObj = (PPERF_OBJECT_TYPE)((PBYTE)pData + pData->HeaderLength);
  925. for(iIndex = 0; iIndex < (int)pData->NumObjectTypes; iIndex++)
  926. {
  927. if((int)pObj->ObjectNameTitleIndex == iObj)
  928. break; // found it!
  929. pObj = (PPERF_OBJECT_TYPE)((PBYTE)pObj + pObj->TotalByteLength);
  930. }
  931. if(iIndex == (int)pData->NumObjectTypes)
  932. return WBEM_E_FAILED; // never found object in the block
  933. // Object was found, set the object type data
  934. if(bNew)
  935. {
  936. pls->ObjPerfFreq = *(LONGLONG UNALIGNED *)(&pObj->PerfFreq);
  937. pls->ObjCounterTimeNew = *(LONGLONG UNALIGNED *)(&pObj->PerfTime);
  938. }
  939. else
  940. pls->ObjCounterTimeOld = *(LONGLONG UNALIGNED *)(&pObj->PerfTime);
  941. // Go through the list of counters for the object and find the one that
  942. // matches iCount. Note that some counter names may be have more than
  943. // one id. Therefore, try the other ids if the intial one doesnt work.
  944. bool bFound = false;
  945. bool bEndOfList = false;
  946. int lTry = 0; // how may times we have tried
  947. do
  948. {
  949. pCount = (PPERF_COUNTER_DEFINITION)((PBYTE)pObj + pObj->HeaderLength);
  950. for(iIndex = 0; iIndex < (int)pObj->NumCounters; iIndex++)
  951. {
  952. if((int)pCount->CounterNameTitleIndex == iCount || pInfo)
  953. {
  954. bFound = true;
  955. break; // found it!
  956. }
  957. pCount = (PPERF_COUNTER_DEFINITION)((PBYTE)pCount + pCount->ByteLength);
  958. }
  959. if(bFound == false)
  960. {
  961. lTry++;
  962. iCount = m_IndexCache.Find(ProvObj.sGetToken(2), lTry);
  963. if(iCount == -1)
  964. bEndOfList = true;
  965. }
  966. } while (bFound == false && bEndOfList == false);
  967. if(bFound == false)
  968. {
  969. return WBEM_E_FAILED; // never found object in the block
  970. }
  971. // The counter was found, save the counter information
  972. // If the counter is not the last one in the object, then the
  973. // next one might be the base which is used for certain calculations
  974. dwType = pCount->CounterType;
  975. pls->lnCounterType = pCount->CounterType;
  976. if(iIndex < (int)pObj->NumCounters - 1)
  977. {
  978. // might be the base
  979. pCountBase = (PPERF_COUNTER_DEFINITION)((PBYTE)pCount +
  980. pCount->ByteLength);
  981. dwTypeBase = pCountBase->CounterType;
  982. }
  983. // Get a pointer to the start of the perf counter block
  984. // There are two cases: If there are no instances, then
  985. // the data starts after the last counter descriptor.
  986. // If there are instances, each instance has it's own block.
  987. pVoid = NULL;
  988. if(pObj->NumInstances == -1)
  989. {
  990. // The object is a singleton
  991. if(pInfo) // If we are enumerating instances
  992. {
  993. pInfo->AddEntry(L"@");
  994. return S_OK;
  995. }
  996. // easy case, get offset into data, add offset
  997. // for particular counter.
  998. pVoid = (PBYTE)pObj + pObj->DefinitionLength
  999. + pCount->CounterOffset;
  1000. if(pCountBase)
  1001. pVoidBase = (PBYTE)pObj + pObj->DefinitionLength
  1002. + pCountBase->CounterOffset;
  1003. }
  1004. else if(pObj->NumInstances > 0)
  1005. {
  1006. WCHAR wNum[12];
  1007. // hard case, got a list of instaces, start off
  1008. // by getting a pointer to the first one.
  1009. long lNumDupsSoFar = 0;
  1010. pInst= (PPERF_INSTANCE_DEFINITION)((PBYTE)pObj + pObj->DefinitionLength);
  1011. for(iIndex = 0; iIndex < (int)pObj->NumInstances; iIndex++)
  1012. {
  1013. // Each instance has a unicode name, get it and
  1014. // compare it against the name passed in the
  1015. // provider string.
  1016. PPERF_COUNTER_BLOCK pCtrBlk;
  1017. WCHAR * pwName;
  1018. if(pInst->UniqueID == PERF_NO_UNIQUE_ID)
  1019. pwName = (WCHAR *)((PBYTE)pInst + pInst->NameOffset);
  1020. else
  1021. {
  1022. _ltow (pInst->UniqueID, wNum, 10);
  1023. pwName = wNum;
  1024. }
  1025. if(pInfo)
  1026. {
  1027. // We we are mearly getting the instance names, just add the
  1028. // instance name to the list. If the instance name is a
  1029. // duplicate, prepend "[num]" to the name.
  1030. if(wcslen(pwName) > 240)
  1031. continue; // should never happen but just in case!
  1032. int iRet = pInfo->GetNumDuplicates(pwName);
  1033. if(iRet > 0)
  1034. {
  1035. StringCchPrintfW (wInstName, MAX_PATH, L"[%ld]", iRet);
  1036. StringCchCatW(wInstName, MAX_PATH, pwName);
  1037. }
  1038. else
  1039. StringCchCopyW(wInstName, MAX_PATH, pwName);
  1040. pInfo->AddEntry(wInstName);
  1041. }
  1042. else
  1043. {
  1044. // for now the code assumes that the first instance
  1045. // will be retrieved if the instance is not specified
  1046. if(wcslen(pwInstName) == 0)
  1047. bEqual = TRUE;
  1048. else
  1049. {
  1050. bEqual = !wbem_wcsicmp(pwName ,pwInstName);
  1051. if(lDuplicateNum > lNumDupsSoFar && bEqual)
  1052. {
  1053. bEqual = FALSE;
  1054. lNumDupsSoFar++;
  1055. }
  1056. }
  1057. if(bEqual)
  1058. {
  1059. // we found the instance !!!! Data is found
  1060. // in data block following instance offset
  1061. // appropriatly for this counter.
  1062. pVoid = (PBYTE)pInst + pInst->ByteLength +
  1063. pCount->CounterOffset;
  1064. if(pCountBase)
  1065. pVoidBase = (PBYTE)pInst + pInst->ByteLength +
  1066. pCountBase->CounterOffset;
  1067. break;
  1068. }
  1069. }
  1070. // not found yet, next instance is after this
  1071. // instance + this instance's counter data
  1072. pCtrBlk = (PPERF_COUNTER_BLOCK)((PBYTE)pInst +
  1073. pInst->ByteLength);
  1074. pInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)pInst +
  1075. pInst->ByteLength + pCtrBlk->ByteLength);
  1076. }
  1077. }
  1078. // Bail out if data was never found or if we were just looking for instances
  1079. if(pInfo)
  1080. return pInfo->GetStatus();
  1081. if(pVoid == NULL)
  1082. {
  1083. return WBEM_E_FAILED; // never found object in the block
  1084. }
  1085. // Move the counter data and possibly the base data into the structure
  1086. // Note that text is handled via the ppRetData pointer and is not
  1087. // done here.
  1088. DWORD dwSizeField = dwType & 0x300;
  1089. void * pDest = (bNew) ? &pls->lnaCounterValue[0] : &pls->lnaOldCounterValue[0];
  1090. if(dwSizeField == PERF_SIZE_DWORD)
  1091. {
  1092. memset(pDest,0,sizeof(LONGLONG)); // zero out unused portions
  1093. dwSize = sizeof(DWORD);
  1094. memcpy(pDest,pVoid,dwSize);
  1095. }
  1096. else if(dwSizeField == PERF_SIZE_LARGE)
  1097. {
  1098. dwSize = sizeof(LONGLONG);
  1099. memcpy(pDest,pVoid,dwSize);
  1100. }
  1101. else if(dwSizeField == PERF_SIZE_VARIABLE_LEN)
  1102. dwSize = pCount->CounterSize; // this sets it for text
  1103. else
  1104. {
  1105. return WBEM_E_FAILED; // never found object in the block
  1106. }
  1107. // possibly do the base now.
  1108. dwSizeField = dwTypeBase & 0x300;
  1109. pDest = (bNew) ? &pls->lnaCounterValue[1] : &pls->lnaOldCounterValue[1];
  1110. if(dwSizeField == PERF_SIZE_DWORD && pVoidBase)
  1111. {
  1112. memset(pDest,0,sizeof(LONGLONG));
  1113. memcpy(pDest,pVoidBase,sizeof(DWORD));
  1114. }
  1115. else if(dwSizeField == PERF_SIZE_LARGE && pVoidBase)
  1116. memcpy(pDest,pVoidBase,sizeof(LONGLONG));
  1117. *ppRetData = pVoid; // Set to return data
  1118. *pdwSize = dwSize;
  1119. return S_OK;
  1120. }
  1121. catch(...)
  1122. {
  1123. return WBEM_E_FAILED;
  1124. }
  1125. }
  1126. //***************************************************************************
  1127. //
  1128. // SCODE CImpPerf::MakeEnum
  1129. //
  1130. // DESCRIPTION:
  1131. //
  1132. // Creates a CEnumPerfInfo object which can be used for enumeration
  1133. //
  1134. // PARAMETERS:
  1135. //
  1136. // pClass Pointer to the class object.
  1137. // ProvObj Object containing the property context string.
  1138. // ppInfo Set to point to an collection object which has
  1139. // the keynames of the instances.
  1140. //
  1141. // RETURN VALUE:
  1142. //
  1143. // S_OK all is well,
  1144. // else set by LoadData or FindData
  1145. //
  1146. //***************************************************************************
  1147. SCODE CImpPerf::MakeEnum(
  1148. IN IWbemClassObject * pClass,
  1149. IN CProvObj & ProvObj,
  1150. OUT CEnumInfo ** ppInfo)
  1151. {
  1152. SCODE sc;
  1153. int iObject,iCounter;
  1154. PERF_DATA_BLOCK * pNew;
  1155. DWORD dwSize;
  1156. LINESTRUCT ls;
  1157. void * pCountData;
  1158. CVariant vPerf;
  1159. CEnumPerfInfo * pInfo = NULL;
  1160. *ppInfo = NULL;
  1161. // The perf counter provider keeps some rather expensive data and
  1162. // so it doesnt support complete reentrancy.
  1163. if(hExec)
  1164. {
  1165. DWORD dwRet;
  1166. dwRet = WaitForSingleObject(hExec,MAX_EXEC_WAIT);
  1167. if(dwRet != WAIT_ABANDONED && dwRet != WAIT_OBJECT_0)
  1168. return WBEM_E_FAILED;
  1169. }
  1170. else
  1171. return WBEM_E_FAILED;
  1172. // Load up the data
  1173. sc = LoadData(ProvObj,&ls,&iObject,&iCounter,&pNew,TRUE);
  1174. if(sc != S_OK)
  1175. goto DoneMakeEnum;
  1176. // Create a new CEnumPerfInfo object. Its entries will be filled
  1177. // in by Find Data.
  1178. pInfo = new CEnumPerfInfo();
  1179. if(pInfo == NULL)
  1180. {
  1181. sc = WBEM_E_OUT_OF_MEMORY;
  1182. goto DoneMakeEnum;
  1183. }
  1184. sc = FindData(pNew,iObject,iCounter,ProvObj,&dwSize,&pCountData,
  1185. &ls,TRUE,pInfo);
  1186. if(sc != S_OK)
  1187. delete pInfo;
  1188. DoneMakeEnum:
  1189. if(sc == S_OK)
  1190. *ppInfo = pInfo;
  1191. if(hExec)
  1192. ReleaseMutex(hExec);
  1193. return sc;
  1194. }
  1195. //***************************************************************************
  1196. //
  1197. // SCODE CImpPerf::GetKey
  1198. //
  1199. // DESCRIPTION:
  1200. //
  1201. // Gets the key name of an entry in the enumeration list.
  1202. //
  1203. // PARAMETERS:
  1204. //
  1205. // pInfo Collection list
  1206. // iIndex Index in the collection
  1207. // ppKey Set to the string. MUST BE FREED with "delete"
  1208. //
  1209. // RETURN VALUE:
  1210. //
  1211. // S_OK if all is well
  1212. // WBEM_E_INVALID_PARAMETER bad index
  1213. // WBEM_E_OUT_OF_MEMORY
  1214. //***************************************************************************
  1215. SCODE CImpPerf::GetKey(
  1216. IN CEnumInfo * pInfo,
  1217. IN int iIndex,
  1218. OUT LPWSTR * ppKey)
  1219. {
  1220. DWORD dwLen;
  1221. CEnumPerfInfo * pPerfInfo = (CEnumPerfInfo *)pInfo;
  1222. LPWSTR pEntry = pPerfInfo->GetEntry(iIndex);
  1223. if(pEntry == NULL)
  1224. return WBEM_E_INVALID_PARAMETER;
  1225. dwLen = wcslen(pEntry)+1;
  1226. *ppKey = new WCHAR[dwLen];
  1227. if(*ppKey == NULL)
  1228. return WBEM_E_OUT_OF_MEMORY;
  1229. StringCchCopyW(*ppKey, dwLen,pEntry);
  1230. return S_OK;
  1231. }
  1232. //***************************************************************************
  1233. //
  1234. // SCODE CImpPerf::MergeStrings
  1235. //
  1236. // DESCRIPTION:
  1237. //
  1238. // Combines the Class Context, Key, and Property Context strings.
  1239. //
  1240. // PARAMETERS:
  1241. //
  1242. // ppOut Output string. MUST BE FREED VIA "delete"
  1243. // pClassContext Class context
  1244. // pKey Key property value
  1245. // pPropContext Property context
  1246. //
  1247. // RETURN VALUE:
  1248. //
  1249. // S_OK if all is well
  1250. // WBEM_E_INVALID_PARAMETER context string
  1251. // WBEM_E_OUT_OF_MEMORY
  1252. //
  1253. //***************************************************************************
  1254. SCODE CImpPerf::MergeStrings(
  1255. OUT LPWSTR * ppOut,
  1256. IN LPWSTR pClassContext,
  1257. IN LPWSTR pKey,
  1258. IN LPWSTR pPropContext)
  1259. {
  1260. // Allocate space for output
  1261. int iLen = 3;
  1262. if(pClassContext)
  1263. iLen += wcslen(pClassContext);
  1264. if(pKey)
  1265. iLen += wcslen(pKey);
  1266. if(pPropContext)
  1267. iLen += wcslen(pPropContext);
  1268. else
  1269. return WBEM_E_INVALID_PARAMETER; // should always have this!
  1270. *ppOut = new WCHAR[iLen];
  1271. if(*ppOut == NULL)
  1272. return WBEM_E_OUT_OF_MEMORY;
  1273. //todo todo, remove this demo specical
  1274. if(pPropContext[0] == L'@')
  1275. {
  1276. StringCchCopyW(*ppOut, iLen, pPropContext+1);
  1277. return S_OK;
  1278. }
  1279. //todo todo, remove this demo specical
  1280. // simplecase is that everything is in the property context. That would
  1281. // be the case when the provider is being used as a simple dynamic
  1282. // property provider
  1283. if(pClassContext == NULL || pKey == NULL)
  1284. {
  1285. StringCchCopyW(*ppOut, iLen, pPropContext);
  1286. return S_OK;
  1287. }
  1288. // Copy the class context, property, and finally the key
  1289. StringCchCopyW(*ppOut, iLen, pClassContext);
  1290. StringCchCatW(*ppOut, iLen, L"|");
  1291. StringCchCatW(*ppOut, iLen, pPropContext);
  1292. StringCchCatW(*ppOut, iLen, L"|");
  1293. StringCchCatW(*ppOut, iLen, pKey);
  1294. return S_OK;
  1295. }
  1296. //***************************************************************************
  1297. //
  1298. // CEnumPerfInfo::CEnumPerfInfo
  1299. //
  1300. // DESCRIPTION:
  1301. //
  1302. // Constructor.
  1303. //
  1304. //***************************************************************************
  1305. CEnumPerfInfo::CEnumPerfInfo()
  1306. {
  1307. m_iNumUniChar = 0;
  1308. m_iNumEntries = 0;
  1309. m_pBuffer = NULL;
  1310. m_status = S_OK;
  1311. }
  1312. //***************************************************************************
  1313. //
  1314. // CEnumPerfInfo::~CEnumPerfInfo
  1315. //
  1316. // DESCRIPTION:
  1317. //
  1318. // Destructor.
  1319. //
  1320. //***************************************************************************
  1321. CEnumPerfInfo::~CEnumPerfInfo()
  1322. {
  1323. if(m_pBuffer)
  1324. delete m_pBuffer;
  1325. }
  1326. //***************************************************************************
  1327. //
  1328. // void CEnumPerfInfo::AddEntry
  1329. //
  1330. // DESCRIPTION:
  1331. //
  1332. // Adds an entry to the enumeration list.
  1333. //
  1334. // PARAMETERS:
  1335. //
  1336. // pNew String to add to collection.
  1337. //
  1338. //***************************************************************************
  1339. void CEnumPerfInfo::AddEntry(
  1340. LPWSTR pNew)
  1341. {
  1342. if(m_status != S_OK)
  1343. return; // already had memory problems.
  1344. int iNewSize = wcslen(pNew) + 1 + m_iNumUniChar;
  1345. LPWSTR pNewBuff = new WCHAR[iNewSize];
  1346. if(pNewBuff == NULL)
  1347. {
  1348. m_status = WBEM_E_OUT_OF_MEMORY;
  1349. return;
  1350. }
  1351. StringCchCopyW(&pNewBuff[m_iNumUniChar], iNewSize - m_iNumUniChar,pNew);
  1352. if(m_pBuffer)
  1353. {
  1354. memcpy(pNewBuff,m_pBuffer,m_iNumUniChar*2);
  1355. delete m_pBuffer;
  1356. }
  1357. m_iNumEntries++;
  1358. m_iNumUniChar = iNewSize;
  1359. m_pBuffer = pNewBuff;
  1360. }
  1361. //***************************************************************************
  1362. //
  1363. // int CEnumPerfInfo::GetNumDuplicates
  1364. //
  1365. // DESCRIPTION:
  1366. //
  1367. // Checks the list to find duplicate entries.
  1368. //
  1369. // PARAMETERS:
  1370. //
  1371. // pwcTest string to test for duplicates
  1372. //
  1373. // RETURN VALUE:
  1374. //
  1375. // number of matching strings in the collection.
  1376. //
  1377. //***************************************************************************
  1378. int CEnumPerfInfo::GetNumDuplicates(
  1379. LPWSTR pwcTest)
  1380. {
  1381. int iRet = 0;
  1382. int iCnt;
  1383. LPWSTR pVal = m_pBuffer;
  1384. for(iCnt = 0; iCnt < m_iNumEntries; iCnt++)
  1385. {
  1386. WCHAR * pwcText = pVal;
  1387. // If the string is of the form "[number]text", skip the "[number]"
  1388. // part.
  1389. if(*pVal == L'[')
  1390. {
  1391. for(pwcText = pVal+1; *pwcText && *pwcText != L']';pwcText++);
  1392. if(*pwcText == L']')
  1393. pVal = pwcText+1;
  1394. }
  1395. if(!wbem_wcsicmp(pwcTest, pVal))
  1396. iRet++;
  1397. pVal += wcslen(pVal) + 1;
  1398. }
  1399. return iRet;
  1400. }
  1401. //***************************************************************************
  1402. //
  1403. // LPWSTR CEnumPerfInfo::GetEntry
  1404. //
  1405. // DESCRIPTION:
  1406. //
  1407. // Gets a list entry.
  1408. //
  1409. // PARAMETERS:
  1410. //
  1411. // iIndex collection index
  1412. //
  1413. // RETURN VALUE:
  1414. //
  1415. // pointer to string in index. Should NOT be freed.
  1416. // NULL if bad index
  1417. //
  1418. //***************************************************************************
  1419. LPWSTR CEnumPerfInfo::GetEntry(
  1420. IN int iIndex)
  1421. {
  1422. // fist check for bad conditions
  1423. if(m_status != S_OK || iIndex < 0 || iIndex >= m_iNumEntries)
  1424. return NULL;
  1425. int iCnt;
  1426. LPWSTR pRet = m_pBuffer;
  1427. for(iCnt = 0; iCnt < iIndex; iCnt++)
  1428. pRet += wcslen(pRet) + 1;
  1429. return pRet;
  1430. }
  1431. //***************************************************************************
  1432. //
  1433. // CImpPerfProp::CImpPerfProp
  1434. //
  1435. // DESCRIPTION:
  1436. //
  1437. // Constructor.
  1438. //
  1439. //***************************************************************************
  1440. CImpPerfProp::CImpPerfProp()
  1441. {
  1442. m_pImpDynProv = new CImpPerf();
  1443. }
  1444. //***************************************************************************
  1445. //
  1446. // CImpPerfProp::~CImpPerfProp
  1447. //
  1448. // DESCRIPTION:
  1449. //
  1450. // Destructor.
  1451. //
  1452. //***************************************************************************
  1453. CImpPerfProp::~CImpPerfProp()
  1454. {
  1455. if(m_pImpDynProv)
  1456. delete m_pImpDynProv;
  1457. }