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.

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