Leaked source code of windows server 2003

1872 lines
84 KiB

  1. /*++
  2. Copyright (C) 1995-1999 Microsoft Corporation
  3. Module Name:
  4. cutils.c
  5. Abstract:
  6. Counter management utility functions
  7. --*/
  8. #include <windows.h>
  9. #include <math.h>
  10. #include "strsafe.h"
  11. #include <pdh.h>
  12. #include "pdhitype.h"
  13. #include "pdhidef.h"
  14. #include "perftype.h"
  15. #include "perfdata.h"
  16. #include "pdhmsg.h"
  17. #include "strings.h"
  18. BOOL
  19. IsValidCounter(
  20. HCOUNTER hCounter
  21. )
  22. /*++
  23. Routine Description:
  24. examines the counter handle to verify it is a valid counter. For now
  25. the test amounts to:
  26. the Handle is NOT NULL
  27. the memory is accessible (i.e. it doesn't AV)
  28. the signature array is valid
  29. the size field is correct
  30. if any tests fail, the handle is presumed to be invalid
  31. Arguments:
  32. IN HCOUNTER hCounter
  33. the handle of the counter to test
  34. Return Value:
  35. TRUE the handle passes all the tests
  36. FALSE one of the test's failed and the handle is not a valid counter
  37. --*/
  38. {
  39. BOOL bReturn = FALSE; // assume it's not a valid query
  40. PPDHI_COUNTER pCounter;
  41. LONG lStatus = ERROR_SUCCESS;
  42. __try {
  43. if (hCounter != NULL) {
  44. // see if a valid signature
  45. pCounter = (PPDHI_COUNTER) hCounter;
  46. if ((* (DWORD *) & pCounter->signature[0] == SigCounter) &&
  47. (pCounter->dwLength == sizeof (PDHI_COUNTER))) {
  48. bReturn = TRUE;
  49. }
  50. }
  51. }
  52. __except (EXCEPTION_EXECUTE_HANDLER) {
  53. // something failed miserably so we can assume this is invalid
  54. lStatus = GetExceptionCode();
  55. }
  56. return bReturn;
  57. }
  58. BOOL
  59. InitCounter(
  60. PPDHI_COUNTER pCounter
  61. )
  62. /*++
  63. Routine Description:
  64. Initialized the counter data structure by:
  65. Allocating the memory block to contain the counter structure
  66. and all the associated data fields. If this allocation
  67. is successful, then the fields are initialized by
  68. verifying the counter is valid.
  69. Arguments:
  70. IN PPDHI_COUNTER pCounter
  71. pointer of the counter to initialize using the system data
  72. Return Value:
  73. TRUE if the counter was successfully initialized
  74. FALSE if a problem was encountered
  75. In either case, the CStatus field of the structure is updated to
  76. indicate the status of the operation.
  77. --*/
  78. {
  79. PPERF_MACHINE pMachine = NULL;
  80. DWORD dwBufferSize = MEDIUM_BUFFER_SIZE;
  81. DWORD dwOldSize;
  82. BOOL bInstances = FALSE;
  83. LPVOID pLocalCounterPath = NULL;
  84. BOOL bReturn = TRUE;
  85. LONG lOffset;
  86. // reset the last error value
  87. pCounter->ThisValue.CStatus = ERROR_SUCCESS;
  88. SetLastError(ERROR_SUCCESS);
  89. if (pCounter->szFullName != NULL) {
  90. // allocate counter path buffer
  91. if (pCounter->pCounterPath != NULL) {
  92. __try {
  93. G_FREE(pCounter->pCounterPath);
  94. }
  95. __except (EXCEPTION_EXECUTE_HANDLER) {
  96. // no need to do anything
  97. }
  98. pCounter->pCounterPath = NULL;
  99. }
  100. pLocalCounterPath = G_ALLOC(dwBufferSize);
  101. if (pLocalCounterPath == NULL) {
  102. // could not allocate string buffer
  103. pCounter->ThisValue.CStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  104. bReturn = FALSE;
  105. }
  106. else {
  107. dwOldSize = dwBufferSize;
  108. if (ParseFullPathNameW(pCounter->szFullName, & dwBufferSize, pLocalCounterPath, FALSE)) {
  109. // resize to only the space required
  110. if (dwOldSize < dwBufferSize) {
  111. pCounter->pCounterPath = G_REALLOC(pLocalCounterPath, dwBufferSize);
  112. }
  113. else {
  114. pCounter->pCounterPath = pLocalCounterPath;
  115. }
  116. if (pCounter->pCounterPath != NULL) {
  117. if (pLocalCounterPath != pCounter->pCounterPath) { // ???
  118. // the memory block moved so
  119. // correct addresses inside structure
  120. lOffset = (LONG) ((ULONG_PTR) pCounter->pCounterPath - (ULONG_PTR) pLocalCounterPath);
  121. if (lOffset != 0 && pCounter->pCounterPath->szMachineName != NULL) {
  122. pCounter->pCounterPath->szMachineName = (LPWSTR) (
  123. (LPBYTE)pCounter->pCounterPath->szMachineName + lOffset);
  124. }
  125. if (lOffset != 0 && pCounter->pCounterPath->szObjectName != NULL) {
  126. pCounter->pCounterPath->szObjectName = (LPWSTR) (
  127. (LPBYTE)pCounter->pCounterPath->szObjectName + lOffset);
  128. }
  129. if (lOffset != 0 && pCounter->pCounterPath->szInstanceName != NULL) {
  130. pCounter->pCounterPath->szInstanceName = (LPWSTR) (
  131. (LPBYTE)pCounter->pCounterPath->szInstanceName + lOffset);
  132. }
  133. if (lOffset != 0 && pCounter->pCounterPath->szParentName != NULL) {
  134. pCounter->pCounterPath->szParentName = (LPWSTR) (
  135. (LPBYTE)pCounter->pCounterPath->szParentName + lOffset);
  136. }
  137. if (lOffset != 0 && pCounter->pCounterPath->szCounterName != NULL) {
  138. pCounter->pCounterPath->szCounterName = (LPWSTR) (
  139. (LPBYTE)pCounter->pCounterPath->szCounterName + lOffset);
  140. }
  141. }
  142. if (pCounter->pOwner->hLog == NULL) {
  143. // validate realtime counter
  144. // try to connect to machine and get machine pointer
  145. pMachine = GetMachine(pCounter->pCounterPath->szMachineName, 0, PDH_GM_UPDATE_PERFNAME_ONLY);
  146. if (pMachine == NULL) {
  147. // unable to find machine
  148. pCounter->ThisValue.CStatus = PDH_CSTATUS_NO_MACHINE;
  149. pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
  150. bReturn = FALSE;
  151. }
  152. else if (pMachine->szPerfStrings == NULL || pMachine->typePerfStrings == NULL) {
  153. // a machine entry was found, but the machine is not available
  154. pMachine->dwRefCount --;
  155. RELEASE_MUTEX(pMachine->hMutex);
  156. pCounter->ThisValue.CStatus = pMachine->dwStatus;
  157. if (pMachine->dwStatus == PDH_ACCESS_DENIED) {
  158. // then don't add this counter since the machine
  159. // won't let us in
  160. bReturn = FALSE;
  161. }
  162. }
  163. else {
  164. // init raw counter value
  165. ZeroMemory(& pCounter->ThisValue, sizeof(PDH_RAW_COUNTER));
  166. ZeroMemory(& pCounter->LastValue, sizeof(PDH_RAW_COUNTER));
  167. // look up object name
  168. pCounter->plCounterInfo.dwObjectId = GetObjectId(pMachine,
  169. pCounter->pCounterPath->szObjectName,
  170. & bInstances);
  171. if (pCounter->plCounterInfo.dwObjectId == (DWORD) -1) {
  172. // unable to lookup object on this machine
  173. pCounter->plCounterInfo.dwObjectId = (DWORD) -1;
  174. pCounter->ThisValue.CStatus = PDH_CSTATUS_NO_OBJECT;
  175. pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
  176. bReturn = FALSE;
  177. }
  178. else {
  179. // update instanceName look up instances if necessary
  180. if (bInstances) {
  181. if (pCounter->pCounterPath->szInstanceName != NULL) {
  182. if (* pCounter->pCounterPath->szInstanceName != SPLAT_L) {
  183. if (! GetInstanceByNameMatch(pMachine, pCounter)) {
  184. // unable to lookup instance
  185. pCounter->ThisValue.CStatus = PDH_CSTATUS_NO_INSTANCE;
  186. // keep the counter since the instance may return
  187. }
  188. }
  189. else {
  190. // this is a wild card query so don't look
  191. // for any instances yet
  192. pCounter->dwFlags |= PDHIC_MULTI_INSTANCE;
  193. }
  194. }
  195. else {
  196. // the path for this object should include an instance name
  197. // and doesn't so return an error
  198. // this is an unrecoverable error so indicate that it's finished
  199. //
  200. pCounter->ThisValue.CStatus = PDH_CSTATUS_BAD_COUNTERNAME;
  201. pCounter->dwFlags &= ~PDHIC_COUNTER_NOT_INIT;
  202. pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
  203. bReturn = FALSE;
  204. }
  205. }
  206. pCounter->dwFlags &= ~PDHIC_COUNTER_NOT_INIT;
  207. }
  208. pMachine->dwRefCount --;
  209. RELEASE_MUTEX(pMachine->hMutex);
  210. if (bReturn) {
  211. // look up counter
  212. if (*pCounter->pCounterPath->szCounterName != SPLAT_L) {
  213. pCounter->plCounterInfo.dwCounterId = GetCounterId(
  214. pMachine,
  215. pCounter->plCounterInfo.dwObjectId,
  216. pCounter->pCounterPath->szCounterName);
  217. if (pCounter->plCounterInfo.dwCounterId != (DWORD) -1) {
  218. // load and initialize remaining counter values
  219. if (AddMachineToQueryLists(pMachine, pCounter)) {
  220. if (InitPerflibCounterInfo(pCounter)) {
  221. // assign the appropriate calculation function
  222. bReturn = AssignCalcFunction(
  223. pCounter->plCounterInfo.dwCounterType,
  224. & pCounter->CalcFunc,
  225. & pCounter->StatFunc);
  226. TRACE((PDH_DBG_TRACE_INFO),
  227. (__LINE__,
  228. PDH_CUTILS,
  229. ARG_DEF(ARG_TYPE_WSTR, 1),
  230. ERROR_SUCCESS,
  231. TRACE_WSTR(pCounter->szFullName),
  232. TRACE_DWORD(pCounter->plCounterInfo.dwCounterType),
  233. NULL));
  234. if (! bReturn) {
  235. pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
  236. }
  237. }
  238. else {
  239. // unable to initialize this counter
  240. pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
  241. bReturn = FALSE;
  242. }
  243. }
  244. else {
  245. // machine could not be added, error is already
  246. // in "LastError" so free string buffer and leave
  247. pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
  248. bReturn = FALSE;
  249. }
  250. }
  251. else {
  252. // unable to lookup counter
  253. pCounter->ThisValue.CStatus = PDH_CSTATUS_NO_COUNTER;
  254. pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
  255. bReturn = FALSE;
  256. }
  257. }
  258. else {
  259. if (AddMachineToQueryLists(pMachine, pCounter)) {
  260. pCounter->dwFlags |= PDHIC_COUNTER_OBJECT;
  261. pCounter->pThisObject = NULL;
  262. pCounter->pLastObject = NULL;
  263. }
  264. else {
  265. // machine could not be added, error is already
  266. // in "LastError" so free string buffer and leave
  267. pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
  268. bReturn = FALSE;
  269. }
  270. }
  271. }
  272. }
  273. }
  274. else {
  275. PDH_STATUS pdhStatus;
  276. // validate counter from log file
  277. pdhStatus = PdhiGetLogCounterInfo(pCounter->pOwner->hLog, pCounter);
  278. if (pdhStatus == ERROR_SUCCESS) {
  279. // finish initializing the counter
  280. //
  281. pCounter->ThisValue.TimeStamp.dwLowDateTime = 0;
  282. pCounter->ThisValue.TimeStamp.dwHighDateTime = 0;
  283. pCounter->ThisValue.MultiCount = 1;
  284. pCounter->ThisValue.FirstValue = 0;
  285. pCounter->ThisValue.SecondValue = 0;
  286. //
  287. pCounter->LastValue.TimeStamp.dwLowDateTime = 0;
  288. pCounter->LastValue.TimeStamp.dwHighDateTime = 0;
  289. pCounter->LastValue.MultiCount = 1;
  290. pCounter->LastValue.FirstValue = 0;
  291. pCounter->LastValue.SecondValue = 0;
  292. //
  293. // lastly update status
  294. //
  295. pCounter->ThisValue.CStatus = PDH_CSTATUS_VALID_DATA;
  296. pCounter->LastValue.CStatus = PDH_CSTATUS_VALID_DATA;
  297. // assign the appropriate calculation function
  298. bReturn = AssignCalcFunction(pCounter->plCounterInfo.dwCounterType,
  299. & pCounter->CalcFunc,
  300. & pCounter->StatFunc);
  301. TRACE((PDH_DBG_TRACE_INFO),
  302. (__LINE__,
  303. PDH_CUTILS,
  304. ARG_DEF(ARG_TYPE_WSTR, 1),
  305. ERROR_SUCCESS,
  306. TRACE_WSTR(pCounter->szFullName),
  307. TRACE_DWORD(pCounter->plCounterInfo.dwCounterType),
  308. NULL));
  309. }
  310. else {
  311. // set the counter status to the error returned
  312. pCounter->ThisValue.CStatus = pdhStatus;
  313. pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
  314. bReturn = FALSE;
  315. }
  316. pCounter->dwFlags &= ~PDHIC_COUNTER_NOT_INIT;
  317. }
  318. if (! bReturn) {
  319. //free string buffer
  320. G_FREE(pCounter->pCounterPath);
  321. pCounter->pCounterPath = NULL;
  322. }
  323. }
  324. else {
  325. G_FREE(pLocalCounterPath);
  326. // unable to realloc
  327. pCounter->ThisValue.CStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  328. bReturn = FALSE;
  329. }
  330. }
  331. else {
  332. // unable to parse counter name
  333. pCounter->ThisValue.CStatus = PDH_CSTATUS_BAD_COUNTERNAME;
  334. pCounter->dwFlags &= ~PDHIC_COUNTER_NOT_INIT;
  335. pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
  336. G_FREE(pLocalCounterPath);
  337. bReturn = FALSE;
  338. }
  339. }
  340. }
  341. else {
  342. // no counter name
  343. pCounter->ThisValue.CStatus = PDH_CSTATUS_NO_COUNTERNAME;
  344. pCounter->dwFlags &= ~PDHIC_COUNTER_NOT_INIT;
  345. pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
  346. bReturn = FALSE;
  347. }
  348. if (! bReturn && pCounter->ThisValue.CStatus != ERROR_SUCCESS) {
  349. SetLastError(pCounter->ThisValue.CStatus);
  350. }
  351. return bReturn;
  352. }
  353. BOOL
  354. ParseInstanceName(
  355. LPCWSTR szInstanceString,
  356. LPWSTR szInstanceName,
  357. LPWSTR szParentName,
  358. DWORD dwName,
  359. LPDWORD lpIndex
  360. )
  361. /*
  362. parses the instance name formatted as follows
  363. [parent/]instance[#index]
  364. parent is optional and if present, is delimited by a forward slash
  365. index is optional and if present, is delimited by a colon
  366. parent and instance may be any legal file name character except a
  367. delimeter character "/#\()" Index must be a string composed of
  368. decimal digit characters (0-9), less than 10 characters in length, and
  369. equate to a value between 0 and 2**32-1 (inclusive).
  370. This function assumes that the instance name and parent name buffers
  371. are of sufficient size.
  372. NOTE: szInstanceName and szInstanceString can be the same buffer
  373. */
  374. {
  375. LPWSTR szSrcChar = (LPWSTR) szInstanceString;
  376. LPWSTR szDestChar = (LPWSTR) szInstanceName;
  377. LPWSTR szLastPound = NULL;
  378. BOOL bReturn = FALSE;
  379. DWORD dwIndex = 0;
  380. DWORD dwInstCount = 0;
  381. szDestChar = (LPWSTR) szInstanceName;
  382. szSrcChar = (LPWSTR) szInstanceString;
  383. __try {
  384. do {
  385. * szDestChar = * szSrcChar;
  386. if (* szDestChar == POUNDSIGN_L) szLastPound = szDestChar;
  387. szDestChar ++;
  388. szSrcChar ++;
  389. dwInstCount ++;
  390. }
  391. while (dwInstCount <= dwName && (* szSrcChar != L'\0') && (* szSrcChar != SLASH_L));
  392. if (dwInstCount <= dwName) {
  393. // see if that was really the parent or not
  394. if (* szSrcChar == SLASH_L) {
  395. // terminate destination after test in case they are the same buffer
  396. * szDestChar = L'\0';
  397. szSrcChar ++; // and move source pointer past delimter
  398. // it was the parent name so copy it to the parent
  399. StringCchCopyW(szParentName, dwName, szInstanceName);
  400. // and copy the rest of the string after the "/" to the
  401. // instance name field
  402. szDestChar = szInstanceName;
  403. dwInstCount = 0;
  404. do {
  405. * szDestChar = * szSrcChar;
  406. if (* szDestChar == POUNDSIGN_L) szLastPound = szDestChar;
  407. szDestChar ++;
  408. szSrcChar ++;
  409. dwInstCount ++;
  410. }
  411. while (dwInstCount <= dwName && (* szSrcChar != L'\0'));
  412. }
  413. else {
  414. // that was the only element so load an empty string for the parent
  415. * szParentName = L'\0';
  416. }
  417. if (dwInstCount <= dwName) {
  418. // if szLastPound is NOT null and is inside the instance string, then
  419. // see if it points to a decimal number. If it does, then it's an index
  420. // otherwise it's part of the instance name
  421. * szDestChar = L'\0'; // terminate the destination string
  422. dwIndex = 0;
  423. if (szLastPound != NULL) {
  424. if (szLastPound > szInstanceName) {
  425. // there's a pound sign in the instance name
  426. // see if it's preceded by a non-space char
  427. szLastPound --;
  428. if (* szLastPound > SPACE_L) {
  429. szLastPound ++;
  430. // see if it's followed by a digit
  431. szLastPound ++;
  432. if ((* szLastPound >= L'0') && (*szLastPound <= L'9')) {
  433. dwIndex = wcstoul(szLastPound, NULL, 10);
  434. szLastPound --;
  435. * szLastPound = L'\0'; // terminate the name at the pound sign
  436. }
  437. }
  438. }
  439. }
  440. * lpIndex = dwIndex;
  441. bReturn = TRUE;
  442. }
  443. }
  444. }
  445. __except (EXCEPTION_EXECUTE_HANDLER) {
  446. // unable to move strings
  447. bReturn = FALSE;
  448. }
  449. return bReturn;
  450. }
  451. BOOL
  452. ParseFullPathNameW(
  453. LPCWSTR szFullCounterPath,
  454. PDWORD pdwBufferSize,
  455. PPDHI_COUNTER_PATH pCounter,
  456. BOOL bWbemSyntax
  457. )
  458. /*
  459. interprets counter path string as either a
  460. \\machine\object(instance)\counter
  461. or if bWbemSyntax == TRUE
  462. \\machine\namespace:ClassName(InstanceName)\CounterName
  463. and returns the component in the counter path structure
  464. \\machine or \\machine\namespace may be omitted on the local machine
  465. (instance) may be omitted on counters with no instance structures
  466. if object or counter is missing, then FALSE is returned, otherwise
  467. TRUE is returned if the parsing was successful
  468. */
  469. {
  470. LPWSTR szWorkMachine = NULL;
  471. LPWSTR szWorkObject = NULL;
  472. LPWSTR szWorkInstance = NULL;
  473. LPWSTR szWorkParent = NULL;
  474. LPWSTR szWorkCounter = NULL;
  475. DWORD dwBufferSize = lstrlenW(szFullCounterPath) + 1;
  476. BOOL bReturn = FALSE;
  477. LPWSTR szSrcChar, szDestChar;
  478. DWORD dwBufferLength = 0;
  479. DWORD dwWorkMachineLength = 0;
  480. DWORD dwWorkObjectLength = 0;
  481. DWORD dwWorkInstanceLength = 0;
  482. DWORD dwWorkParentLength = 0;
  483. DWORD dwWorkCounterLength = 0;
  484. DWORD dwWorkIndex = 0;
  485. DWORD dwParenDepth = 0;
  486. WCHAR wDelimiter = 0;
  487. LPWSTR pszBsDelim[2] = {0,0};
  488. LPWSTR szThisChar;
  489. DWORD dwParenCount = 0;
  490. LPWSTR szLastParen = NULL;
  491. if (dwBufferSize < MAX_PATH) dwBufferSize = MAX_PATH;
  492. szWorkMachine = G_ALLOC(dwBufferSize * sizeof(WCHAR));
  493. szWorkObject = G_ALLOC(dwBufferSize * sizeof(WCHAR));
  494. szWorkInstance = G_ALLOC(dwBufferSize * sizeof(WCHAR));
  495. szWorkParent = G_ALLOC(dwBufferSize * sizeof(WCHAR));
  496. szWorkCounter = G_ALLOC(dwBufferSize * sizeof(WCHAR));
  497. if (szWorkMachine != NULL && szWorkObject != NULL && szWorkInstance != NULL
  498. && szWorkParent != NULL && szWorkCounter != NULL) {
  499. // get machine name from counter path
  500. szSrcChar = (LPWSTR) szFullCounterPath;
  501. //define the delimiter char between the machine and the object
  502. // or in WBEM parlance, the server & namespace and the Class name
  503. if (bWbemSyntax) {
  504. wDelimiter = COLON_L;
  505. }
  506. else {
  507. wDelimiter = BACKSLASH_L;
  508. // if this is backslash delimited string, then find the
  509. // backslash the denotes the end of the machine and start of the
  510. // object by walking down the string and finding the 2nd to the last
  511. // backslash.
  512. // this is necessary since a WBEM machine\namespace path can have
  513. // multiple backslashes in it while there will ALWAYS be two at
  514. // the end, one at the start of the object name and one at the start
  515. // of the counter name
  516. dwParenDepth = 0;
  517. for (szThisChar = szSrcChar; * szThisChar != L'\0'; szThisChar++) {
  518. if (* szThisChar == LEFTPAREN_L) {
  519. if (dwParenDepth == 0) dwParenCount ++;
  520. dwParenDepth ++;
  521. }
  522. else if (* szThisChar == RIGHTPAREN_L) {
  523. if (dwParenDepth > 0) dwParenDepth --;
  524. }
  525. else {
  526. if (dwParenDepth == 0) {
  527. // ignore delimiters inside parenthesis
  528. if (* szThisChar == wDelimiter) {
  529. pszBsDelim[0] = pszBsDelim[1];
  530. pszBsDelim[1] = szThisChar;
  531. }
  532. // ignore it and go to the next character
  533. }
  534. }
  535. }
  536. if ((dwParenCount > 0) && (pszBsDelim[0] != NULL) && (pszBsDelim[1] != NULL)) {
  537. dwParenDepth = 0;
  538. for (szThisChar = pszBsDelim[0]; ((* szThisChar != L'\0') && (szThisChar < pszBsDelim[1])); szThisChar ++) {
  539. if (* szThisChar == LEFTPAREN_L) {
  540. if (dwParenDepth == 0) {
  541. // see if the preceeding char is whitespace
  542. -- szThisChar;
  543. if (* szThisChar > SPACE_L) {
  544. // then this could be an instance delim
  545. szLastParen = ++ szThisChar;
  546. }
  547. else {
  548. // else it's probably part of the instance name
  549. ++ szThisChar;
  550. }
  551. }
  552. dwParenDepth ++;
  553. }
  554. else if (* szThisChar == RIGHTPAREN_L) {
  555. if (dwParenDepth > 0) dwParenDepth --;
  556. }
  557. }
  558. }
  559. }
  560. // see if this is really a machine name by looking for leading "\\"
  561. if ((szSrcChar[0] == BACKSLASH_L) && (szSrcChar[1] == BACKSLASH_L)) {
  562. szDestChar = szWorkMachine;
  563. * szDestChar ++ = * szSrcChar ++;
  564. * szDestChar ++ = * szSrcChar ++;
  565. dwWorkMachineLength = 2;
  566. // must be a machine name so find the object delimiter and zero terminate
  567. // it there
  568. while (* szSrcChar != L'\0') {
  569. if (pszBsDelim[0] != NULL) {
  570. // then go to this pointer
  571. if (szSrcChar == pszBsDelim[0]) break;
  572. }
  573. else {
  574. // go to the next delimiter
  575. if (* szSrcChar != wDelimiter) break;
  576. }
  577. * szDestChar ++ = * szSrcChar ++;
  578. dwWorkMachineLength ++;
  579. }
  580. if (* szSrcChar == L'\0') {
  581. // no other required fields
  582. goto Cleanup;
  583. }
  584. else {
  585. // null terminate and continue
  586. * szDestChar ++ = L'\0';
  587. }
  588. }
  589. else {
  590. // no machine name, so they must have skipped that field
  591. // which is OK. We'll insert the local machine name here
  592. StringCchCopyW(szWorkMachine, dwBufferSize, szStaticLocalMachineName);
  593. dwWorkMachineLength = lstrlenW(szWorkMachine);
  594. }
  595. // szSrcChar should be pointing to the backslash preceeding the
  596. // object name now.
  597. if (szSrcChar[0] == wDelimiter) {
  598. szSrcChar ++; // to move past backslash
  599. szDestChar = szWorkObject;
  600. // copy until:
  601. // a) the end of the source string is reached
  602. // b) the instance delimiter is found "("
  603. // c) the counter delimiter is found "\"
  604. // d) a non-printable, non-space char is found
  605. while ((* szSrcChar != L'\0') && (szSrcChar != szLastParen)
  606. && (* szSrcChar != BACKSLASH_L) && (* szSrcChar >= SPACE_L)) {
  607. dwWorkObjectLength ++;
  608. * szDestChar ++ = * szSrcChar ++;
  609. }
  610. // see why it ended:
  611. if (* szSrcChar < SPACE_L) {
  612. // ran of source string
  613. goto Cleanup;
  614. }
  615. else if (szSrcChar == szLastParen) {
  616. dwParenDepth = 1;
  617. // there's an instance so copy that to the instance field
  618. * szDestChar = L'\0'; // terminate destination string
  619. szDestChar = szWorkInstance;
  620. // skip past open paren
  621. ++ szSrcChar;
  622. // copy until:
  623. // a) the end of the source string is reached
  624. // b) the instance delimiter is found "("
  625. while ((* szSrcChar != L'\0') && (dwParenDepth > 0)) {
  626. if (* szSrcChar == RIGHTPAREN_L) {
  627. dwParenDepth --;
  628. }
  629. else if (* szSrcChar == LEFTPAREN_L) {
  630. dwParenDepth ++;
  631. }
  632. if (dwParenDepth > 0) {
  633. // copy all parenthesis except the last one
  634. dwWorkInstanceLength ++;
  635. * szDestChar ++ = * szSrcChar ++;
  636. }
  637. }
  638. // see why it ended:
  639. if (* szSrcChar == L'\0') {
  640. // ran of source string
  641. goto Cleanup;
  642. }
  643. else {
  644. // move source to object delimiter
  645. if (* ++ szSrcChar != BACKSLASH_L) {
  646. // bad format
  647. goto Cleanup;
  648. }
  649. else {
  650. * szDestChar = L'\0';
  651. // check instance string for a parent
  652. if (ParseInstanceName(
  653. szWorkInstance, szWorkInstance, szWorkParent, dwBufferSize, & dwWorkIndex)) {
  654. dwWorkInstanceLength = lstrlenW(szWorkInstance);
  655. dwWorkParentLength = lstrlenW(szWorkParent);
  656. }
  657. else {
  658. // instance string not formatted correctly
  659. goto Cleanup;
  660. }
  661. }
  662. }
  663. }
  664. else {
  665. // terminate the destination string
  666. * szDestChar = L'\0';
  667. }
  668. // finally copy the counter name
  669. szSrcChar ++; // to move past backslash
  670. szDestChar = szWorkCounter;
  671. // copy until:
  672. // a) the end of the source string is reached
  673. while (* szSrcChar != L'\0') {
  674. dwWorkCounterLength ++;
  675. * szDestChar ++ = * szSrcChar ++;
  676. }
  677. * szDestChar = L'\0';
  678. // now to see if all this will fit in the users's buffer
  679. dwBufferLength = sizeof(PDHI_COUNTER_PATH) - sizeof(BYTE);
  680. dwBufferLength += DWORD_MULTIPLE((dwWorkMachineLength + 1) * sizeof(WCHAR));
  681. dwBufferLength += DWORD_MULTIPLE((dwWorkObjectLength + 1) * sizeof(WCHAR));
  682. if (dwWorkInstanceLength > 0) {
  683. dwBufferLength += DWORD_MULTIPLE((dwWorkInstanceLength + 1) * sizeof(WCHAR));
  684. }
  685. if (dwWorkParentLength > 0) {
  686. dwBufferLength += DWORD_MULTIPLE((dwWorkParentLength + 1) * sizeof(WCHAR));
  687. }
  688. dwBufferLength += DWORD_MULTIPLE((dwWorkCounterLength + 1) * sizeof(WCHAR));
  689. TRACE((PDH_DBG_TRACE_INFO),
  690. (__LINE__,
  691. PDH_CUTILS,
  692. ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2)
  693. | ARG_DEF(ARG_TYPE_WSTR, 3)
  694. | ARG_DEF(ARG_TYPE_WSTR, 4)
  695. | ARG_DEF(ARG_TYPE_WSTR, 5)
  696. | ARG_DEF(ARG_TYPE_WSTR, 6),
  697. ERROR_SUCCESS,
  698. TRACE_WSTR(szFullCounterPath),
  699. TRACE_WSTR(szWorkMachine),
  700. TRACE_WSTR(szWorkObject),
  701. TRACE_WSTR(szWorkCounter),
  702. TRACE_WSTR(szWorkInstance),
  703. TRACE_WSTR(szWorkParent),
  704. TRACE_DWORD(dwWorkIndex),
  705. TRACE_DWORD(dwBufferLength),
  706. NULL));
  707. if (dwBufferLength < * pdwBufferSize) {
  708. // it looks like it'll fit so start filling things in
  709. szDestChar = (LPWSTR) & pCounter->pBuffer[0];
  710. if (dwWorkMachineLength != 0) {
  711. pCounter->szMachineName = szDestChar;
  712. StringCchCopyW(szDestChar, dwWorkMachineLength + 1, szWorkMachine);
  713. szDestChar += dwWorkMachineLength + 1;
  714. szDestChar = ALIGN_ON_DWORD(szDestChar);
  715. }
  716. else {
  717. pCounter->szMachineName = NULL;
  718. }
  719. pCounter->szObjectName = szDestChar;
  720. StringCchCopyW(szDestChar, dwWorkObjectLength + 1, szWorkObject);
  721. szDestChar += dwWorkObjectLength + 1;
  722. szDestChar = ALIGN_ON_DWORD(szDestChar);
  723. if (dwWorkInstanceLength != 0) {
  724. pCounter->szInstanceName = szDestChar;
  725. StringCchCopyW(szDestChar, dwWorkInstanceLength + 1, szWorkInstance);
  726. szDestChar += dwWorkInstanceLength + 1;
  727. szDestChar = ALIGN_ON_DWORD(szDestChar);
  728. }
  729. else {
  730. pCounter->szInstanceName = NULL;
  731. }
  732. if (dwWorkParentLength != 0) {
  733. pCounter->szParentName = szDestChar;
  734. StringCchCopyW(szDestChar, dwWorkParentLength + 1, szWorkParent);
  735. szDestChar += dwWorkParentLength + 1;
  736. szDestChar = ALIGN_ON_DWORD(szDestChar);
  737. }
  738. else {
  739. pCounter->szParentName = NULL;
  740. }
  741. pCounter->dwIndex = dwWorkIndex;
  742. pCounter->szCounterName = szDestChar;
  743. StringCchCopyW(szDestChar, dwWorkCounterLength + 1, szWorkCounter);
  744. szDestChar += dwWorkCounterLength + 1;
  745. szDestChar = ALIGN_ON_DWORD(szDestChar);
  746. * pdwBufferSize = dwBufferLength;
  747. bReturn = TRUE;
  748. }
  749. else {
  750. //insufficient buffer
  751. }
  752. }
  753. else {
  754. // no object found so return
  755. }
  756. }
  757. else {
  758. // incoming string is too long
  759. }
  760. Cleanup:
  761. G_FREE(szWorkMachine);
  762. G_FREE(szWorkObject);
  763. G_FREE(szWorkInstance);
  764. G_FREE(szWorkParent);
  765. G_FREE(szWorkCounter);
  766. return bReturn;
  767. }
  768. BOOL
  769. FreeCounter(
  770. PPDHI_COUNTER pThisCounter
  771. )
  772. {
  773. // NOTE:
  774. // This function assumes the query containing
  775. // this counter has already been locked by the calling
  776. // function.
  777. PPDHI_COUNTER pPrevCounter;
  778. PPDHI_COUNTER pNextCounter;
  779. PPDHI_QUERY pParentQuery;
  780. // define pointers
  781. pPrevCounter = pThisCounter->next.blink;
  782. pNextCounter = pThisCounter->next.flink;
  783. pParentQuery = pThisCounter->pOwner;
  784. // decrement machine reference counter if a machine has been assigned
  785. if (pThisCounter->pQMachine != NULL) {
  786. if (pThisCounter->pQMachine->pMachine != NULL) {
  787. if (--pThisCounter->pQMachine->pMachine->dwRefCount == 0) {
  788. // then this is the last counter so remove machine
  789. // freeing the machine in this call causes all kinds of
  790. // multi-threading problems so we'll keep it around until
  791. // the DLL unloads.
  792. // FreeMachine (pThisCounter->pQMachine->pMachine, FALSE);
  793. pThisCounter->pQMachine->pMachine = NULL;
  794. }
  795. else {
  796. // the ref count is non-zero so leave the pointer alone
  797. }
  798. }
  799. else {
  800. // the pointer has already been cleared
  801. }
  802. }
  803. else {
  804. // there's no machine
  805. }
  806. // free allocated memory in the counter
  807. G_FREE(pThisCounter->pCounterPath);
  808. pThisCounter->pCounterPath = NULL;
  809. G_FREE(pThisCounter->szFullName);
  810. pThisCounter->szFullName = NULL;
  811. if (pParentQuery != NULL) {
  812. if (pParentQuery->hLog == NULL) {
  813. G_FREE(pThisCounter->pThisObject);
  814. pThisCounter->pThisObject = NULL;
  815. G_FREE(pThisCounter->pLastObject);
  816. pThisCounter->pLastObject = NULL;
  817. G_FREE(pThisCounter->pThisRawItemList);
  818. pThisCounter->pThisRawItemList = NULL;
  819. G_FREE(pThisCounter->pLastRawItemList);
  820. pThisCounter->pLastRawItemList = NULL;
  821. }
  822. }
  823. // check for WBEM items
  824. if ((pThisCounter->dwFlags & PDHIC_WBEM_COUNTER) && (pThisCounter->pOwner != NULL)) {
  825. PdhiCloseWbemCounter(pThisCounter);
  826. }
  827. // update pointers if they've been assigned
  828. if ((pPrevCounter != NULL) && (pNextCounter != NULL)) {
  829. if ((pPrevCounter != pThisCounter) && (pNextCounter != pThisCounter)) {
  830. // update query list pointers
  831. pPrevCounter->next.flink = pNextCounter;
  832. pNextCounter->next.blink = pPrevCounter;
  833. }
  834. else {
  835. // this is the only counter entry in the list
  836. // so the caller must deal with updating the head pointer
  837. }
  838. }
  839. // delete this counter
  840. G_FREE(pThisCounter);
  841. return TRUE;
  842. }
  843. BOOL
  844. UpdateCounterValue(
  845. PPDHI_COUNTER pCounter,
  846. PPERF_DATA_BLOCK pPerfData
  847. )
  848. {
  849. DWORD LocalCStatus = 0;
  850. DWORD LocalCType = 0;
  851. LPVOID pData = NULL;
  852. PDWORD pdwData;
  853. UNALIGNED LONGLONG * pllData;
  854. PPERF_OBJECT_TYPE pPerfObject = NULL;
  855. BOOL bReturn = FALSE;
  856. pData = GetPerfCounterDataPtr(pPerfData,
  857. pCounter->pCounterPath,
  858. & pCounter->plCounterInfo,
  859. 0,
  860. & pPerfObject,
  861. & LocalCStatus);
  862. pCounter->ThisValue.CStatus = LocalCStatus;
  863. if (IsSuccessSeverity(LocalCStatus)) {
  864. // assume success
  865. bReturn = TRUE;
  866. // load counter value based on counter type
  867. LocalCType = pCounter->plCounterInfo.dwCounterType;
  868. switch (LocalCType) {
  869. //
  870. // these counter types are loaded as:
  871. // Numerator = Counter data from perf data block
  872. // Denominator = Perf Time from perf data block
  873. // (the time base is the PerfFreq)
  874. //
  875. case PERF_COUNTER_COUNTER:
  876. case PERF_COUNTER_QUEUELEN_TYPE:
  877. case PERF_SAMPLE_COUNTER:
  878. pCounter->ThisValue.FirstValue = (LONGLONG) (* (DWORD *) pData);
  879. pCounter->ThisValue.SecondValue = pPerfData->PerfTime.QuadPart;
  880. break;
  881. case PERF_OBJ_TIME_TIMER:
  882. pCounter->ThisValue.FirstValue = (LONGLONG) (* (DWORD *) pData);
  883. pCounter->ThisValue.SecondValue = pPerfObject->PerfTime.QuadPart;
  884. break;
  885. case PERF_COUNTER_100NS_QUEUELEN_TYPE:
  886. pllData = (UNALIGNED LONGLONG *) pData;
  887. pCounter->ThisValue.FirstValue = * pllData;
  888. pCounter->ThisValue.SecondValue = pPerfData->PerfTime100nSec.QuadPart;
  889. break;
  890. case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
  891. pllData = (UNALIGNED LONGLONG *) pData;
  892. pCounter->ThisValue.FirstValue = * pllData;
  893. pCounter->ThisValue.SecondValue = pPerfObject->PerfTime.QuadPart;
  894. break;
  895. case PERF_COUNTER_TIMER:
  896. case PERF_COUNTER_TIMER_INV:
  897. case PERF_COUNTER_BULK_COUNT:
  898. case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
  899. pllData = (UNALIGNED LONGLONG *) pData;
  900. pCounter->ThisValue.FirstValue = * pllData;
  901. pCounter->ThisValue.SecondValue = pPerfData->PerfTime.QuadPart;
  902. if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
  903. pCounter->ThisValue.MultiCount = (DWORD) * ++ pllData;
  904. }
  905. break;
  906. //
  907. // this is a hack to make the PDH work like PERFMON for
  908. // this counter type
  909. //
  910. case PERF_COUNTER_MULTI_TIMER:
  911. case PERF_COUNTER_MULTI_TIMER_INV:
  912. pllData = (UNALIGNED LONGLONG *) pData;
  913. pCounter->ThisValue.FirstValue = * pllData;
  914. // begin hack code
  915. pCounter->ThisValue.FirstValue *= (DWORD) pPerfData->PerfFreq.QuadPart;
  916. // end hack code
  917. pCounter->ThisValue.SecondValue = pPerfData->PerfTime.QuadPart;
  918. if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
  919. pCounter->ThisValue.MultiCount = (DWORD) * ++ pllData;
  920. }
  921. break;
  922. //
  923. // These counters do not use any time reference
  924. //
  925. case PERF_COUNTER_RAWCOUNT:
  926. case PERF_COUNTER_RAWCOUNT_HEX:
  927. case PERF_COUNTER_DELTA:
  928. pCounter->ThisValue.FirstValue = (LONGLONG) (* (DWORD *) pData);
  929. pCounter->ThisValue.SecondValue = 0;
  930. break;
  931. case PERF_COUNTER_LARGE_RAWCOUNT:
  932. case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
  933. case PERF_COUNTER_LARGE_DELTA:
  934. pCounter->ThisValue.FirstValue = * (LONGLONG *) pData;
  935. pCounter->ThisValue.SecondValue = 0;
  936. break;
  937. //
  938. // These counters use the 100 Ns time base in thier calculation
  939. //
  940. case PERF_100NSEC_TIMER:
  941. case PERF_100NSEC_TIMER_INV:
  942. case PERF_100NSEC_MULTI_TIMER:
  943. case PERF_100NSEC_MULTI_TIMER_INV:
  944. pllData = (UNALIGNED LONGLONG *)pData;
  945. pCounter->ThisValue.FirstValue = * pllData;
  946. pCounter->ThisValue.SecondValue = pPerfData->PerfTime100nSec.QuadPart;
  947. if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
  948. ++ pllData;
  949. pCounter->ThisValue.MultiCount = * (DWORD *) pllData;
  950. }
  951. break;
  952. //
  953. // These counters use two data points, the one pointed to by
  954. // pData and the one immediately after
  955. //
  956. case PERF_SAMPLE_FRACTION:
  957. case PERF_RAW_FRACTION:
  958. pdwData = (DWORD *) pData;
  959. pCounter->ThisValue.FirstValue = (LONGLONG) (* pdwData);
  960. // find the pointer to the base value in the structure
  961. pData = GetPerfCounterDataPtr(pPerfData,
  962. pCounter->pCounterPath,
  963. & pCounter->plCounterInfo,
  964. GPCDP_GET_BASE_DATA,
  965. NULL,
  966. & LocalCStatus);
  967. if (IsSuccessSeverity(LocalCStatus)) {
  968. pdwData = (DWORD *) pData;
  969. pCounter->ThisValue.SecondValue = (LONGLONG) (* pdwData);
  970. }
  971. else {
  972. // unable to locate base value
  973. pCounter->ThisValue.SecondValue = 0;
  974. pCounter->ThisValue.CStatus = LocalCStatus;
  975. bReturn = FALSE;
  976. }
  977. break;
  978. case PERF_LARGE_RAW_FRACTION:
  979. pllData = (UNALIGNED LONGLONG *) pData;
  980. pCounter->ThisValue.FirstValue = * pllData;
  981. pData = GetPerfCounterDataPtr(pPerfData,
  982. pCounter->pCounterPath,
  983. & pCounter->plCounterInfo,
  984. GPCDP_GET_BASE_DATA,
  985. NULL,
  986. & LocalCStatus);
  987. if (IsSuccessSeverity(LocalCStatus)) {
  988. pllData = (LONGLONG *) pData;
  989. pCounter->ThisValue.SecondValue = * pllData;
  990. }
  991. else {
  992. pCounter->ThisValue.SecondValue = 0;
  993. pCounter->ThisValue.CStatus = LocalCStatus;
  994. bReturn = FALSE;
  995. }
  996. break;
  997. case PERF_PRECISION_SYSTEM_TIMER:
  998. case PERF_PRECISION_100NS_TIMER:
  999. case PERF_PRECISION_OBJECT_TIMER:
  1000. pllData = (LONGLONG *) pData;
  1001. pCounter->ThisValue.FirstValue = * pllData;
  1002. // find the pointer to the base value in the structure
  1003. pData = GetPerfCounterDataPtr(pPerfData,
  1004. pCounter->pCounterPath,
  1005. & pCounter->plCounterInfo,
  1006. GPCDP_GET_BASE_DATA,
  1007. NULL,
  1008. & LocalCStatus);
  1009. if (IsSuccessSeverity(LocalCStatus)) {
  1010. pllData = (LONGLONG *) pData;
  1011. pCounter->ThisValue.SecondValue = * pllData;
  1012. }
  1013. else {
  1014. // unable to locate base value
  1015. pCounter->ThisValue.SecondValue = 0;
  1016. pCounter->ThisValue.CStatus = LocalCStatus;
  1017. bReturn = FALSE;
  1018. }
  1019. break;
  1020. case PERF_AVERAGE_TIMER:
  1021. case PERF_AVERAGE_BULK:
  1022. // counter (numerator) is a LONGLONG, while the
  1023. // denominator is just a DWORD
  1024. pllData = (UNALIGNED LONGLONG *) pData;
  1025. pCounter->ThisValue.FirstValue = * pllData;
  1026. pData = GetPerfCounterDataPtr(pPerfData,
  1027. pCounter->pCounterPath,
  1028. & pCounter->plCounterInfo,
  1029. GPCDP_GET_BASE_DATA,
  1030. NULL,
  1031. & LocalCStatus);
  1032. if (IsSuccessSeverity(LocalCStatus)) {
  1033. pdwData = (DWORD *) pData;
  1034. pCounter->ThisValue.SecondValue = * pdwData;
  1035. } else {
  1036. // unable to locate base value
  1037. pCounter->ThisValue.SecondValue = 0;
  1038. pCounter->ThisValue.CStatus = LocalCStatus;
  1039. bReturn = FALSE;
  1040. }
  1041. break;
  1042. //
  1043. // These counters are used as the part of another counter
  1044. // and as such should not be used, but in case they are
  1045. // they'll be handled here.
  1046. //
  1047. case PERF_SAMPLE_BASE:
  1048. case PERF_AVERAGE_BASE:
  1049. case PERF_COUNTER_MULTI_BASE:
  1050. case PERF_RAW_BASE:
  1051. case PERF_LARGE_RAW_BASE:
  1052. pCounter->ThisValue.FirstValue = 0;
  1053. pCounter->ThisValue.SecondValue = 0;
  1054. break;
  1055. case PERF_ELAPSED_TIME:
  1056. // this counter type needs the object perf data as well
  1057. if (GetObjectPerfInfo(pPerfData,
  1058. pCounter->plCounterInfo.dwObjectId,
  1059. & pCounter->ThisValue.SecondValue,
  1060. & pCounter->TimeBase)) {
  1061. pllData = (UNALIGNED LONGLONG *) pData;
  1062. pCounter->ThisValue.FirstValue = * pllData;
  1063. }
  1064. else {
  1065. pCounter->ThisValue.FirstValue = 0;
  1066. pCounter->ThisValue.SecondValue = 0;
  1067. }
  1068. break;
  1069. //
  1070. // These counters are not supported by this function (yet)
  1071. //
  1072. case PERF_COUNTER_TEXT:
  1073. case PERF_COUNTER_NODATA:
  1074. case PERF_COUNTER_HISTOGRAM_TYPE:
  1075. pCounter->ThisValue.FirstValue = 0;
  1076. pCounter->ThisValue.SecondValue = 0;
  1077. break;
  1078. default:
  1079. // an unidentified counter was returned so
  1080. pCounter->ThisValue.FirstValue = 0;
  1081. pCounter->ThisValue.SecondValue = 0;
  1082. bReturn = FALSE;
  1083. break;
  1084. }
  1085. }
  1086. else {
  1087. // else this counter is not valid so this value == 0
  1088. pCounter->ThisValue.FirstValue = pCounter->LastValue.FirstValue;
  1089. pCounter->ThisValue.SecondValue = pCounter->LastValue.SecondValue;
  1090. pCounter->ThisValue.CStatus = LocalCStatus;
  1091. bReturn = FALSE;
  1092. }
  1093. return bReturn;
  1094. }
  1095. BOOL
  1096. UpdateRealTimeCounterValue(
  1097. PPDHI_COUNTER pCounter
  1098. )
  1099. {
  1100. BOOL bResult = FALSE;
  1101. DWORD LocalCStatus = 0;
  1102. FILETIME GmtFileTime;
  1103. // move current value to last value buffer
  1104. pCounter->LastValue = pCounter->ThisValue;
  1105. // and clear the old value
  1106. pCounter->ThisValue.MultiCount = 1;
  1107. pCounter->ThisValue.FirstValue = 0;
  1108. pCounter->ThisValue.SecondValue = 0;
  1109. // don't process if the counter has not been initialized
  1110. if (!(pCounter->dwFlags & PDHIC_COUNTER_UNUSABLE)) {
  1111. // get the counter's machine status first. There's no point in
  1112. // contuning if the machine is offline
  1113. LocalCStatus = pCounter->pQMachine->lQueryStatus;
  1114. if (IsSuccessSeverity(LocalCStatus) && pCounter->pQMachine->pPerfData != NULL) {
  1115. // update timestamp
  1116. SystemTimeToFileTime(& pCounter->pQMachine->pPerfData->SystemTime, & GmtFileTime);
  1117. FileTimeToLocalFileTime(& GmtFileTime, & pCounter->ThisValue.TimeStamp);
  1118. bResult = UpdateCounterValue(pCounter, pCounter->pQMachine->pPerfData);
  1119. }
  1120. else {
  1121. // unable to read data from this counter's machine so use the
  1122. // query's timestamp
  1123. //
  1124. pCounter->ThisValue.TimeStamp.dwLowDateTime = LODWORD(pCounter->pQMachine->llQueryTime);
  1125. pCounter->ThisValue.TimeStamp.dwHighDateTime = HIDWORD(pCounter->pQMachine->llQueryTime);
  1126. // all other data fields remain un-changed
  1127. pCounter->ThisValue.CStatus = LocalCStatus; // save counter status
  1128. }
  1129. }
  1130. else {
  1131. if (pCounter->dwFlags & PDHIC_COUNTER_NOT_INIT) {
  1132. // try to init it
  1133. InitCounter (pCounter);
  1134. }
  1135. }
  1136. return bResult;
  1137. }
  1138. BOOL
  1139. UpdateMultiInstanceCounterValue(
  1140. PPDHI_COUNTER pCounter,
  1141. PPERF_DATA_BLOCK pPerfData,
  1142. LONGLONG TimeStamp
  1143. )
  1144. {
  1145. PPERF_OBJECT_TYPE pPerfObject = NULL;
  1146. PPERF_INSTANCE_DEFINITION pPerfInstance = NULL;
  1147. PPERF_OBJECT_TYPE pParentObject = NULL;
  1148. PPERF_INSTANCE_DEFINITION pThisParentInstance = NULL;
  1149. PPERF_COUNTER_DEFINITION pNumPerfCounter = NULL;
  1150. PPERF_COUNTER_DEFINITION pDenPerfCounter = NULL;
  1151. DWORD LocalCStatus = 0;
  1152. DWORD LocalCType = 0;
  1153. LPVOID pData = NULL;
  1154. PDWORD pdwData;
  1155. UNALIGNED LONGLONG * pllData;
  1156. FILETIME GmtFileTime;
  1157. DWORD dwSize;
  1158. DWORD dwFinalSize;
  1159. LONG nThisInstanceIndex;
  1160. LONG nParentInstanceIndex;
  1161. LPWSTR szNextNameString;
  1162. DWORD dwStrSize;
  1163. PPDHI_RAW_COUNTER_ITEM pThisItem;
  1164. BOOL bReturn = FALSE;
  1165. pPerfObject = GetObjectDefByTitleIndex(pPerfData, pCounter->plCounterInfo.dwObjectId);
  1166. if (pPerfObject != NULL) {
  1167. // this should be caught during the AddCounter operation
  1168. //
  1169. // allocate a new buffer for the current data
  1170. // this should be large enough to handle the header,
  1171. // all instances and thier name strings
  1172. //
  1173. dwSize = sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK) - sizeof(PDHI_RAW_COUNTER_ITEM);
  1174. dwStrSize = 0;
  1175. pPerfInstance = FirstInstance(pPerfObject);
  1176. // make sure pointer is still within the same instance
  1177. for (nThisInstanceIndex = 0;
  1178. pPerfInstance != NULL && nThisInstanceIndex < pPerfObject->NumInstances;
  1179. nThisInstanceIndex ++) {
  1180. // this should only fail in dire cases
  1181. if (pPerfInstance == NULL) break;
  1182. // for this instance add the size of the data item
  1183. dwSize += sizeof(PDHI_RAW_COUNTER_ITEM);
  1184. // and the size of the name string
  1185. dwSize += pPerfInstance->NameLength + sizeof(WCHAR);
  1186. dwStrSize += pPerfInstance->NameLength / sizeof(WCHAR) + 1;
  1187. // to the required buffer size
  1188. // if this instance has a parent, see how long it's string
  1189. // is
  1190. // first see if we've already got the pointer to the parent
  1191. if (pPerfInstance->ParentObjectTitleIndex != 0) {
  1192. // then include the parent instance name
  1193. if (pParentObject == NULL) {
  1194. // get parent object
  1195. pParentObject = GetObjectDefByTitleIndex(pPerfData, pPerfInstance->ParentObjectTitleIndex);
  1196. }
  1197. else {
  1198. if (pParentObject->ObjectNameTitleIndex != pPerfInstance->ParentObjectTitleIndex) {
  1199. pParentObject = GetObjectDefByTitleIndex(pPerfData, pPerfInstance->ParentObjectTitleIndex);
  1200. }
  1201. }
  1202. if (pParentObject == NULL) break;
  1203. // now go to the corresponding instance entry
  1204. pThisParentInstance = FirstInstance(pParentObject);
  1205. // make sure pointer is still within the same instance
  1206. if (pThisParentInstance != NULL) {
  1207. if (pPerfInstance->ParentObjectInstance < (DWORD) pParentObject->NumInstances) {
  1208. for (nParentInstanceIndex = 0;
  1209. (DWORD) nParentInstanceIndex != pPerfInstance->ParentObjectInstance;
  1210. nParentInstanceIndex ++) {
  1211. pThisParentInstance = NextInstance(pParentObject, pThisParentInstance);
  1212. if (pThisParentInstance == NULL) break;
  1213. }
  1214. if (pThisParentInstance != NULL) {
  1215. // found it so add in it's string length
  1216. dwSize += pThisParentInstance->NameLength + sizeof(WCHAR);
  1217. dwStrSize += pThisParentInstance->NameLength / sizeof(WCHAR) + 1;
  1218. }
  1219. }
  1220. else {
  1221. // the index is not in the parent
  1222. pThisParentInstance = NULL;
  1223. // so don't change the size required field
  1224. }
  1225. }
  1226. }
  1227. // round up to the next DWORD address
  1228. dwSize = DWORD_MULTIPLE(dwSize);
  1229. // and go to the next instance
  1230. pPerfInstance = NextInstance(pPerfObject, pPerfInstance);
  1231. }
  1232. //
  1233. //
  1234. pCounter->pThisRawItemList = G_ALLOC(dwSize);
  1235. if (pCounter->pThisRawItemList != NULL) {
  1236. pCounter->pThisRawItemList->dwLength = dwSize;
  1237. pNumPerfCounter = GetCounterDefByTitleIndex(pPerfObject, 0, pCounter->plCounterInfo.dwCounterId);
  1238. // just in case we need it later
  1239. pDenPerfCounter = pNumPerfCounter + 1;
  1240. // fill in the counter data
  1241. pCounter->pThisRawItemList->dwItemCount = pPerfObject->NumInstances;
  1242. pCounter->pThisRawItemList->CStatus = LocalCStatus;
  1243. // update timestamp
  1244. SystemTimeToFileTime(& pPerfData->SystemTime, & GmtFileTime);
  1245. FileTimeToLocalFileTime(& GmtFileTime, & pCounter->pThisRawItemList->TimeStamp);
  1246. pThisItem = & pCounter->pThisRawItemList->pItemArray[0];
  1247. szNextNameString = (LPWSTR) & (pCounter->pThisRawItemList->pItemArray[pPerfObject->NumInstances]);
  1248. pPerfInstance = FirstInstance(pPerfObject);
  1249. if (pPerfInstance != NULL) {
  1250. // make sure pointer is still within the same instance
  1251. // for each instance log the raw data values for this counter
  1252. for (nThisInstanceIndex = 0;
  1253. pPerfInstance != NULL && nThisInstanceIndex < pPerfObject->NumInstances;
  1254. nThisInstanceIndex ++) {
  1255. // make sure pointe is still within the same instance
  1256. // make a new instance entry
  1257. // get the name of this instance
  1258. pThisItem->szName = (DWORD) (((LPBYTE) szNextNameString) - ((LPBYTE) pCounter->pThisRawItemList));
  1259. if (dwStrSize == 0) {
  1260. SetLastError(ERROR_OUTOFMEMORY);
  1261. bReturn = FALSE;
  1262. break;
  1263. }
  1264. dwSize = GetFullInstanceNameStr(pPerfData, pPerfObject, pPerfInstance, szNextNameString, dwStrSize);
  1265. if (dwSize == 0) {
  1266. // unable to read instance name
  1267. // so make one up (and assert in DBG builds)
  1268. _ltow(nThisInstanceIndex, szNextNameString, 10);
  1269. dwSize = lstrlenW(szNextNameString);
  1270. }
  1271. if (dwSize + 1 > dwStrSize) {
  1272. SetLastError(ERROR_OUTOFMEMORY);
  1273. bReturn = FALSE;
  1274. break;
  1275. }
  1276. szNextNameString += dwSize + 1;
  1277. dwStrSize -= (dwSize + 1);
  1278. // get the pointer to the counter data
  1279. pData = GetPerfCounterDataPtr(pPerfData,
  1280. pCounter->pCounterPath,
  1281. & pCounter->plCounterInfo,
  1282. 0,
  1283. NULL,
  1284. & LocalCStatus);
  1285. if (pNumPerfCounter != NULL) {
  1286. pData = GetInstanceCounterDataPtr(pPerfObject, pPerfInstance, pNumPerfCounter);
  1287. }
  1288. if (pData == NULL) {
  1289. SetLastError(PDH_CSTATUS_NO_INSTANCE);
  1290. bReturn = FALSE;
  1291. break;
  1292. }
  1293. bReturn = TRUE; // assume success
  1294. // load counter value based on counter type
  1295. LocalCType = pCounter->plCounterInfo.dwCounterType;
  1296. switch (LocalCType) {
  1297. //
  1298. // these counter types are loaded as:
  1299. // Numerator = Counter data from perf data block
  1300. // Denominator = Perf Time from perf data block
  1301. // (the time base is the PerfFreq)
  1302. //
  1303. case PERF_COUNTER_COUNTER:
  1304. case PERF_COUNTER_QUEUELEN_TYPE:
  1305. case PERF_SAMPLE_COUNTER:
  1306. pThisItem->FirstValue = (LONGLONG) (* (DWORD *) pData);
  1307. pThisItem->SecondValue = pPerfData->PerfTime.QuadPart;
  1308. break;
  1309. case PERF_OBJ_TIME_TIMER:
  1310. pThisItem->FirstValue = (LONGLONG) (* (DWORD *) pData);
  1311. pThisItem->SecondValue = pPerfObject->PerfTime.QuadPart;
  1312. break;
  1313. case PERF_COUNTER_100NS_QUEUELEN_TYPE:
  1314. pllData = (UNALIGNED LONGLONG *) pData;
  1315. pThisItem->FirstValue = * pllData;
  1316. pThisItem->SecondValue = pPerfData->PerfTime100nSec.QuadPart;
  1317. break;
  1318. case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
  1319. pllData = (UNALIGNED LONGLONG *) pData;
  1320. pThisItem->FirstValue = * pllData;
  1321. pThisItem->SecondValue = pPerfObject->PerfTime.QuadPart;
  1322. break;
  1323. case PERF_COUNTER_TIMER:
  1324. case PERF_COUNTER_TIMER_INV:
  1325. case PERF_COUNTER_BULK_COUNT:
  1326. case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
  1327. pllData = (UNALIGNED LONGLONG *) pData;
  1328. pThisItem->FirstValue = * pllData;
  1329. pThisItem->SecondValue = pPerfData->PerfTime.QuadPart;
  1330. if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
  1331. pThisItem->MultiCount = (DWORD) * ++pllData;
  1332. }
  1333. break;
  1334. case PERF_COUNTER_MULTI_TIMER:
  1335. case PERF_COUNTER_MULTI_TIMER_INV:
  1336. pllData = (UNALIGNED LONGLONG *) pData;
  1337. pThisItem->FirstValue = * pllData;
  1338. // begin hack code
  1339. pThisItem->FirstValue *= (DWORD) pPerfData->PerfFreq.QuadPart;
  1340. // end hack code
  1341. pThisItem->SecondValue = pPerfData->PerfTime.QuadPart;
  1342. if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
  1343. pThisItem->MultiCount = (DWORD) * ++ pllData;
  1344. }
  1345. break;
  1346. //
  1347. // These counters do not use any time reference
  1348. //
  1349. case PERF_COUNTER_RAWCOUNT:
  1350. case PERF_COUNTER_RAWCOUNT_HEX:
  1351. case PERF_COUNTER_DELTA:
  1352. pThisItem->FirstValue = (LONGLONG) (* (DWORD *) pData);
  1353. pThisItem->SecondValue = 0;
  1354. break;
  1355. case PERF_COUNTER_LARGE_RAWCOUNT:
  1356. case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
  1357. case PERF_COUNTER_LARGE_DELTA:
  1358. pThisItem->FirstValue = * (LONGLONG *) pData;
  1359. pThisItem->SecondValue = 0;
  1360. break;
  1361. //
  1362. // These counters use the 100 Ns time base in thier calculation
  1363. //
  1364. case PERF_100NSEC_TIMER:
  1365. case PERF_100NSEC_TIMER_INV:
  1366. case PERF_100NSEC_MULTI_TIMER:
  1367. case PERF_100NSEC_MULTI_TIMER_INV:
  1368. pllData = (UNALIGNED LONGLONG *) pData;
  1369. pThisItem->FirstValue = * pllData;
  1370. pThisItem->SecondValue = pPerfData->PerfTime100nSec.QuadPart;
  1371. if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
  1372. ++ pllData;
  1373. pThisItem->MultiCount = * (DWORD *) pllData;
  1374. }
  1375. break;
  1376. //
  1377. // These counters use two data points, the one pointed to by
  1378. // pData and the one pointed by the definition following
  1379. // immediately after
  1380. //
  1381. case PERF_SAMPLE_FRACTION:
  1382. case PERF_RAW_FRACTION:
  1383. pdwData = (DWORD *) pData;
  1384. pThisItem->FirstValue = (LONGLONG)(* pdwData);
  1385. pData = GetInstanceCounterDataPtr(pPerfObject, pPerfInstance, pDenPerfCounter);
  1386. pdwData = (DWORD *) pData;
  1387. pThisItem->SecondValue = (LONGLONG) (* pdwData);
  1388. break;
  1389. case PERF_LARGE_RAW_FRACTION:
  1390. pllData = (UNALIGNED LONGLONG *) pData;
  1391. pCounter->ThisValue.FirstValue = * pllData;
  1392. pData = GetInstanceCounterDataPtr(pPerfObject, pPerfInstance, pDenPerfCounter);
  1393. if (pData) {
  1394. pllData = (LONGLONG *) pData;
  1395. pCounter->ThisValue.SecondValue = * pllData;
  1396. }
  1397. else {
  1398. pCounter->ThisValue.SecondValue = 0;
  1399. bReturn = FALSE;
  1400. }
  1401. break;
  1402. case PERF_PRECISION_SYSTEM_TIMER:
  1403. case PERF_PRECISION_100NS_TIMER:
  1404. case PERF_PRECISION_OBJECT_TIMER:
  1405. pllData = (UNALIGNED LONGLONG *) pData;
  1406. pThisItem->FirstValue = * pllData;
  1407. // find the pointer to the base value in the structure
  1408. pData = GetInstanceCounterDataPtr(pPerfObject, pPerfInstance, pDenPerfCounter);
  1409. pllData = (LONGLONG *) pData;
  1410. pThisItem->SecondValue = * pllData;
  1411. break;
  1412. case PERF_AVERAGE_TIMER:
  1413. case PERF_AVERAGE_BULK:
  1414. // counter (numerator) is a LONGLONG, while the
  1415. // denominator is just a DWORD
  1416. pllData = (UNALIGNED LONGLONG *) pData;
  1417. pThisItem->FirstValue = * pllData;
  1418. pData = GetInstanceCounterDataPtr(pPerfObject, pPerfInstance, pDenPerfCounter);
  1419. pdwData = (DWORD *) pData;
  1420. pThisItem->SecondValue = (LONGLONG) * pdwData;
  1421. break;
  1422. //
  1423. // These counters are used as the part of another counter
  1424. // and as such should not be used, but in case they are
  1425. // they'll be handled here.
  1426. //
  1427. case PERF_SAMPLE_BASE:
  1428. case PERF_AVERAGE_BASE:
  1429. case PERF_COUNTER_MULTI_BASE:
  1430. case PERF_RAW_BASE:
  1431. case PERF_LARGE_RAW_BASE:
  1432. pThisItem->FirstValue = 0;
  1433. pThisItem->SecondValue = 0;
  1434. break;
  1435. case PERF_ELAPSED_TIME:
  1436. // this counter type needs the object perf data as well
  1437. if (GetObjectPerfInfo(pPerfData,
  1438. pCounter->plCounterInfo.dwObjectId,
  1439. & pThisItem->SecondValue,
  1440. & pCounter->TimeBase)) {
  1441. pllData = (UNALIGNED LONGLONG *) pData;
  1442. pThisItem->FirstValue = * pllData;
  1443. }
  1444. else {
  1445. pThisItem->FirstValue = 0;
  1446. pThisItem->SecondValue = 0;
  1447. }
  1448. break;
  1449. //
  1450. // These counters are not supported by this function (yet)
  1451. //
  1452. case PERF_COUNTER_TEXT:
  1453. case PERF_COUNTER_NODATA:
  1454. case PERF_COUNTER_HISTOGRAM_TYPE:
  1455. pThisItem->FirstValue = 0;
  1456. pThisItem->SecondValue = 0;
  1457. break;
  1458. default:
  1459. // an unrecognized counter type was returned
  1460. pThisItem->FirstValue = 0;
  1461. pThisItem->SecondValue = 0;
  1462. bReturn = FALSE;
  1463. break;
  1464. }
  1465. pThisItem ++; // go to the next entry
  1466. // go to the next instance data block
  1467. pPerfInstance = NextInstance(pPerfObject, pPerfInstance);
  1468. } // end for each instance
  1469. }
  1470. else {
  1471. // no instance found so ignore
  1472. }
  1473. // measure the memory block used
  1474. dwFinalSize = (DWORD)((LPBYTE)szNextNameString - (LPBYTE) pCounter->pThisRawItemList);
  1475. }
  1476. else {
  1477. // unable to allocate a new buffer so return error
  1478. SetLastError(ERROR_OUTOFMEMORY);
  1479. bReturn = FALSE;
  1480. }
  1481. }
  1482. else {
  1483. pCounter->pThisRawItemList = G_ALLOC(sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK));
  1484. if (pCounter->pThisRawItemList != NULL) {
  1485. pCounter->pThisRawItemList->dwLength = sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK);
  1486. pCounter->pThisRawItemList->dwItemCount = 0;
  1487. pCounter->pThisRawItemList->CStatus = LocalCStatus;
  1488. pCounter->pThisRawItemList->TimeStamp.dwLowDateTime = LODWORD(TimeStamp);
  1489. pCounter->pThisRawItemList->TimeStamp.dwHighDateTime = HIDWORD(TimeStamp);
  1490. }
  1491. else {
  1492. SetLastError(ERROR_OUTOFMEMORY);
  1493. bReturn = FALSE;
  1494. }
  1495. }
  1496. return bReturn;
  1497. }
  1498. BOOL
  1499. UpdateRealTimeMultiInstanceCounterValue(
  1500. PPDHI_COUNTER pCounter
  1501. )
  1502. {
  1503. BOOL bResult = TRUE;
  1504. DWORD LocalCStatus = 0;
  1505. if (pCounter->pThisRawItemList != NULL) {
  1506. // free old counter buffer list
  1507. if (pCounter->pLastRawItemList && pCounter->pLastRawItemList != pCounter->pThisRawItemList) {
  1508. G_FREE(pCounter->pLastRawItemList);
  1509. }
  1510. pCounter->pLastRawItemList = pCounter->pThisRawItemList;
  1511. pCounter->pThisRawItemList = NULL;
  1512. }
  1513. // don't process if the counter has not been initialized
  1514. if (!(pCounter->dwFlags & PDHIC_COUNTER_UNUSABLE)) {
  1515. // get the counter's machine status first. There's no point in
  1516. // contuning if the machine is offline
  1517. LocalCStatus = pCounter->pQMachine->lQueryStatus;
  1518. if (IsSuccessSeverity(LocalCStatus)) {
  1519. bResult = UpdateMultiInstanceCounterValue(pCounter,
  1520. pCounter->pQMachine->pPerfData,
  1521. pCounter->pQMachine->llQueryTime);
  1522. }
  1523. else {
  1524. // unable to read data from this counter's machine so use the
  1525. // query's timestamp
  1526. pCounter->pThisRawItemList = G_ALLOC(sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK));
  1527. if (pCounter->pThisRawItemList != NULL) {
  1528. pCounter->pThisRawItemList->dwLength = sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK);
  1529. pCounter->pThisRawItemList->dwItemCount = 0;
  1530. pCounter->pThisRawItemList->CStatus = LocalCStatus;
  1531. pCounter->pThisRawItemList->TimeStamp.dwLowDateTime = LODWORD(pCounter->pQMachine->llQueryTime);
  1532. pCounter->pThisRawItemList->TimeStamp.dwHighDateTime = HIDWORD(pCounter->pQMachine->llQueryTime);
  1533. }
  1534. else {
  1535. SetLastError(ERROR_OUTOFMEMORY);
  1536. bResult = FALSE;
  1537. }
  1538. }
  1539. }
  1540. else {
  1541. if (pCounter->dwFlags & PDHIC_COUNTER_NOT_INIT) {
  1542. // try to init is
  1543. InitCounter(pCounter);
  1544. }
  1545. }
  1546. return bResult;
  1547. }
  1548. BOOL
  1549. UpdateCounterObject(
  1550. PPDHI_COUNTER pCounter
  1551. )
  1552. {
  1553. BOOL bReturn = TRUE;
  1554. PPERF_OBJECT_TYPE pPerfObject = NULL;
  1555. PPERF_OBJECT_TYPE pLogPerfObj;
  1556. DWORD dwBufferSize = sizeof(PERF_DATA_BLOCK);
  1557. FILETIME ftGmtTime;
  1558. FILETIME ftLocTime;
  1559. if (pCounter == NULL) {
  1560. SetLastError(PDH_INVALID_ARGUMENT);
  1561. bReturn = FALSE;
  1562. }
  1563. else {
  1564. if (pCounter->pThisObject != NULL) {
  1565. if (pCounter->pLastObject && pCounter->pThisObject != pCounter->pLastObject) {
  1566. G_FREE(pCounter->pLastObject);
  1567. }
  1568. pCounter->pLastObject = pCounter->pThisObject;
  1569. pCounter->pThisObject = NULL;
  1570. }
  1571. // don't process if the counter has not been initialized
  1572. if (!(pCounter->dwFlags & PDHIC_COUNTER_UNUSABLE)) {
  1573. if (IsSuccessSeverity(pCounter->pQMachine->lQueryStatus)) {
  1574. pPerfObject = GetObjectDefByTitleIndex(pCounter->pQMachine->pPerfData,
  1575. pCounter->plCounterInfo.dwObjectId);
  1576. dwBufferSize = pCounter->pQMachine->pPerfData->HeaderLength;
  1577. dwBufferSize += ((pPerfObject == NULL) ? sizeof(PERF_OBJECT_TYPE) : pPerfObject->TotalByteLength);
  1578. pCounter->pThisObject = G_ALLOC(dwBufferSize);
  1579. if (pCounter->pThisObject != NULL) {
  1580. RtlCopyMemory(pCounter->pThisObject,
  1581. pCounter->pQMachine->pPerfData,
  1582. pCounter->pQMachine->pPerfData->HeaderLength);
  1583. pCounter->pThisObject->TotalByteLength = dwBufferSize;
  1584. pCounter->pThisObject->NumObjectTypes = 1;
  1585. SystemTimeToFileTime(& pCounter->pThisObject->SystemTime, & ftGmtTime);
  1586. FileTimeToLocalFileTime(& ftGmtTime, & ftLocTime);
  1587. FileTimeToSystemTime(& ftLocTime, & pCounter->pThisObject->SystemTime);
  1588. pLogPerfObj = (PPERF_OBJECT_TYPE)
  1589. ((LPBYTE) pCounter->pThisObject + pCounter->pQMachine->pPerfData->HeaderLength);
  1590. if (pPerfObject != NULL) {
  1591. RtlCopyMemory(pLogPerfObj, pPerfObject, pPerfObject->TotalByteLength);
  1592. }
  1593. else {
  1594. ZeroMemory(pLogPerfObj, sizeof(PERF_OBJECT_TYPE));
  1595. pLogPerfObj->TotalByteLength = sizeof(PERF_OBJECT_TYPE);
  1596. pLogPerfObj->DefinitionLength = sizeof(PERF_OBJECT_TYPE);
  1597. pLogPerfObj->HeaderLength = sizeof(PERF_OBJECT_TYPE);
  1598. pLogPerfObj->ObjectNameTitleIndex = pCounter->plCounterInfo.dwObjectId;
  1599. pLogPerfObj->ObjectHelpTitleIndex = pCounter->plCounterInfo.dwObjectId + 1;
  1600. }
  1601. }
  1602. else {
  1603. SetLastError(ERROR_OUTOFMEMORY);
  1604. bReturn = FALSE;
  1605. }
  1606. }
  1607. else {
  1608. pCounter->pThisObject = G_ALLOC(sizeof(PERF_DATA_BLOCK));
  1609. if (pCounter->pThisObject == NULL) {
  1610. pCounter->pThisObject = pCounter->pLastObject;
  1611. }
  1612. else {
  1613. pCounter->pThisObject->Signature[0] = L'P';
  1614. pCounter->pThisObject->Signature[1] = L'E';
  1615. pCounter->pThisObject->Signature[2] = L'R';
  1616. pCounter->pThisObject->Signature[3] = L'F';
  1617. pCounter->pThisObject->LittleEndian = TRUE;
  1618. pCounter->pThisObject->Version = PERF_DATA_VERSION;
  1619. pCounter->pThisObject->Revision = PERF_DATA_REVISION;
  1620. pCounter->pThisObject->TotalByteLength = sizeof(PERF_DATA_BLOCK);
  1621. pCounter->pThisObject->NumObjectTypes = 1;
  1622. pCounter->pThisObject->DefaultObject = pCounter->plCounterInfo.dwObjectId;
  1623. pCounter->pThisObject->SystemNameLength = 0;
  1624. pCounter->pThisObject->SystemNameOffset = 0;
  1625. pCounter->pThisObject->HeaderLength = sizeof(PERF_DATA_BLOCK);
  1626. pCounter->pThisObject->PerfTime.QuadPart = 0;
  1627. pCounter->pThisObject->PerfFreq.QuadPart = 0;
  1628. pCounter->pThisObject->PerfTime100nSec.QuadPart = 0;
  1629. GetLocalTime(& pCounter->pThisObject->SystemTime);
  1630. }
  1631. SetLastError(PDH_CSTATUS_INVALID_DATA);
  1632. bReturn = FALSE;
  1633. }
  1634. }
  1635. else {
  1636. if (pCounter->dwFlags & PDHIC_COUNTER_NOT_INIT) {
  1637. InitCounter(pCounter);
  1638. }
  1639. pCounter->pThisObject = pCounter->pLastObject;
  1640. SetLastError(PDH_CSTATUS_INVALID_DATA);
  1641. bReturn = FALSE;
  1642. }
  1643. }
  1644. return bReturn;
  1645. }
  1646. PVOID
  1647. GetPerfCounterDataPtr(
  1648. PPERF_DATA_BLOCK pPerfData,
  1649. PPDHI_COUNTER_PATH pPath,
  1650. PPERFLIB_COUNTER pplCtr ,
  1651. DWORD dwFlags,
  1652. PPERF_OBJECT_TYPE *pPerfObjectArg,
  1653. PDWORD pStatus
  1654. )
  1655. {
  1656. PPERF_OBJECT_TYPE pPerfObject = NULL;
  1657. PPERF_INSTANCE_DEFINITION pPerfInstance = NULL;
  1658. PPERF_COUNTER_DEFINITION pPerfCounter = NULL;
  1659. DWORD dwTestValue = 0;
  1660. PVOID pData = NULL;
  1661. DWORD dwCStatus = PDH_CSTATUS_INVALID_DATA;
  1662. pPerfObject = GetObjectDefByTitleIndex(pPerfData, pplCtr->dwObjectId);
  1663. if (pPerfObject != NULL) {
  1664. if (pPerfObjectArg != NULL) * pPerfObjectArg = pPerfObject;
  1665. if (pPerfObject->NumInstances == PERF_NO_INSTANCES) {
  1666. // then just look up the counter
  1667. pPerfCounter = GetCounterDefByTitleIndex(pPerfObject,
  1668. ((dwFlags & GPCDP_GET_BASE_DATA) ? TRUE : FALSE),
  1669. pplCtr->dwCounterId);
  1670. if (pPerfCounter != NULL) {
  1671. // get data and return it
  1672. pData = GetCounterDataPtr(pPerfObject, pPerfCounter);
  1673. if (pData != NULL) {
  1674. // test the pointer to see if it fails
  1675. __try {
  1676. dwTestValue = * (DWORD *) pData;
  1677. dwCStatus = PDH_CSTATUS_VALID_DATA;
  1678. }
  1679. __except (EXCEPTION_EXECUTE_HANDLER) {
  1680. pData = NULL;
  1681. dwCStatus = PDH_CSTATUS_INVALID_DATA;
  1682. }
  1683. }
  1684. else {
  1685. dwCStatus = PDH_CSTATUS_INVALID_DATA;
  1686. }
  1687. }
  1688. else {
  1689. // unable to find counter
  1690. dwCStatus = PDH_CSTATUS_NO_COUNTER;
  1691. }
  1692. }
  1693. else {
  1694. // find instance
  1695. if (pplCtr->lInstanceId == PERF_NO_UNIQUE_ID && pPath->szInstanceName != NULL) {
  1696. pPerfInstance = GetInstanceByName(pPerfData,
  1697. pPerfObject,
  1698. pPath->szInstanceName,
  1699. pPath->szParentName,
  1700. pPath->dwIndex);
  1701. if (pPerfInstance == NULL && pPath->szInstanceName[0] >= L'0' && pPath->szInstanceName[0] <= L'9') {
  1702. LONG lInstanceId = (LONG) _wtoi(pPath->szInstanceName);
  1703. pPerfInstance = GetInstanceByUniqueId(pPerfObject, lInstanceId);
  1704. }
  1705. }
  1706. else {
  1707. pPerfInstance = GetInstanceByUniqueId(pPerfObject, pplCtr->lInstanceId);
  1708. }
  1709. if (pPerfInstance != NULL) {
  1710. // instance found so find pointer to counter data
  1711. pPerfCounter = GetCounterDefByTitleIndex(pPerfObject,
  1712. ((dwFlags & GPCDP_GET_BASE_DATA) ? TRUE : FALSE),
  1713. pplCtr->dwCounterId);
  1714. if (pPerfCounter != NULL) {
  1715. // counter found so get data pointer
  1716. pData = GetInstanceCounterDataPtr(pPerfObject, pPerfInstance, pPerfCounter);
  1717. if (pData != NULL) {
  1718. // test the pointer to see if it's valid
  1719. __try {
  1720. dwTestValue = * (DWORD *) pData;
  1721. dwCStatus = PDH_CSTATUS_VALID_DATA;
  1722. }
  1723. __except (EXCEPTION_EXECUTE_HANDLER) {
  1724. pData = NULL;
  1725. dwCStatus = PDH_CSTATUS_INVALID_DATA;
  1726. }
  1727. }
  1728. else {
  1729. dwCStatus = PDH_CSTATUS_INVALID_DATA;
  1730. }
  1731. }
  1732. else {
  1733. // counter not found
  1734. dwCStatus = PDH_CSTATUS_NO_COUNTER;
  1735. }
  1736. }
  1737. else {
  1738. // instance not found
  1739. dwCStatus = PDH_CSTATUS_NO_INSTANCE;
  1740. }
  1741. }
  1742. }
  1743. else {
  1744. // unable to find object
  1745. dwCStatus = PDH_CSTATUS_NO_OBJECT;
  1746. }
  1747. if (pStatus != NULL) {
  1748. __try {
  1749. * pStatus = dwCStatus;
  1750. }
  1751. __except (EXCEPTION_EXECUTE_HANDLER) {
  1752. // ?
  1753. }
  1754. }
  1755. return pData;
  1756. }