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.

1998 lines
76 KiB

  1. /*++
  2. Copyright (C) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. counter.c
  5. Abstract:
  6. counter processing functions exposed in pdh.dll
  7. --*/
  8. #include <windows.h>
  9. #include <stdlib.h>
  10. #include <assert.h>
  11. #include <math.h>
  12. #include <mbctype.h>
  13. #include <pdh.h>
  14. #include "pdhitype.h"
  15. #include "pdhidef.h"
  16. #include "pdhmsg.h"
  17. #include "strings.h"
  18. __inline
  19. DWORD
  20. PdhiGetStringLength(
  21. LPWSTR szString,
  22. BOOL bUnicode
  23. )
  24. {
  25. DWORD dwReturn = 0;
  26. if (bUnicode) {
  27. dwReturn = lstrlenW(szString);
  28. }
  29. else {
  30. dwReturn = WideCharToMultiByte(_getmbcp(),
  31. 0,
  32. szString,
  33. lstrlenW(szString),
  34. NULL,
  35. 0,
  36. NULL,
  37. NULL);
  38. }
  39. return dwReturn;
  40. }
  41. STATIC_PDH_FUNCTION
  42. PdhiGetFormattedCounterArray (
  43. IN PPDHI_COUNTER pCounter,
  44. IN DWORD dwFormat,
  45. IN LPDWORD lpdwBufferSize,
  46. IN LPDWORD lpdwItemCount,
  47. IN LPVOID ItemBuffer,
  48. IN BOOL bWideArgs
  49. )
  50. {
  51. PDH_STATUS PdhStatus = ERROR_SUCCESS;
  52. PDH_STATUS PdhFnStatus = ERROR_SUCCESS;
  53. DWORD dwRequiredSize = 0;
  54. WCHAR wszInstanceName[1024];
  55. PPDHI_RAW_COUNTER_ITEM pThisItem = NULL;
  56. PPDHI_RAW_COUNTER_ITEM pLastItem = NULL;
  57. PDH_RAW_COUNTER ThisRawCounter;
  58. PDH_RAW_COUNTER LastRawCounter;
  59. LPWSTR szThisItem;
  60. LPWSTR szLastItem;
  61. PPDH_RAW_COUNTER pThisRawCounter;
  62. PPDH_RAW_COUNTER pLastRawCounter;
  63. PPDH_FMT_COUNTERVALUE_ITEM_W pThisFmtItem;
  64. DWORD dwThisItemIndex;
  65. LPWSTR wszNextString;
  66. DWORD dwNameLength;
  67. DWORD dwRetItemCount = 0;
  68. PdhStatus = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
  69. if (PdhStatus != ERROR_SUCCESS) {
  70. return PdhStatus;
  71. }
  72. // compute required buffer size
  73. if (pCounter->dwFlags & PDHIC_MULTI_INSTANCE) {
  74. if (ItemBuffer != NULL) {
  75. pThisFmtItem = (PPDH_FMT_COUNTERVALUE_ITEM_W)ItemBuffer;
  76. if( pCounter->pThisRawItemList == NULL ){
  77. PdhStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
  78. goto Cleanup;
  79. }
  80. wszNextString = (LPWSTR)((LPBYTE)ItemBuffer +
  81. (sizeof (PDH_FMT_COUNTERVALUE_ITEM_W) *
  82. pCounter->pThisRawItemList->dwItemCount));
  83. // verify 8 byte alignment
  84. assert (((DWORD)wszNextString & 0x00000007) == 0);
  85. } else {
  86. pThisFmtItem = NULL;
  87. wszNextString = NULL;
  88. }
  89. // for multi structs, the buffer required
  90. dwThisItemIndex = 0;
  91. dwRequiredSize += (DWORD)(pCounter->pThisRawItemList->dwItemCount) *
  92. (bWideArgs ? sizeof (PDH_FMT_COUNTERVALUE_ITEM_W)
  93. : sizeof (PDH_FMT_COUNTERVALUE_ITEM_A));
  94. for (pThisItem = &(pCounter->pThisRawItemList->pItemArray[0]);
  95. dwThisItemIndex < pCounter->pThisRawItemList->dwItemCount;
  96. dwThisItemIndex++, pThisItem++, pLastItem++) {
  97. szThisItem = (LPWSTR) ( ((LPBYTE) pCounter->pThisRawItemList)
  98. + pThisItem->szName);
  99. if (bWideArgs) {
  100. dwRequiredSize += (lstrlenW(szThisItem) + 1) * sizeof(WCHAR);
  101. if ((dwRequiredSize <= *lpdwBufferSize) && (wszNextString != NULL)) {
  102. // this is the only field that is type dependent (i.e.
  103. // wide vs ansi chars.
  104. pThisFmtItem->szName = wszNextString;
  105. dwNameLength = lstrlenW(szThisItem) + 1;
  106. lstrcpyW (wszNextString, szThisItem);
  107. wszNextString += dwNameLength;
  108. PdhStatus = ERROR_SUCCESS;
  109. }
  110. else {
  111. PdhStatus = PDH_MORE_DATA;
  112. }
  113. }
  114. else {
  115. DWORD dwSize = (* lpdwBufferSize < dwRequiredSize)
  116. ? (0) : (* lpdwBufferSize - dwRequiredSize);
  117. PdhStatus = PdhiConvertUnicodeToAnsi(_getmbcp(),
  118. szThisItem, (LPSTR) wszNextString, & dwSize);
  119. if (wszNextString && PdhStatus == ERROR_SUCCESS) {
  120. pThisFmtItem->szName = wszNextString;
  121. wszNextString = (LPWSTR) ((LPSTR) wszNextString + dwSize);
  122. }
  123. dwRequiredSize += (dwSize * sizeof(CHAR));
  124. }
  125. if (PdhStatus == ERROR_SUCCESS) {
  126. //
  127. // COMPUTE FORMATTED VALUE HERE!!!
  128. //
  129. if (pCounter->pThisRawItemList != NULL) {
  130. ThisRawCounter.CStatus = pCounter->pThisRawItemList->CStatus;
  131. ThisRawCounter.TimeStamp = pCounter->pThisRawItemList->TimeStamp;
  132. ThisRawCounter.FirstValue = pThisItem->FirstValue;
  133. ThisRawCounter.SecondValue = pThisItem->SecondValue;
  134. ThisRawCounter.MultiCount = pThisItem->MultiCount;
  135. pThisRawCounter = &ThisRawCounter;
  136. } else {
  137. memset (&ThisRawCounter, 0, sizeof(ThisRawCounter));
  138. pThisRawCounter = NULL;
  139. }
  140. if (pCounter->pLastRawItemList != NULL) {
  141. // test to see if "This" buffer has more entries than "last" buffer
  142. if (dwThisItemIndex < pCounter->pLastRawItemList->dwItemCount) {
  143. pLastItem = &(pCounter->pLastRawItemList->pItemArray[dwThisItemIndex]);
  144. szLastItem = (LPWSTR)
  145. ( ((LPBYTE) pCounter->pLastRawItemList)
  146. + pLastItem->szName);
  147. if (lstrcmpiW(szThisItem, szLastItem) == 0) {
  148. // the names match so we'll assume this is the correct instance
  149. LastRawCounter.CStatus = pCounter->pLastRawItemList->CStatus;
  150. LastRawCounter.TimeStamp = pCounter->pLastRawItemList->TimeStamp;
  151. LastRawCounter.FirstValue = pLastItem->FirstValue;
  152. LastRawCounter.SecondValue = pLastItem->SecondValue;
  153. LastRawCounter.MultiCount = pLastItem->MultiCount;
  154. pLastRawCounter = &LastRawCounter;
  155. } else {
  156. // the names DON'T match so we'll try the calc on just
  157. // one value. This will work for some (e.g. instantaneous)
  158. // counters, but not all
  159. memset (&LastRawCounter, 0, sizeof(LastRawCounter));
  160. pLastRawCounter = NULL;
  161. }
  162. } else {
  163. // the new buffer is larger than the old one so
  164. // we'll try the calc function on just
  165. // one value. This will work for some (e.g. instantaneous)
  166. // counters, but not all
  167. memset (&LastRawCounter, 0, sizeof(LastRawCounter));
  168. pLastRawCounter = NULL;
  169. }
  170. } else {
  171. // there is no "previous" counter entry for this counter
  172. memset (&LastRawCounter, 0, sizeof(LastRawCounter));
  173. pLastRawCounter = NULL;
  174. }
  175. PdhFnStatus = PdhiComputeFormattedValue (
  176. pCounter->CalcFunc,
  177. pCounter->plCounterInfo.dwCounterType,
  178. pCounter->lScale,
  179. dwFormat,
  180. pThisRawCounter,
  181. pLastRawCounter,
  182. &pCounter->TimeBase,
  183. 0L,
  184. &pThisFmtItem->FmtValue);
  185. if (PdhFnStatus != ERROR_SUCCESS) {
  186. // save the last error encountered for return to the caller
  187. PdhStatus = PdhFnStatus;
  188. // error in calculation so set the status for this
  189. // counter item
  190. pThisFmtItem->FmtValue.CStatus = PDH_CSTATUS_INVALID_DATA;
  191. // clear the value
  192. pThisFmtItem->FmtValue.largeValue = 0;
  193. }
  194. // update pointers
  195. pThisFmtItem++;
  196. }
  197. }
  198. dwRetItemCount = dwThisItemIndex;
  199. } else {
  200. if (ItemBuffer != NULL) {
  201. pThisFmtItem = (PPDH_FMT_COUNTERVALUE_ITEM_W)ItemBuffer;
  202. wszNextString = (LPWSTR)((LPBYTE)ItemBuffer +
  203. (bWideArgs ? sizeof (PDH_FMT_COUNTERVALUE_ITEM_W)
  204. : sizeof (PDH_FMT_COUNTERVALUE_ITEM_A)));
  205. // verify 8 byte alignment
  206. assert (((DWORD)wszNextString & 0x00000007) == 0);
  207. } else {
  208. pThisFmtItem = NULL;
  209. wszNextString = NULL;
  210. }
  211. // this is a single instance counter so the size required is:
  212. // the size of the instance name +
  213. // the size of the parent name +
  214. // the size of any index parameter +
  215. // the size of the value buffer
  216. //
  217. if (pCounter->pCounterPath->szInstanceName != NULL) {
  218. dwRequiredSize += PdhiGetStringLength(
  219. pCounter->pCounterPath->szInstanceName,
  220. bWideArgs);
  221. if (pCounter->pCounterPath->szParentName != NULL) {
  222. dwRequiredSize += 1 + PdhiGetStringLength(
  223. pCounter->pCounterPath->szParentName,
  224. bWideArgs);
  225. }
  226. if (pCounter->pCounterPath->dwIndex > 0) {
  227. double dIndex, dLen;
  228. dIndex = (double) pCounter->pCounterPath->dwIndex; // cast to float
  229. dLen = floor(log10(dIndex)); // get integer log
  230. dwRequiredSize = (DWORD) dLen; // cast to integer
  231. dwRequiredSize += 2; // increment for brackets
  232. }
  233. // add in length of null character
  234. dwRequiredSize += 1;
  235. }
  236. // adjust size of required buffer by size of text character
  237. dwRequiredSize *= ((bWideArgs) ? (sizeof(WCHAR)) : (sizeof(CHAR)));
  238. // add in length of data structure
  239. dwRequiredSize += (bWideArgs ? sizeof (PDH_FMT_COUNTERVALUE_ITEM_W)
  240. : sizeof (PDH_FMT_COUNTERVALUE_ITEM_A));
  241. if ((dwRequiredSize <= *lpdwBufferSize) & (wszNextString != NULL)) {
  242. pThisFmtItem->szName = wszNextString;
  243. if (pCounter->pCounterPath->szInstanceName != NULL) {
  244. if (bWideArgs) {
  245. if (pCounter->pCounterPath->szParentName != NULL) {
  246. lstrcatW(pThisFmtItem->szName, pCounter->pCounterPath->szParentName);
  247. lstrcatW(pThisFmtItem->szName, cszSlash);
  248. } else {
  249. pThisFmtItem->szName[0] = 0;
  250. }
  251. lstrcatW(pThisFmtItem->szName, pCounter->pCounterPath->szInstanceName);
  252. if (pCounter->pCounterPath->dwIndex > 0) {
  253. _ltow (pCounter->pCounterPath->dwIndex,
  254. wszInstanceName, 10);
  255. lstrcatW(pThisFmtItem->szName, cszPoundSign);
  256. lstrcatW(pThisFmtItem->szName, wszInstanceName);
  257. }
  258. // update pointers
  259. wszNextString += lstrlenW(pThisFmtItem->szName) + 1;
  260. } else {
  261. if (pCounter->pCounterPath->szParentName != NULL) {
  262. dwNameLength = lstrlenW (pCounter->pCounterPath->szParentName);
  263. WideCharToMultiByte(_getmbcp(),
  264. 0,
  265. pCounter->pCounterPath->szParentName,
  266. dwNameLength + 1,
  267. (LPSTR) wszNextString,
  268. (dwNameLength + 1) * sizeof(WCHAR),
  269. NULL,
  270. NULL);
  271. wszNextString = (LPWSTR) ((LPSTR) wszNextString
  272. + lstrlenA((LPSTR) wszNextString));
  273. dwNameLength = lstrlenW(cszSlash);
  274. WideCharToMultiByte(_getmbcp(),
  275. 0,
  276. cszSlash,
  277. dwNameLength + 1,
  278. (LPSTR) wszNextString,
  279. (dwNameLength + 1 ) * sizeof(WCHAR),
  280. NULL,
  281. NULL);
  282. wszNextString = (LPWSTR) ((LPSTR) wszNextString
  283. + lstrlenA((LPSTR) wszNextString));
  284. }
  285. dwNameLength = lstrlenW(pCounter->pCounterPath->szInstanceName);
  286. WideCharToMultiByte(_getmbcp(),
  287. 0,
  288. pCounter->pCounterPath->szInstanceName,
  289. dwNameLength + 1,
  290. (LPSTR) wszNextString,
  291. (dwNameLength + 1) * sizeof(WCHAR),
  292. NULL,
  293. NULL);
  294. wszNextString = (LPWSTR) ((LPSTR) wszNextString
  295. + lstrlenA((LPSTR) wszNextString));
  296. if (pCounter->pCounterPath->dwIndex > 0) {
  297. _ltoa (pCounter->pCounterPath->dwIndex,
  298. (LPSTR)wszInstanceName, 10);
  299. lstrcatA((LPSTR)wszNextString, caszPoundSign);
  300. lstrcatA((LPSTR)wszNextString, (LPSTR)wszInstanceName);
  301. }
  302. // null terminate the string
  303. *((LPSTR)wszNextString) = 0;
  304. wszNextString = (LPWSTR)((LPBYTE)wszNextString + 1);
  305. // insure alignment on the appropriate boundry
  306. assert (bWideArgs ? (((DWORD)wszNextString & 0x00000001) == 0) : TRUE);
  307. }
  308. } else {
  309. *wszNextString = 0;
  310. }
  311. PdhFnStatus = PdhiComputeFormattedValue (
  312. pCounter->CalcFunc,
  313. pCounter->plCounterInfo.dwCounterType,
  314. pCounter->lScale,
  315. dwFormat,
  316. & pCounter->ThisValue,
  317. & pCounter->LastValue,
  318. & pCounter->TimeBase,
  319. 0L,
  320. & pThisFmtItem->FmtValue);
  321. if (PdhFnStatus != ERROR_SUCCESS) {
  322. PdhStatus = PdhFnStatus;
  323. // error in calculation so set the status for this
  324. // counter item
  325. pThisFmtItem->FmtValue.CStatus = PDH_CSTATUS_INVALID_DATA;
  326. // clear the value
  327. pThisFmtItem->FmtValue.largeValue = 0;
  328. // and return the status to the caller
  329. }
  330. } else {
  331. // then this was a real data request so return
  332. PdhStatus = PDH_MORE_DATA;
  333. }
  334. dwRetItemCount = 1;
  335. }
  336. Cleanup:
  337. RELEASE_MUTEX(pCounter->pOwner->hMutex);
  338. if (PdhStatus == ERROR_SUCCESS || PdhStatus == PDH_MORE_DATA) {
  339. // update buffer size and item count buffers
  340. * lpdwBufferSize = dwRequiredSize;
  341. * lpdwItemCount = dwRetItemCount;
  342. }
  343. return PdhStatus;
  344. }
  345. PDH_FUNCTION
  346. PdhGetFormattedCounterArrayA (
  347. IN HCOUNTER hCounter,
  348. IN DWORD dwFormat,
  349. IN LPDWORD lpdwBufferSize,
  350. IN LPDWORD lpdwItemCount,
  351. IN PPDH_FMT_COUNTERVALUE_ITEM_A ItemBuffer
  352. )
  353. {
  354. PDH_STATUS PdhStatus = ERROR_SUCCESS;
  355. DWORD dwBufferSize;
  356. DWORD dwItemCount;
  357. DWORD dwTest;
  358. LPBYTE pByte;
  359. // TODO: Post W2K1 Capture lpdw* to local variables. Capture ItemBuffer
  360. if ((lpdwBufferSize == NULL) || (lpdwItemCount == NULL)) {
  361. PdhStatus = PDH_INVALID_ARGUMENT;
  362. }
  363. else if (!IsValidCounter(hCounter)) {
  364. PdhStatus = PDH_INVALID_HANDLE;
  365. } else if (!CounterIsOkToUse (hCounter)) {
  366. PdhStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
  367. } else {
  368. // validate arguments
  369. __try {
  370. // test argument for Read and Write access
  371. dwBufferSize = *lpdwBufferSize;
  372. // test argument for Read and Write access
  373. dwItemCount = *lpdwItemCount;
  374. if (dwBufferSize > 0) {
  375. // then the buffer must be valid
  376. if (ItemBuffer != NULL) {
  377. // NULL is a valid value for this parameter
  378. // test both ends of the buffer passed in
  379. pByte = (LPBYTE)ItemBuffer;
  380. dwTest = (DWORD)pByte[0];
  381. pByte[0] = 0;
  382. pByte[0] = (BYTE)(dwTest & 0x000000FF);
  383. dwTest = (DWORD)pByte[dwBufferSize -1];
  384. pByte[dwBufferSize -1] = 0;
  385. pByte[dwBufferSize -1] = (BYTE)(dwTest & 0x000000FF);
  386. } else {
  387. PdhStatus = PDH_INVALID_ARGUMENT;
  388. }
  389. }
  390. // check for disallowed format options
  391. if ((dwFormat & PDH_FMT_RAW) ||
  392. (dwFormat & PDH_FMT_ANSI) ||
  393. (dwFormat & PDH_FMT_UNICODE) ||
  394. (dwFormat & PDH_FMT_NODATA)) {
  395. PdhStatus = PDH_INVALID_ARGUMENT;
  396. }
  397. } __except (EXCEPTION_EXECUTE_HANDLER) {
  398. PdhStatus = PDH_INVALID_ARGUMENT;
  399. }
  400. }
  401. if (PdhStatus == ERROR_SUCCESS) {
  402. PdhStatus = PdhiGetFormattedCounterArray (
  403. (PPDHI_COUNTER)hCounter,
  404. dwFormat,
  405. & dwBufferSize,
  406. & dwItemCount,
  407. (LPVOID)ItemBuffer,
  408. FALSE);
  409. }
  410. if (PdhStatus == ERROR_SUCCESS || PdhStatus == PDH_MORE_DATA) {
  411. __try {
  412. * lpdwBufferSize = dwBufferSize;
  413. * lpdwItemCount = dwItemCount;
  414. }
  415. __except (EXCEPTION_EXECUTE_HANDLER) {
  416. PdhStatus = PDH_INVALID_ARGUMENT;
  417. }
  418. }
  419. return PdhStatus;
  420. }
  421. PDH_FUNCTION
  422. PdhGetFormattedCounterArrayW (
  423. IN HCOUNTER hCounter,
  424. IN DWORD dwFormat,
  425. IN LPDWORD lpdwBufferSize,
  426. IN LPDWORD lpdwItemCount,
  427. IN PPDH_FMT_COUNTERVALUE_ITEM_W ItemBuffer
  428. )
  429. {
  430. PDH_STATUS PdhStatus = ERROR_SUCCESS;
  431. DWORD dwBufferSize;
  432. DWORD dwItemCount;
  433. DWORD dwTest;
  434. LPBYTE pByte;
  435. // TODO: Post W2K1 Capture lpdw* to local variables. Capture ItemBuffer
  436. if ((lpdwBufferSize == NULL) || (lpdwItemCount == NULL)) {
  437. PdhStatus = PDH_INVALID_ARGUMENT;
  438. }
  439. else if (!IsValidCounter(hCounter)) {
  440. PdhStatus = PDH_INVALID_HANDLE;
  441. } else if (!CounterIsOkToUse (hCounter)) {
  442. PdhStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
  443. } else {
  444. // validate arguments
  445. __try {
  446. // test argument for Read and Write access
  447. dwBufferSize = *lpdwBufferSize;
  448. // test argument for Read and Write access
  449. dwItemCount = *lpdwItemCount;
  450. if (dwBufferSize > 0) {
  451. // then the buffer must be valid
  452. if (ItemBuffer != NULL) {
  453. // NULL is a valid value for this parameter
  454. // test both ends of the buffer passed in
  455. pByte = (LPBYTE)ItemBuffer;
  456. dwTest = (DWORD)pByte[0];
  457. pByte[0] = 0;
  458. pByte[0] = (BYTE)(dwTest & 0x000000FF);
  459. dwTest = (DWORD)pByte[dwBufferSize -1];
  460. pByte[dwBufferSize -1] = 0;
  461. pByte[dwBufferSize -1] = (BYTE)(dwTest & 0x000000FF);
  462. } else {
  463. PdhStatus = PDH_INVALID_ARGUMENT;
  464. }
  465. }
  466. // check for disallowed format options
  467. if ((dwFormat & PDH_FMT_RAW) ||
  468. (dwFormat & PDH_FMT_ANSI) ||
  469. (dwFormat & PDH_FMT_UNICODE) ||
  470. (dwFormat & PDH_FMT_NODATA)) {
  471. PdhStatus = PDH_INVALID_ARGUMENT;
  472. }
  473. } __except (EXCEPTION_EXECUTE_HANDLER) {
  474. PdhStatus = PDH_INVALID_ARGUMENT;
  475. }
  476. }
  477. if (PdhStatus == ERROR_SUCCESS) {
  478. PdhStatus = PdhiGetFormattedCounterArray (
  479. (PPDHI_COUNTER)hCounter,
  480. dwFormat,
  481. & dwBufferSize,
  482. & dwItemCount,
  483. (LPVOID)ItemBuffer,
  484. TRUE);
  485. }
  486. if (PdhStatus == ERROR_SUCCESS || PdhStatus == PDH_MORE_DATA) {
  487. __try {
  488. * lpdwBufferSize = dwBufferSize;
  489. * lpdwItemCount = dwItemCount;
  490. }
  491. __except (EXCEPTION_EXECUTE_HANDLER) {
  492. PdhStatus = PDH_INVALID_ARGUMENT;
  493. }
  494. }
  495. return PdhStatus;
  496. }
  497. STATIC_PDH_FUNCTION
  498. PdhiGetRawCounterArray (
  499. IN PPDHI_COUNTER pCounter,
  500. IN LPDWORD lpdwBufferSize,
  501. IN LPDWORD lpdwItemCount,
  502. IN LPVOID ItemBuffer,
  503. IN BOOL bWideArgs
  504. )
  505. {
  506. PDH_STATUS PdhStatus = ERROR_SUCCESS;
  507. DWORD dwRequiredSize = 0;
  508. WCHAR wszInstanceName[1024];
  509. PPDHI_RAW_COUNTER_ITEM pThisItem;
  510. LPWSTR szThisItem;
  511. PPDH_RAW_COUNTER_ITEM_W pThisRawItem;
  512. DWORD dwThisItemIndex;
  513. LPWSTR wszNextString;
  514. DWORD dwNameLength;
  515. DWORD dwRetItemCount = 0;
  516. PdhStatus = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
  517. if (PdhStatus != ERROR_SUCCESS) {
  518. return PdhStatus;
  519. }
  520. // compute required buffer size
  521. if (pCounter->dwFlags & PDHIC_MULTI_INSTANCE) {
  522. if (ItemBuffer != NULL) {
  523. pThisRawItem = (PPDH_RAW_COUNTER_ITEM_W)ItemBuffer;
  524. wszNextString = (LPWSTR)((LPBYTE)ItemBuffer +
  525. (sizeof (PDH_RAW_COUNTER_ITEM_W) *
  526. pCounter->pThisRawItemList->dwItemCount));
  527. // verify 8 byte alignment
  528. assert (((DWORD)wszNextString & 0x00000007) == 0);
  529. } else {
  530. pThisRawItem = NULL;
  531. wszNextString = NULL;
  532. }
  533. // for multi structs, the buffer required
  534. dwThisItemIndex = 0;
  535. dwRequiredSize += pCounter->pThisRawItemList->dwItemCount *
  536. (bWideArgs ? sizeof (PDH_RAW_COUNTER_ITEM_W)
  537. : sizeof (PDH_RAW_COUNTER_ITEM_A));
  538. for (pThisItem = &(pCounter->pThisRawItemList->pItemArray[0]);
  539. dwThisItemIndex < pCounter->pThisRawItemList->dwItemCount;
  540. dwThisItemIndex++, pThisItem++) {
  541. szThisItem = (LPWSTR) ( ((LPBYTE) pCounter->pThisRawItemList)
  542. + pThisItem->szName);
  543. if (pThisRawItem != NULL) {
  544. pThisRawItem->szName = wszNextString;
  545. }
  546. else {
  547. PdhStatus = PDH_MORE_DATA;
  548. }
  549. if (bWideArgs) {
  550. dwNameLength = lstrlenW(szThisItem) + 1;
  551. if ( (dwRequiredSize <= * lpdwBufferSize)
  552. && (wszNextString != NULL)) {
  553. lstrcpyW (wszNextString, szThisItem);
  554. wszNextString += dwNameLength;
  555. }
  556. else {
  557. PdhStatus = PDH_MORE_DATA;
  558. if (pThisRawItem != NULL) pThisRawItem->szName = NULL;
  559. }
  560. dwRequiredSize += (dwNameLength * sizeof(WCHAR));
  561. }
  562. else {
  563. dwNameLength = (dwRequiredSize <= * lpdwBufferSize)
  564. ? (* lpdwBufferSize - dwRequiredSize) : (0);
  565. PdhStatus = PdhiConvertUnicodeToAnsi(_getmbcp(),
  566. szThisItem,
  567. (LPSTR) wszNextString,
  568. & dwNameLength);
  569. if (PdhStatus == ERROR_SUCCESS) {
  570. wszNextString = (LPWSTR)
  571. (((LPSTR) wszNextString) + dwNameLength);
  572. }
  573. else if (pThisRawItem != NULL) {
  574. pThisRawItem->szName = NULL;
  575. }
  576. dwRequiredSize += (dwNameLength * sizeof(CHAR));
  577. }
  578. if (PdhStatus == ERROR_SUCCESS) {
  579. pThisRawItem->RawValue.CStatus = pCounter->pThisRawItemList->CStatus;
  580. pThisRawItem->RawValue.TimeStamp = pCounter->pThisRawItemList->TimeStamp;
  581. pThisRawItem->RawValue.FirstValue = pThisItem->FirstValue;
  582. pThisRawItem->RawValue.SecondValue = pThisItem->SecondValue;
  583. pThisRawItem->RawValue.MultiCount = pThisItem->MultiCount;
  584. // update pointers
  585. pThisRawItem++;
  586. }
  587. }
  588. dwRetItemCount = dwThisItemIndex;
  589. } else {
  590. if (ItemBuffer != NULL) {
  591. pThisRawItem = (PPDH_RAW_COUNTER_ITEM_W)ItemBuffer;
  592. wszNextString = (LPWSTR)((LPBYTE)ItemBuffer +
  593. (bWideArgs ? sizeof (PDH_RAW_COUNTER_ITEM_W)
  594. : sizeof (PDH_RAW_COUNTER_ITEM_A)));
  595. // verify 8 byte alignment
  596. assert (((DWORD)wszNextString & 0x00000007) == 0);
  597. } else {
  598. pThisRawItem = NULL;
  599. wszNextString = NULL;
  600. }
  601. // this is a single instance counter so the size required is:
  602. // the size of the instance name +
  603. // the size of the parent name +
  604. // the size of any index parameter +
  605. // the size of the value buffer
  606. //
  607. if (pCounter->pCounterPath->szInstanceName != NULL) {
  608. dwRequiredSize += PdhiGetStringLength(
  609. pCounter->pCounterPath->szInstanceName,
  610. bWideArgs);
  611. if (pCounter->pCounterPath->szParentName != NULL) {
  612. dwRequiredSize += 1 + PdhiGetStringLength(
  613. pCounter->pCounterPath->szParentName,
  614. bWideArgs);
  615. }
  616. if (pCounter->pCounterPath->dwIndex > 0) {
  617. double dIndex, dLen;
  618. dIndex = (double)pCounter->pCounterPath->dwIndex; // cast to float
  619. dLen = floor(log10(dIndex)); // get integer log
  620. dwRequiredSize = (DWORD)dLen; // cast to integer
  621. dwRequiredSize += 1; // increment for pound sign
  622. }
  623. // add in length of two null characters
  624. // this still has to look like an MSZ even if there is
  625. // is only one string in the buffer
  626. dwRequiredSize += 1;
  627. }
  628. // adjust size of required buffer by size of text character
  629. dwRequiredSize *= ((bWideArgs) ? (sizeof(WCHAR)) : (sizeof(CHAR)));
  630. // add in length of data structure
  631. dwRequiredSize += (bWideArgs ? sizeof (PDH_RAW_COUNTER_ITEM_W)
  632. : sizeof (PDH_RAW_COUNTER_ITEM_A));
  633. if ((dwRequiredSize <= *lpdwBufferSize) && (wszNextString != NULL)) {
  634. if (pThisRawItem != NULL) {
  635. pThisRawItem->szName = wszNextString;
  636. }
  637. else {
  638. PdhStatus = PDH_MORE_DATA;
  639. }
  640. if (pCounter->pCounterPath->szInstanceName != NULL) {
  641. if (bWideArgs) {
  642. if (pCounter->pCounterPath->szParentName != NULL) {
  643. lstrcpyW(pThisRawItem->szName, pCounter->pCounterPath->szParentName);
  644. lstrcatW(pThisRawItem->szName, cszSlash);
  645. lstrcatW(pThisRawItem->szName, pCounter->pCounterPath->szInstanceName);
  646. } else {
  647. lstrcpyW(pThisRawItem->szName, pCounter->pCounterPath->szInstanceName);
  648. }
  649. if (pCounter->pCounterPath->dwIndex > 0) {
  650. _ltow (pCounter->pCounterPath->dwIndex,
  651. wszInstanceName, 10);
  652. lstrcatW(pThisRawItem->szName, cszPoundSign);
  653. lstrcatW(pThisRawItem->szName, wszInstanceName);
  654. }
  655. dwNameLength = lstrlenW(pThisRawItem->szName) + 1;
  656. wszNextString += dwNameLength;
  657. } else {
  658. if (pCounter->pCounterPath->szParentName != NULL) {
  659. dwNameLength = lstrlenW (pCounter->pCounterPath->szParentName);
  660. WideCharToMultiByte(_getmbcp(),
  661. 0,
  662. pCounter->pCounterPath->szParentName,
  663. dwNameLength + 1,
  664. (LPSTR) wszNextString,
  665. (dwNameLength + 1) * sizeof(WCHAR),
  666. NULL,
  667. NULL);
  668. wszNextString = (LPWSTR) ((LPSTR) wszNextString
  669. + lstrlenA((LPSTR) wszNextString));
  670. dwNameLength = lstrlenW(cszSlash);
  671. WideCharToMultiByte(_getmbcp(),
  672. 0,
  673. cszSlash,
  674. dwNameLength + 1,
  675. (LPSTR) wszNextString,
  676. (dwNameLength + 1) * sizeof(WCHAR),
  677. NULL,
  678. NULL);
  679. wszNextString = (LPWSTR) ((LPSTR) wszNextString
  680. + lstrlenA((LPSTR) wszNextString));
  681. }
  682. dwNameLength = lstrlenW(pCounter->pCounterPath->szInstanceName);
  683. WideCharToMultiByte(_getmbcp(),
  684. 0,
  685. pCounter->pCounterPath->szInstanceName,
  686. dwNameLength + 1,
  687. (LPSTR) wszNextString,
  688. (dwNameLength + 1) * sizeof(WCHAR),
  689. NULL,
  690. NULL);
  691. wszNextString = (LPWSTR) ((LPSTR) wszNextString
  692. + lstrlenA((LPSTR) wszNextString));
  693. if (pCounter->pCounterPath->dwIndex > 0) {
  694. _ltoa (pCounter->pCounterPath->dwIndex,
  695. (LPSTR)wszInstanceName, 10);
  696. lstrcpyA((LPSTR)wszNextString, caszPoundSign);
  697. lstrcatA((LPSTR)wszNextString, (LPSTR)wszInstanceName);
  698. dwNameLength = lstrlenA((LPSTR)wszNextString) + 1;
  699. wszNextString = (LPWSTR)((LPSTR)wszNextString + dwNameLength);
  700. }
  701. // null terminate the string
  702. *((LPSTR)wszNextString) = 0;
  703. wszNextString = (LPWSTR)((LPBYTE)wszNextString + 1);
  704. }
  705. } else {
  706. *wszNextString++ = 0;
  707. }
  708. pThisRawItem->RawValue = pCounter->ThisValue;
  709. } else {
  710. // then this was a real data request so return
  711. PdhStatus = PDH_MORE_DATA;
  712. }
  713. dwRetItemCount = 1;
  714. }
  715. RELEASE_MUTEX(pCounter->pOwner->hMutex);
  716. if (PdhStatus == ERROR_SUCCESS || PdhStatus == PDH_MORE_DATA) {
  717. // update buffer size and item count buffers
  718. *lpdwBufferSize = dwRequiredSize;
  719. *lpdwItemCount = dwRetItemCount;
  720. }
  721. return PdhStatus;
  722. }
  723. PDH_FUNCTION
  724. PdhGetRawCounterArrayA (
  725. IN HCOUNTER hCounter,
  726. IN LPDWORD lpdwBufferSize,
  727. IN LPDWORD lpdwItemCount,
  728. IN PPDH_RAW_COUNTER_ITEM_A ItemBuffer
  729. )
  730. {
  731. PDH_STATUS PdhStatus = ERROR_SUCCESS;
  732. DWORD dwBufferSize;
  733. DWORD dwItemCount;
  734. DWORD dwTest;
  735. LPBYTE pByte;
  736. // TODO: Post W2K1 Capture lpdw* to local variables. Capture ItemBuffer
  737. if ((lpdwBufferSize == NULL) || (lpdwItemCount == NULL)) {
  738. PdhStatus = PDH_INVALID_ARGUMENT;
  739. }
  740. else if (!IsValidCounter(hCounter)) {
  741. PdhStatus = PDH_INVALID_HANDLE;
  742. } else if (!CounterIsOkToUse (hCounter)) {
  743. PdhStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
  744. } else {
  745. // validate arguments
  746. __try {
  747. // test argument for Read and Write access
  748. dwBufferSize = *lpdwBufferSize;
  749. // test argument for Read and Write access
  750. dwItemCount = *lpdwItemCount;
  751. if (dwBufferSize > 0) {
  752. if (ItemBuffer != NULL) {
  753. // NULL is a valid value for this parameter
  754. // test both ends of the buffer passed in
  755. pByte = (LPBYTE)ItemBuffer;
  756. dwTest = (DWORD)pByte[0];
  757. pByte[0] = 0;
  758. pByte[0] = (BYTE)(dwTest & 0x000000FF);
  759. dwTest = (DWORD)pByte[dwBufferSize -1];
  760. pByte[dwBufferSize -1] = 0;
  761. pByte[dwBufferSize -1] = (BYTE)(dwTest & 0x000000FF);
  762. } else {
  763. // if the buffer size is > 0, then a pointer
  764. // must be non-null & valid
  765. PdhStatus = PDH_INVALID_ARGUMENT;
  766. }
  767. }
  768. } __except (EXCEPTION_EXECUTE_HANDLER) {
  769. PdhStatus = PDH_INVALID_ARGUMENT;
  770. }
  771. }
  772. if (PdhStatus == ERROR_SUCCESS) {
  773. PdhStatus = PdhiGetRawCounterArray (
  774. (PPDHI_COUNTER) hCounter,
  775. & dwBufferSize,
  776. & dwItemCount,
  777. (LPVOID) ItemBuffer,
  778. FALSE);
  779. }
  780. if (PdhStatus == ERROR_SUCCESS || PdhStatus == PDH_MORE_DATA) {
  781. __try {
  782. * lpdwBufferSize = dwBufferSize;
  783. * lpdwItemCount = dwItemCount;
  784. }
  785. __except (EXCEPTION_EXECUTE_HANDLER) {
  786. PdhStatus = PDH_INVALID_ARGUMENT;
  787. }
  788. }
  789. return PdhStatus;
  790. }
  791. PDH_FUNCTION
  792. PdhGetRawCounterArrayW (
  793. IN HCOUNTER hCounter,
  794. IN LPDWORD lpdwBufferSize,
  795. IN LPDWORD lpdwItemCount,
  796. IN PPDH_RAW_COUNTER_ITEM_W ItemBuffer
  797. )
  798. {
  799. PDH_STATUS PdhStatus = ERROR_SUCCESS;
  800. DWORD dwBufferSize;
  801. DWORD dwItemCount;
  802. DWORD dwTest;
  803. LPBYTE pByte;
  804. // TODO: Post W2K1 Capture lpdw* to local variables. Capture ItemBuffer
  805. if ((lpdwBufferSize == NULL) || (lpdwItemCount == NULL)) {
  806. PdhStatus = PDH_INVALID_ARGUMENT;
  807. }
  808. else if (!IsValidCounter(hCounter)) {
  809. PdhStatus = PDH_INVALID_HANDLE;
  810. } else if (!CounterIsOkToUse (hCounter)) {
  811. PdhStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
  812. } else {
  813. // validate arguments
  814. __try {
  815. // test argument for Read and Write access
  816. dwBufferSize = *lpdwBufferSize;
  817. // test argument for Read and Write access
  818. dwItemCount = *lpdwItemCount;
  819. if (dwBufferSize > 0) {
  820. if (ItemBuffer != NULL) {
  821. // NULL is a valid value for this parameter
  822. // test both ends of the buffer passed in
  823. pByte = (LPBYTE)ItemBuffer;
  824. dwTest = (DWORD)pByte[0];
  825. pByte[0] = 0;
  826. pByte[0] = (BYTE)(dwTest & 0x000000FF);
  827. dwTest = (DWORD)pByte[dwBufferSize -1];
  828. pByte[dwBufferSize -1] = 0;
  829. pByte[dwBufferSize -1] = (BYTE)(dwTest & 0x000000FF);
  830. } else {
  831. // if the buffer size is > 0, then a pointer
  832. // must be non-null & valid
  833. PdhStatus = PDH_INVALID_ARGUMENT;
  834. }
  835. }
  836. } __except (EXCEPTION_EXECUTE_HANDLER) {
  837. PdhStatus = PDH_INVALID_ARGUMENT;
  838. }
  839. }
  840. if (PdhStatus == ERROR_SUCCESS) {
  841. PdhStatus = PdhiGetRawCounterArray (
  842. (PPDHI_COUNTER) hCounter,
  843. & dwBufferSize,
  844. & dwItemCount,
  845. (LPVOID) ItemBuffer,
  846. TRUE);
  847. }
  848. if (PdhStatus == ERROR_SUCCESS || PdhStatus == PDH_MORE_DATA) {
  849. __try {
  850. * lpdwBufferSize = dwBufferSize;
  851. * lpdwItemCount = dwItemCount;
  852. }
  853. __except (EXCEPTION_EXECUTE_HANDLER) {
  854. PdhStatus = PDH_INVALID_ARGUMENT;
  855. }
  856. }
  857. return PdhStatus;
  858. }
  859. PDH_FUNCTION
  860. PdhGetFormattedCounterValue (
  861. IN HCOUNTER hCounter,
  862. IN DWORD dwFormat,
  863. IN LPDWORD lpdwType,
  864. IN PPDH_FMT_COUNTERVALUE pValue
  865. )
  866. /*++
  867. Routine Description:
  868. Function to retrieve, computer and format the specified counter's
  869. current value. The values used are those currently in the counter
  870. buffer. (The data is not collected by this routine.)
  871. Arguments:
  872. IN HCOUNTER hCounter
  873. the handle to the counter whose value should be returned
  874. IN DWORD dwFormat
  875. the format flags that define how the counter value should be
  876. formatted prior for return. These flags are defined in the
  877. PDH.H header file.
  878. IN LPDWORD lpdwType
  879. an optional buffer in which the counter type value can be returned.
  880. For the prototype, the flag values are defined in WINPERF.H
  881. IN PPDH_FMT_COUNTERVALUE pValue
  882. the pointer to the data buffer passed by the caller to receive
  883. the data requested.
  884. Return Value:
  885. The WIN32 Error status of the function's operation. Common values
  886. returned are:
  887. ERROR_SUCCESS when all requested data is returned
  888. PDH_INVALID_HANDLE if the handle is not recognized as valid
  889. PDH_INVALID_ARGUMENT if an argument is not correct or is
  890. incorrectly formatted.
  891. PDH_INVALID_DATA if the counter does not contain valid data
  892. or a successful status code
  893. --*/
  894. {
  895. PPDHI_COUNTER pCounter;
  896. PDH_STATUS lStatus = ERROR_SUCCESS;
  897. PDH_FMT_COUNTERVALUE LocalCounterValue;
  898. DWORD dwTypeMask;
  899. // TODO: Why bother with testing for NON-NULL stuff in mutex?
  900. // Check for obvious lpdwType != NULL & pValue != NULL before mutex.
  901. if (pValue == NULL) {
  902. lStatus = PDH_INVALID_ARGUMENT;
  903. } else {
  904. __try {
  905. if (pValue != NULL) {
  906. pValue->CStatus = (DWORD)-1;
  907. pValue->longValue = (LONGLONG)0;
  908. } else {
  909. lStatus = PDH_INVALID_ARGUMENT;
  910. }
  911. } __except (EXCEPTION_EXECUTE_HANDLER) {
  912. lStatus = PDH_INVALID_ARGUMENT;
  913. }
  914. }
  915. if (lStatus == ERROR_SUCCESS) {
  916. lStatus = WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
  917. if (lStatus != ERROR_SUCCESS) {
  918. // bail out here
  919. return lStatus;
  920. }
  921. if (!IsValidCounter(hCounter)) {
  922. lStatus = PDH_INVALID_HANDLE;
  923. }
  924. else if (!CounterIsOkToUse(hCounter)) {
  925. lStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
  926. } else {
  927. // validate format flags:
  928. // only one of the following can be set at a time
  929. dwTypeMask = dwFormat &
  930. (PDH_FMT_LONG | PDH_FMT_DOUBLE | PDH_FMT_LARGE);
  931. if (!((dwTypeMask == PDH_FMT_LONG) ||
  932. (dwTypeMask == PDH_FMT_DOUBLE) ||
  933. (dwTypeMask == PDH_FMT_LARGE))) {
  934. lStatus = PDH_INVALID_ARGUMENT;
  935. }
  936. }
  937. if (lStatus == ERROR_SUCCESS) {
  938. // get counter pointer
  939. pCounter = (PPDHI_COUNTER)hCounter;
  940. // lock query while reading the data
  941. lStatus = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
  942. if (lStatus == ERROR_SUCCESS) {
  943. // compute and format current value
  944. lStatus = PdhiComputeFormattedValue (
  945. pCounter->CalcFunc,
  946. pCounter->plCounterInfo.dwCounterType,
  947. pCounter->lScale,
  948. dwFormat,
  949. &pCounter->ThisValue,
  950. &pCounter->LastValue,
  951. &pCounter->TimeBase,
  952. 0L,
  953. &LocalCounterValue);
  954. RELEASE_MUTEX(pCounter->pOwner->hMutex);
  955. __try {
  956. if (lpdwType != NULL) {
  957. *lpdwType = pCounter->plCounterInfo.dwCounterType;
  958. } // NULL is OK, the counter type will not be returned, though
  959. *pValue = LocalCounterValue;
  960. } __except (EXCEPTION_EXECUTE_HANDLER) {
  961. lStatus = PDH_INVALID_ARGUMENT;
  962. }
  963. }
  964. }
  965. RELEASE_MUTEX (hPdhDataMutex);
  966. }
  967. return lStatus;
  968. }
  969. PDH_FUNCTION
  970. PdhGetRawCounterValue (
  971. IN HCOUNTER hCounter,
  972. IN LPDWORD lpdwType,
  973. IN PPDH_RAW_COUNTER pValue
  974. )
  975. /*++
  976. Routine Description:
  977. Function to retrieve the specified counter's current raw value.
  978. The values used are those currently in the counter
  979. buffer. (The data is not collected by this routine.)
  980. Arguments:
  981. IN HCOUNTER hCounter
  982. the handle to the counter whose value should be returned
  983. IN LPDWORD lpdwType
  984. an optional buffer in which the counter type value can be returned.
  985. This value must be NULL if this info is not desired.
  986. For the prototype, the flag values are defined in WINPERF.H
  987. IN PPDH_RAW_COUNTER pValue
  988. the pointer to the data buffer passed by the caller to receive
  989. the data requested.
  990. Return Value:
  991. The WIN32 Error status of the function's operation. Common values
  992. returned are:
  993. ERROR_SUCCESS when all requested data is returned
  994. PDH_INVALID_HANDLE if the handle is not recognized as valid
  995. PDH_INVALID_ARGUMENT if an argument is formatted incorrectly
  996. --*/
  997. {
  998. PDH_STATUS Status = ERROR_SUCCESS;
  999. PPDHI_COUNTER pCounter;
  1000. if (pValue == NULL) {
  1001. Status = PDH_INVALID_ARGUMENT;
  1002. } else {
  1003. Status = WAIT_FOR_AND_LOCK_MUTEX (hPdhDataMutex);
  1004. if (Status == ERROR_SUCCESS) {
  1005. // validate arguments before retrieving the data
  1006. if (!IsValidCounter(hCounter)) {
  1007. Status = PDH_INVALID_HANDLE;
  1008. }
  1009. else if (!CounterIsOkToUse(hCounter)) {
  1010. Status = PDH_CSTATUS_ITEM_NOT_VALIDATED;
  1011. } else {
  1012. // the handle is good so try the rest of the args
  1013. pCounter = (PPDHI_COUNTER)hCounter;
  1014. Status = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
  1015. if (Status == ERROR_SUCCESS) {
  1016. __try {
  1017. // try to write to the arguments passed in
  1018. *pValue = pCounter->ThisValue;
  1019. if (lpdwType != NULL) {
  1020. *lpdwType = pCounter->plCounterInfo.dwCounterType;
  1021. } // NULL is OK
  1022. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1023. Status = PDH_INVALID_ARGUMENT;
  1024. }
  1025. RELEASE_MUTEX(pCounter->pOwner->hMutex);
  1026. }
  1027. }
  1028. RELEASE_MUTEX (hPdhDataMutex);
  1029. }
  1030. }
  1031. return Status;
  1032. }
  1033. PDH_FUNCTION
  1034. PdhCalculateCounterFromRawValue (
  1035. IN HCOUNTER hCounter,
  1036. IN DWORD dwFormat,
  1037. IN PPDH_RAW_COUNTER rawValue1,
  1038. IN PPDH_RAW_COUNTER rawValue2,
  1039. IN PPDH_FMT_COUNTERVALUE fmtValue
  1040. )
  1041. /*++
  1042. Routine Description:
  1043. Calculates the formatted counter value using the data in the RawValue
  1044. buffer in the format requested by the format field using the
  1045. calculation functions of the counter type defined by the dwType
  1046. field.
  1047. Arguments:
  1048. IN HCOUNTER hCounter
  1049. The handle of the counter to use in order to determine the
  1050. calculation functions for interpretation of the raw value buffer
  1051. IN DWORD dwFormat
  1052. Format in which the requested data should be returned. The
  1053. values for this field are described in the PDH.H header
  1054. file.
  1055. IN PPDH_RAW_COUNTER rawValue1
  1056. pointer to the buffer that contains the first raw value structure
  1057. IN PPDH_RAW_COUNTER rawValue2
  1058. pointer to the buffer that contains the second raw value structure.
  1059. This argument may be null if only one value is required for the
  1060. computation.
  1061. IN PPDH_FMT_COUNTERVALUE fmtValue
  1062. the pointer to the data buffer passed by the caller to receive
  1063. the data requested. If the counter requires 2 values, (as in the
  1064. case of a rate counter), rawValue1 is assumed to be the most
  1065. recent value and rawValue2, the older value.
  1066. Return Value:
  1067. The WIN32 Error status of the function's operation. Common values
  1068. returned are:
  1069. ERROR_SUCCESS when all requested data is returned
  1070. PDH_INVALID_HANDLE if the counter handle is incorrect
  1071. PDH_INVALID_ARGUMENT if an argument is incorrect
  1072. --*/
  1073. {
  1074. PDH_STATUS lStatus = ERROR_SUCCESS;
  1075. PPDHI_COUNTER pCounter;
  1076. DWORD dwTypeMask;
  1077. PDH_FMT_COUNTERVALUE pdhLocalCounterValue;
  1078. if (fmtValue == NULL) {
  1079. lStatus = PDH_INVALID_ARGUMENT;
  1080. } else {
  1081. lStatus = WAIT_FOR_AND_LOCK_MUTEX (hPdhDataMutex);
  1082. }
  1083. if (lStatus == ERROR_SUCCESS) {
  1084. // validate arguments
  1085. if (!IsValidCounter(hCounter)) {
  1086. lStatus = PDH_INVALID_HANDLE;
  1087. }
  1088. else if (!CounterIsOkToUse(hCounter)) {
  1089. lStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
  1090. } else {
  1091. // the handle is valid so check the rest of the arguments
  1092. // validate format flags:
  1093. dwTypeMask = dwFormat &
  1094. (PDH_FMT_LONG | PDH_FMT_DOUBLE | PDH_FMT_LARGE);
  1095. // only one of the following can be set at a time
  1096. if (!((dwTypeMask == PDH_FMT_LONG) ||
  1097. (dwTypeMask == PDH_FMT_DOUBLE) ||
  1098. (dwTypeMask == PDH_FMT_LARGE))) {
  1099. lStatus = PDH_INVALID_ARGUMENT;
  1100. }
  1101. }
  1102. if (lStatus == ERROR_SUCCESS) {
  1103. pCounter = (PPDHI_COUNTER)hCounter;
  1104. lStatus = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
  1105. if (lStatus == ERROR_SUCCESS) {
  1106. lStatus = PdhiComputeFormattedValue (
  1107. (((PPDHI_COUNTER)hCounter)->CalcFunc),
  1108. (((PPDHI_COUNTER)hCounter)->plCounterInfo.dwCounterType),
  1109. (((PPDHI_COUNTER)hCounter)->lScale),
  1110. dwFormat,
  1111. rawValue1,
  1112. rawValue2,
  1113. &((PPDHI_COUNTER)hCounter)->TimeBase,
  1114. 0L,
  1115. &pdhLocalCounterValue);
  1116. RELEASE_MUTEX(pCounter->pOwner->hMutex);
  1117. __try {
  1118. *fmtValue = pdhLocalCounterValue;
  1119. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1120. lStatus = PDH_INVALID_ARGUMENT;
  1121. }
  1122. }
  1123. }
  1124. RELEASE_MUTEX (hPdhDataMutex);
  1125. }
  1126. return lStatus;
  1127. }
  1128. PDH_FUNCTION
  1129. PdhComputeCounterStatistics (
  1130. IN HCOUNTER hCounter,
  1131. IN DWORD dwFormat,
  1132. IN DWORD dwFirstEntry,
  1133. IN DWORD dwNumEntries,
  1134. IN PPDH_RAW_COUNTER lpRawValueArray,
  1135. IN PPDH_STATISTICS data
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. Reads an array of raw value structures of the counter type specified in
  1140. the dwType field, computes the counter values of each and formats
  1141. and returns a statistics structure that contains the following
  1142. statistical data from the counter information:
  1143. Minimum The smallest value of the computed counter values
  1144. Maximum The largest value of the computed counter values
  1145. Mean The arithmetic mean (average) of the computed values
  1146. Median The median value of the computed counter values
  1147. Arguments:
  1148. IN HCOUNTER hCounter
  1149. The handle of the counter to use in order to determine the
  1150. calculation functions for interpretation of the raw value buffer
  1151. IN DWORD dwFormat
  1152. Format in which the requested data should be returned. The
  1153. values for this field are described in the PDH.H header
  1154. file.
  1155. IN DWORD dwNumEntries
  1156. the number of raw value entries for the specified counter type
  1157. IN PPDH_RAW_COUNTER lpRawValueArray
  1158. pointer to the array of raw value entries to be evaluated
  1159. IN PPDH_STATISTICS data
  1160. the pointer to the data buffer passed by the caller to receive
  1161. the data requested.
  1162. Return Value:
  1163. The WIN32 Error status of the function's operation. Note that the
  1164. function can return successfully even though no data was calc-
  1165. ulated. The status value in the statistics data buffer must be
  1166. tested to insure the data is valid before it's used by an
  1167. application. Common values returned are:
  1168. ERROR_SUCCESS when all requested data is returned
  1169. PDH_INVALID_HANDLE if the counter handle is incorrect
  1170. PDH_INVALID_ARGUMENT if an argument is incorrect
  1171. --*/
  1172. {
  1173. PPDHI_COUNTER pCounter;
  1174. PDH_STATUS Status = ERROR_SUCCESS;
  1175. DWORD dwTypeMask;
  1176. if ((lpRawValueArray == NULL) || (data == NULL)) {
  1177. Status = PDH_INVALID_ARGUMENT;
  1178. } else {
  1179. Status = WAIT_FOR_AND_LOCK_MUTEX (hPdhDataMutex);
  1180. }
  1181. if (Status == ERROR_SUCCESS) {
  1182. if (!IsValidCounter(hCounter)) {
  1183. Status = PDH_INVALID_HANDLE;
  1184. }
  1185. else if (!CounterIsOkToUse(hCounter)) {
  1186. Status = PDH_CSTATUS_ITEM_NOT_VALIDATED;
  1187. } else {
  1188. // counter handle is valid so test the rest of the
  1189. // arguments
  1190. // validate format flags:
  1191. // only one of the following can be set at a time
  1192. dwTypeMask = dwFormat &
  1193. (PDH_FMT_LONG | PDH_FMT_DOUBLE | PDH_FMT_LARGE);
  1194. if (!((dwTypeMask == PDH_FMT_LONG) ||
  1195. (dwTypeMask == PDH_FMT_DOUBLE) ||
  1196. (dwTypeMask == PDH_FMT_LARGE))) {
  1197. Status = PDH_INVALID_ARGUMENT;
  1198. }
  1199. }
  1200. if (Status == ERROR_SUCCESS) {
  1201. pCounter = (PPDHI_COUNTER)hCounter;
  1202. Status = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
  1203. if (Status == ERROR_SUCCESS) {
  1204. __try {
  1205. DWORD dwTest;
  1206. // we should have read access to the Raw Data
  1207. dwTest = *((DWORD volatile *)&lpRawValueArray->CStatus);
  1208. if (dwFirstEntry >= dwNumEntries) {
  1209. Status = PDH_INVALID_ARGUMENT;
  1210. } else {
  1211. // call satistical function for this counter
  1212. Status = (*pCounter->StatFunc)(
  1213. pCounter,
  1214. dwFormat,
  1215. dwFirstEntry,
  1216. dwNumEntries,
  1217. lpRawValueArray,
  1218. data);
  1219. }
  1220. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1221. Status = PDH_INVALID_ARGUMENT;
  1222. }
  1223. RELEASE_MUTEX(pCounter->pOwner->hMutex);
  1224. }
  1225. }
  1226. RELEASE_MUTEX (hPdhDataMutex);
  1227. }
  1228. return Status;
  1229. }
  1230. STATIC_PDH_FUNCTION
  1231. PdhiGetCounterInfo (
  1232. IN HCOUNTER hCounter,
  1233. IN BOOLEAN bRetrieveExplainText,
  1234. IN LPDWORD pdwBufferSize,
  1235. IN PPDH_COUNTER_INFO_W lpBuffer,
  1236. IN BOOL bUnicode
  1237. )
  1238. /*++
  1239. Routine Description:
  1240. Examines the specified counter and returns the configuration and
  1241. status information of the counter.
  1242. Arguments:
  1243. IN HCOUNTER hCounter
  1244. Handle to the desired counter.
  1245. IN BOOLEAN bRetrieveExplainText
  1246. TRUE will fill in the explain text structure
  1247. FALSE will return a null pointer in the explain text
  1248. IN LPDWORD pcchBufferSize
  1249. The address of the buffer that contains the size of the data buffer
  1250. passed by the caller. On entry, the value in the buffer is the
  1251. size of the data buffer in bytes. On return, this value is the size
  1252. of the buffer returned. If the buffer is not large enough, then
  1253. this value is the size that the buffer needs to be in order to
  1254. hold the requested data.
  1255. IN LPPDH_COUNTER_INFO_W lpBuffer
  1256. the pointer to the data buffer passed by the caller to receive
  1257. the data requested.
  1258. IN BOOL bUnicode
  1259. TRUE if wide character strings should be returned
  1260. FALSE if ANSI strings should be returned
  1261. Return Value:
  1262. The WIN32 Error status of the function's operation. Common values
  1263. returned are:
  1264. ERROR_SUCCESS when all requested data is returned
  1265. PDH_MORE_DATA when the buffer passed by the caller is too small
  1266. PDH_INVALID_HANDLE if the handle is not recognized as valid
  1267. PDH_INVALID_ARGUMENT if an argument is invalid or incorrect
  1268. --*/
  1269. {
  1270. PDH_STATUS Status = ERROR_SUCCESS;
  1271. DWORD dwSizeRequired = 0;
  1272. DWORD dwPathLength;
  1273. DWORD dwMachineLength;
  1274. DWORD dwObjectLength;
  1275. DWORD dwInstanceLength;
  1276. DWORD dwParentLength;
  1277. DWORD dwNameLength = 0;
  1278. DWORD dwHelpLength = 0;
  1279. PPDHI_COUNTER pCounter;
  1280. DWORD dwBufferSize = 0;
  1281. Status = WAIT_FOR_AND_LOCK_MUTEX (hPdhDataMutex);
  1282. if (Status == ERROR_SUCCESS) {
  1283. if (!IsValidCounter(hCounter)) {
  1284. Status = PDH_INVALID_HANDLE;
  1285. }
  1286. else if (!CounterIsOkToUse(hCounter)) {
  1287. Status = PDH_CSTATUS_ITEM_NOT_VALIDATED;
  1288. } else {
  1289. // the counter is valid so test the remaining arguments
  1290. __try {
  1291. if (pdwBufferSize != NULL) {
  1292. // test read & write access
  1293. dwBufferSize = *pdwBufferSize;
  1294. } else {
  1295. // this cannot be NULL
  1296. Status = PDH_INVALID_ARGUMENT;
  1297. }
  1298. if (Status == ERROR_SUCCESS) {
  1299. // test return buffer for write access at
  1300. // both ends of the buffer
  1301. if ((lpBuffer != NULL) && (dwBufferSize > 0)) {
  1302. *(LPDWORD)lpBuffer = 0;
  1303. ((LPBYTE)lpBuffer)[dwBufferSize - 1] = 0;
  1304. }
  1305. }
  1306. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1307. Status = PDH_INVALID_ARGUMENT;
  1308. }
  1309. }
  1310. if (Status == ERROR_SUCCESS) {
  1311. pCounter = (PPDHI_COUNTER) hCounter;
  1312. Status = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
  1313. if (Status == ERROR_SUCCESS) {
  1314. // check for a "no string" request
  1315. if ((dwBufferSize == sizeof (PDH_COUNTER_INFO_W)) &&
  1316. (lpBuffer != NULL)) {
  1317. // then return all but the strings
  1318. // room for the basic structure so load it
  1319. lpBuffer->dwLength = dwSizeRequired; // this will be updated later
  1320. lpBuffer->dwType = pCounter->plCounterInfo.dwCounterType;
  1321. lpBuffer->CVersion = pCounter->CVersion;
  1322. lpBuffer->CStatus = pCounter->ThisValue.CStatus;
  1323. lpBuffer->lScale = pCounter->lScale;
  1324. lpBuffer->lDefaultScale = pCounter->plCounterInfo.lDefaultScale;
  1325. lpBuffer->dwUserData = pCounter->dwUserData;
  1326. lpBuffer->dwQueryUserData = pCounter->pOwner->dwUserData;
  1327. lpBuffer->szFullPath = NULL;
  1328. lpBuffer->szMachineName = NULL;
  1329. lpBuffer->szObjectName = NULL;
  1330. lpBuffer->szInstanceName = NULL;
  1331. lpBuffer->szParentInstance = NULL;
  1332. lpBuffer->dwInstanceIndex = 0L;
  1333. lpBuffer->szCounterName = NULL;
  1334. lpBuffer->szExplainText = NULL;
  1335. lpBuffer->DataBuffer[0] = 0;
  1336. // the size value is ok to leave as is
  1337. } else {
  1338. // this is a size/full request so continue
  1339. // compute size of data to return
  1340. dwSizeRequired = sizeof (PDH_COUNTER_INFO_W) - sizeof(DWORD); // size of struct
  1341. // this should already end on a DWORD boundry
  1342. dwPathLength = 1 + PdhiGetStringLength(
  1343. pCounter->szFullName,
  1344. bUnicode);
  1345. dwPathLength *= (bUnicode ? sizeof(WCHAR)
  1346. : sizeof(CHAR));
  1347. dwPathLength = DWORD_MULTIPLE(dwPathLength);
  1348. dwSizeRequired += dwPathLength;
  1349. dwMachineLength = 1 + PdhiGetStringLength(
  1350. pCounter->pCounterPath->szMachineName,
  1351. bUnicode);
  1352. dwMachineLength *= (bUnicode ? sizeof(WCHAR)
  1353. : sizeof(CHAR));
  1354. dwMachineLength = DWORD_MULTIPLE(dwMachineLength);
  1355. dwSizeRequired += dwMachineLength;
  1356. dwObjectLength = 1 + PdhiGetStringLength(
  1357. pCounter->pCounterPath->szObjectName,
  1358. bUnicode);
  1359. dwObjectLength *= (bUnicode ? sizeof(WCHAR)
  1360. : sizeof(CHAR));
  1361. dwObjectLength = DWORD_MULTIPLE(dwObjectLength);
  1362. dwSizeRequired += dwObjectLength;
  1363. if (pCounter->pCounterPath->szInstanceName != NULL) {
  1364. dwInstanceLength = 1 + PdhiGetStringLength(
  1365. pCounter->pCounterPath->szInstanceName,
  1366. bUnicode);
  1367. dwInstanceLength *= (bUnicode ? sizeof(WCHAR)
  1368. : sizeof(CHAR));
  1369. dwInstanceLength = DWORD_MULTIPLE(dwInstanceLength);
  1370. dwSizeRequired += dwInstanceLength;
  1371. } else {
  1372. dwInstanceLength = 0;
  1373. }
  1374. if (pCounter->pCounterPath->szParentName != NULL) {
  1375. dwParentLength = 1 + PdhiGetStringLength(
  1376. pCounter->pCounterPath->szParentName,
  1377. bUnicode);
  1378. dwParentLength *= (bUnicode ? sizeof(WCHAR)
  1379. : sizeof(CHAR));
  1380. dwParentLength = DWORD_MULTIPLE(dwParentLength);
  1381. dwSizeRequired += dwParentLength;
  1382. } else {
  1383. dwParentLength = 0;
  1384. }
  1385. dwNameLength = 1 + PdhiGetStringLength(
  1386. pCounter->pCounterPath->szCounterName,
  1387. bUnicode);
  1388. dwNameLength *= (bUnicode ? sizeof(WCHAR)
  1389. : sizeof(CHAR));
  1390. dwNameLength = DWORD_MULTIPLE(dwNameLength);
  1391. dwSizeRequired += dwNameLength;
  1392. if (bRetrieveExplainText) {
  1393. if (pCounter->szExplainText != NULL) {
  1394. dwHelpLength = 1 + PdhiGetStringLength(
  1395. pCounter->szExplainText,
  1396. bUnicode);
  1397. dwHelpLength *= (bUnicode ? sizeof(WCHAR)
  1398. : sizeof(CHAR));
  1399. dwHelpLength = DWORD_MULTIPLE(dwHelpLength);
  1400. } else {
  1401. dwHelpLength = 0;
  1402. }
  1403. dwSizeRequired += dwHelpLength;
  1404. }
  1405. if (dwBufferSize < dwSizeRequired) {
  1406. // either way, no data will be transferred
  1407. Status = PDH_MORE_DATA;
  1408. } else if (lpBuffer != NULL) {
  1409. // should be enough room in the buffer, so continue
  1410. lpBuffer->dwLength = dwSizeRequired;
  1411. lpBuffer->dwType = pCounter->plCounterInfo.dwCounterType;
  1412. lpBuffer->CVersion = pCounter->CVersion;
  1413. lpBuffer->CStatus = pCounter->ThisValue.CStatus;
  1414. lpBuffer->lScale = pCounter->lScale;
  1415. lpBuffer->lDefaultScale = pCounter->plCounterInfo.lDefaultScale;
  1416. lpBuffer->dwUserData = pCounter->dwUserData;
  1417. lpBuffer->dwQueryUserData = pCounter->pOwner->dwUserData;
  1418. // do string data now
  1419. lpBuffer->szFullPath = (LPWSTR)&lpBuffer->DataBuffer[0];
  1420. if (bUnicode) {
  1421. lstrcpyW (lpBuffer->szFullPath, pCounter->szFullName);
  1422. } else {
  1423. WideCharToMultiByte(_getmbcp(),
  1424. 0,
  1425. pCounter->szFullName,
  1426. lstrlenW(pCounter->szFullName),
  1427. (LPSTR) lpBuffer->szFullPath,
  1428. dwPathLength,
  1429. NULL,
  1430. NULL);
  1431. }
  1432. lpBuffer->szMachineName = (LPWSTR)((LPBYTE)lpBuffer->szFullPath +
  1433. dwPathLength);
  1434. if (bUnicode) {
  1435. lstrcpyW (lpBuffer->szMachineName,
  1436. pCounter->pCounterPath->szMachineName);
  1437. } else {
  1438. WideCharToMultiByte(
  1439. _getmbcp(),
  1440. 0,
  1441. pCounter->pCounterPath->szMachineName,
  1442. lstrlenW(pCounter->pCounterPath->szMachineName),
  1443. (LPSTR) lpBuffer->szMachineName,
  1444. dwMachineLength,
  1445. NULL,
  1446. NULL);
  1447. }
  1448. lpBuffer->szObjectName = (LPWSTR)((LPBYTE)lpBuffer->szMachineName +
  1449. dwMachineLength);
  1450. if (bUnicode){
  1451. lstrcpyW (lpBuffer->szObjectName,
  1452. pCounter->pCounterPath->szObjectName);
  1453. } else {
  1454. WideCharToMultiByte(
  1455. _getmbcp(),
  1456. 0,
  1457. pCounter->pCounterPath->szObjectName,
  1458. lstrlenW(pCounter->pCounterPath->szObjectName),
  1459. (LPSTR) lpBuffer->szObjectName,
  1460. dwObjectLength,
  1461. NULL,
  1462. NULL);
  1463. }
  1464. lpBuffer->szInstanceName = (LPWSTR)((LPBYTE)lpBuffer->szObjectName +
  1465. dwObjectLength);
  1466. if (dwInstanceLength > 0) {
  1467. if (bUnicode) {
  1468. lstrcpyW (lpBuffer->szInstanceName,
  1469. pCounter->pCounterPath->szInstanceName);
  1470. } else {
  1471. WideCharToMultiByte(
  1472. _getmbcp(),
  1473. 0,
  1474. pCounter->pCounterPath->szInstanceName,
  1475. lstrlenW(pCounter->pCounterPath->szInstanceName),
  1476. (LPSTR) lpBuffer->szInstanceName,
  1477. dwInstanceLength,
  1478. NULL,
  1479. NULL);
  1480. }
  1481. lpBuffer->szParentInstance = (LPWSTR)((LPBYTE)lpBuffer->szInstanceName +
  1482. dwInstanceLength);
  1483. } else {
  1484. lpBuffer->szParentInstance = lpBuffer->szInstanceName;
  1485. lpBuffer->szInstanceName = NULL;
  1486. }
  1487. if (dwParentLength > 0) {
  1488. if (bUnicode) {
  1489. lstrcpyW (lpBuffer->szParentInstance,
  1490. pCounter->pCounterPath->szParentName);
  1491. } else {
  1492. WideCharToMultiByte(
  1493. _getmbcp(),
  1494. 0,
  1495. pCounter->pCounterPath->szParentName,
  1496. lstrlenW(pCounter->pCounterPath->szParentName),
  1497. (LPSTR) lpBuffer->szParentInstance,
  1498. dwParentLength,
  1499. NULL,
  1500. NULL);
  1501. }
  1502. lpBuffer->szCounterName = (LPWSTR)((LPBYTE)lpBuffer->szParentInstance +
  1503. dwParentLength);
  1504. } else {
  1505. lpBuffer->szCounterName = lpBuffer->szParentInstance;
  1506. lpBuffer->szParentInstance = NULL;
  1507. }
  1508. lpBuffer->dwInstanceIndex = pCounter->pCounterPath->dwIndex;
  1509. if (bUnicode) {
  1510. lstrcpyW (lpBuffer->szCounterName,
  1511. pCounter->pCounterPath->szCounterName);
  1512. } else {
  1513. WideCharToMultiByte(
  1514. _getmbcp(),
  1515. 0,
  1516. pCounter->pCounterPath->szCounterName,
  1517. lstrlenW(pCounter->pCounterPath->szCounterName),
  1518. (LPSTR) lpBuffer->szCounterName,
  1519. dwNameLength,
  1520. NULL,
  1521. NULL);
  1522. }
  1523. if ((pCounter->szExplainText != NULL) && bRetrieveExplainText) {
  1524. // copy explain text
  1525. lpBuffer->szExplainText = (LPWSTR)((LPBYTE)lpBuffer->szCounterName +
  1526. dwNameLength);
  1527. if (bUnicode) {
  1528. lstrcpyW (lpBuffer->szExplainText, pCounter->szExplainText);
  1529. } else {
  1530. WideCharToMultiByte(
  1531. _getmbcp(),
  1532. 0,
  1533. pCounter->szExplainText,
  1534. lstrlenW(pCounter->szExplainText),
  1535. (LPSTR) lpBuffer->szExplainText,
  1536. dwHelpLength,
  1537. NULL,
  1538. NULL);
  1539. }
  1540. } else {
  1541. lpBuffer->szExplainText = NULL;
  1542. }
  1543. }
  1544. __try {
  1545. * pdwBufferSize = dwSizeRequired;
  1546. }
  1547. __except (EXCEPTION_EXECUTE_HANDLER) {
  1548. Status = PDH_INVALID_ARGUMENT;
  1549. }
  1550. }
  1551. RELEASE_MUTEX(pCounter->pOwner->hMutex);
  1552. }
  1553. }
  1554. RELEASE_MUTEX (hPdhDataMutex);
  1555. }
  1556. return Status;
  1557. }
  1558. PDH_FUNCTION
  1559. PdhGetCounterInfoW (
  1560. IN HCOUNTER hCounter,
  1561. IN BOOLEAN bRetrieveExplainText,
  1562. IN LPDWORD pdwBufferSize,
  1563. IN PPDH_COUNTER_INFO_W lpBuffer
  1564. )
  1565. /*++
  1566. Routine Description:
  1567. Examines the specified counter and returns the configuration and
  1568. status information of the counter.
  1569. Arguments:
  1570. IN HCOUNTER hCounter
  1571. Handle to the desired counter.
  1572. IN BOOLEAN bRetrieveExplainText
  1573. TRUE will fill in the explain text structure
  1574. FALSE will return a null pointer in the explain text
  1575. IN LPDWORD pcchBufferSize
  1576. The address of the buffer that contains the size of the data buffer
  1577. passed by the caller. On entry, the value in the buffer is the
  1578. size of the data buffer in bytes. On return, this value is the size
  1579. of the buffer returned. If the buffer is not large enough, then
  1580. this value is the size that the buffer needs to be in order to
  1581. hold the requested data.
  1582. IN LPPDH_COUNTER_INFO_W lpBuffer
  1583. the pointer to the data buffer passed by the caller to receive
  1584. the data requested.
  1585. Return Value:
  1586. The WIN32 Error status of the function's operation. Common values
  1587. returned are:
  1588. ERROR_SUCCESS when all requested data is returned
  1589. PDH_MORE_DATA when the buffer passed by the caller is too small
  1590. PDH_INVALID_HANDLE if the handle is not recognized as valid
  1591. PDH_INVALID_ARGUMENT if an argument is invalid or incorrect
  1592. --*/
  1593. {
  1594. return PdhiGetCounterInfo (
  1595. hCounter,
  1596. bRetrieveExplainText,
  1597. pdwBufferSize,
  1598. lpBuffer,
  1599. TRUE);
  1600. }
  1601. PDH_FUNCTION
  1602. PdhGetCounterInfoA (
  1603. IN HCOUNTER hCounter,
  1604. IN BOOLEAN bRetrieveExplainText,
  1605. IN LPDWORD pdwBufferSize,
  1606. IN PPDH_COUNTER_INFO_A lpBuffer
  1607. )
  1608. /*++
  1609. Routine Description:
  1610. Examines the specified counter and returns the configuration and
  1611. status information of the counter.
  1612. Arguments:
  1613. IN HCOUNTER hCounter
  1614. Handle to the desired counter.
  1615. IN BOOLEAN bRetrieveExplainText
  1616. TRUE will fill in the explain text structure
  1617. FALSE will return a null pointer in the explain text
  1618. IN LPDWORD pcchBufferSize
  1619. The address of the buffer that contains the size of the data buffer
  1620. passed by the caller. On entry, the value in the buffer is the
  1621. size of the data buffer in bytes. On return, this value is the size
  1622. of the buffer returned. If the buffer is not large enough, then
  1623. this value is the size that the buffer needs to be in order to
  1624. hold the requested data.
  1625. IN LPPDH_COUNTER_INFO_A lpBuffer
  1626. the pointer to the data buffer passed by the caller to receive
  1627. the data requested.
  1628. Return Value:
  1629. The WIN32 Error status of the function's operation. Common values
  1630. returned are:
  1631. ERROR_SUCCESS when all requested data is returned
  1632. PDH_MORE_DATA when the buffer passed by the caller is too small
  1633. PDH_INVALID_HANDLE if the handle is not recognized as valid
  1634. PDH_INVALID_ARGUMENT if an argument is invalid or incorrect
  1635. --*/
  1636. {
  1637. return PdhiGetCounterInfo (
  1638. hCounter,
  1639. bRetrieveExplainText,
  1640. pdwBufferSize,
  1641. (PPDH_COUNTER_INFO_W) lpBuffer,
  1642. FALSE);
  1643. }
  1644. PDH_FUNCTION
  1645. PdhSetCounterScaleFactor (
  1646. IN HCOUNTER hCounter,
  1647. IN LONG lFactor
  1648. )
  1649. /*++
  1650. Routine Description:
  1651. sets the counter multiplication scale factor used in computing formatted
  1652. counter values. The legal range of values is -7 to +7 which equates
  1653. to a factor of .0000007 to 10,000,000.
  1654. Arguments:
  1655. IN HCOUNTER hCounter
  1656. handle of the counter to update
  1657. IN LONG lFactor
  1658. integer value of the exponent of the factor (i.e. the multiplier is
  1659. 10 ** lFactor.)
  1660. Return Value:
  1661. The WIN32 Error status of the function's operation. Common values
  1662. returned are:
  1663. ERROR_SUCCESS when all requested data is returned
  1664. PDH_INVALID_ARGUMENT if the scale value is out of range
  1665. PDH_INVALID_HANDLE if the handle is not recognized as valid
  1666. --*/
  1667. {
  1668. PPDHI_COUNTER pCounter;
  1669. PDH_STATUS retStatus = ERROR_SUCCESS;
  1670. retStatus = WAIT_FOR_AND_LOCK_MUTEX (hPdhDataMutex);
  1671. if (retStatus == ERROR_SUCCESS) {
  1672. if (!IsValidCounter(hCounter)) {
  1673. // not a valid counter
  1674. retStatus = PDH_INVALID_HANDLE;
  1675. } else if ((lFactor > PDH_MAX_SCALE) || (lFactor < PDH_MIN_SCALE)) {
  1676. retStatus = PDH_INVALID_ARGUMENT;
  1677. } else if (!CounterIsOkToUse(hCounter)) {
  1678. retStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
  1679. } else {
  1680. pCounter = (PPDHI_COUNTER)hCounter;
  1681. retStatus = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
  1682. if (retStatus == ERROR_SUCCESS) {
  1683. pCounter->lScale = lFactor;
  1684. RELEASE_MUTEX(pCounter->pOwner->hMutex);
  1685. retStatus = ERROR_SUCCESS;
  1686. }
  1687. }
  1688. RELEASE_MUTEX (hPdhDataMutex);
  1689. }
  1690. return retStatus;
  1691. }
  1692. #pragma optimize ("", off)
  1693. PDH_FUNCTION
  1694. PdhGetCounterTimeBase (
  1695. IN HCOUNTER hCounter,
  1696. IN LONGLONG *pTimeBase
  1697. )
  1698. /*++
  1699. Routine Description:
  1700. retrieves the value of the timebase used in the computation
  1701. of the formatted version of this counter.
  1702. Arguments:
  1703. IN HCOUNTER hCounter
  1704. handle of the counter to query
  1705. IN LONGLONG pTimeBase
  1706. pointer to the longlong value that will receive the value of the
  1707. timebase used by the counter. The Timebase is the frequency of the
  1708. timer used to measure the specified.
  1709. Return Value:
  1710. The WIN32 Error status of the function's operation. Common values
  1711. returned are:
  1712. ERROR_SUCCESS when all requested data is returned
  1713. PDH_INVALID_ARGUMENT if the scale value is out of range
  1714. PDH_INVALID_HANDLE if the handle is not recognized as valid
  1715. --*/
  1716. {
  1717. PPDHI_COUNTER pCounter;
  1718. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1719. if (pTimeBase != NULL) {
  1720. if (IsValidCounter(hCounter)) {
  1721. if (!CounterIsOkToUse (hCounter)) {
  1722. pdhStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
  1723. }
  1724. else {
  1725. pCounter = (PPDHI_COUNTER)hCounter;
  1726. try {
  1727. LONGLONG volatile llTimeBase;
  1728. // test read/write access
  1729. llTimeBase = *pTimeBase; // TODO: Why need to read
  1730. * pTimeBase = 0; // TODO: redundant
  1731. * pTimeBase = pCounter->TimeBase;
  1732. } except (EXCEPTION_EXECUTE_HANDLER) {
  1733. pdhStatus = PDH_INVALID_ARGUMENT;
  1734. }
  1735. }
  1736. } else {
  1737. pdhStatus = PDH_INVALID_HANDLE;
  1738. }
  1739. } else {
  1740. pdhStatus = PDH_INVALID_ARGUMENT;
  1741. }
  1742. return pdhStatus;
  1743. }
  1744. #pragma optimize ("", on)