Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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