Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1161 lines
43 KiB

  1. /*++
  2. Copyright (C) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. perfutil.c
  5. Abstract:
  6. Performance registry interface functions
  7. --*/
  8. #include <windows.h>
  9. #include "strsafe.h"
  10. #include <pdh.h>
  11. #include "pdhitype.h"
  12. #include "pdhidef.h"
  13. #include "perfdata.h"
  14. #include "pdhmsg.h"
  15. #include "strings.h"
  16. DWORD
  17. PdhiMakePerfLangId(
  18. LANGID lID,
  19. LPWSTR szBuffer
  20. );
  21. PPERF_MACHINE
  22. PdhiAddNewMachine(
  23. PPERF_MACHINE pLastMachine,
  24. LPWSTR szMachineName
  25. );
  26. PPERF_MACHINE pFirstMachine = NULL;
  27. PDH_STATUS
  28. ConnectMachine(
  29. PPERF_MACHINE pThisMachine
  30. )
  31. {
  32. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  33. LONG lStatus = ERROR_SUCCESS;
  34. FILETIME CurrentFileTime;
  35. LONGLONG llCurrentTime;
  36. WCHAR szOsVer[OS_VER_SIZE];
  37. HKEY hKeyRemMachine;
  38. HKEY hKeyRemCurrentVersion;
  39. DWORD dwBufSize;
  40. DWORD dwType;
  41. BOOL bUpdateRetryTime = FALSE;
  42. DWORD dwReconnecting;
  43. if (pThisMachine == NULL) {
  44. pdhStatus = PDH_INVALID_ARGUMENT;
  45. } else {
  46. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX(pThisMachine->hMutex);
  47. }
  48. if (pdhStatus == ERROR_SUCCESS) {
  49. // connect to system's performance registry
  50. if (lstrcmpiW(pThisMachine->szName, szStaticLocalMachineName) == 0) {
  51. // only one thread at a time can try to connect to a machine.
  52. pThisMachine->dwRefCount++;
  53. // assign default OS version
  54. // assume NT4 unless found otherwise
  55. StringCchCopyW(pThisMachine->szOsVer, OS_VER_SIZE, (LPCWSTR) L"4.0");
  56. // this is the local machine so use the local reg key
  57. pThisMachine->hKeyPerformanceData = HKEY_PERFORMANCE_DATA;
  58. // look up the OS version and save it
  59. lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, cszCurrentVersionKey, 0L, KEY_READ, & hKeyRemCurrentVersion);
  60. if (lStatus == ERROR_SUCCESS) {
  61. dwType=0;
  62. dwBufSize = OS_VER_SIZE * sizeof(WCHAR);
  63. lStatus = RegQueryValueExW(hKeyRemCurrentVersion,
  64. cszCurrentVersionValueName,
  65. 0L,
  66. & dwType,
  67. (LPBYTE) szOsVer,
  68. & dwBufSize);
  69. if ((lStatus == ERROR_SUCCESS) && (dwType == REG_SZ)) {
  70. StringCchCopyW(pThisMachine->szOsVer, OS_VER_SIZE, szOsVer);
  71. }
  72. RegCloseKey(hKeyRemCurrentVersion);
  73. }
  74. }
  75. else {
  76. // now try to connect if the retry timeout has elapzed
  77. GetSystemTimeAsFileTime(& CurrentFileTime);
  78. llCurrentTime = MAKELONGLONG(CurrentFileTime.dwLowDateTime, CurrentFileTime.dwHighDateTime);
  79. dwReconnecting = (DWORD)InterlockedCompareExchange((PLONG) & pThisMachine->dwRetryFlags, TRUE, FALSE);
  80. if (! dwReconnecting) {
  81. if ((pThisMachine->llRetryTime == 0) || (pThisMachine->llRetryTime <= llCurrentTime)) {
  82. // only one thread at a time can try to connect to a machine.
  83. pThisMachine->dwRefCount ++;
  84. bUpdateRetryTime = TRUE; // only update after an attempt has been made
  85. __try {
  86. // close any open keys
  87. if (pThisMachine->hKeyPerformanceData != NULL) {
  88. RegCloseKey(pThisMachine->hKeyPerformanceData);
  89. pThisMachine->hKeyPerformanceData = NULL;
  90. }
  91. }
  92. __except (EXCEPTION_EXECUTE_HANDLER) {
  93. lStatus = GetExceptionCode();
  94. }
  95. if (lStatus != ERROR_SUCCESS) {
  96. pThisMachine->hKeyPerformanceData = NULL;
  97. }
  98. else {
  99. // get OS version of remote machine
  100. lStatus = RegConnectRegistryW(pThisMachine->szName,
  101. HKEY_LOCAL_MACHINE,
  102. & hKeyRemMachine);
  103. if (lStatus == ERROR_SUCCESS) {
  104. // look up the OS version and save it
  105. lStatus = RegOpenKeyExW(hKeyRemMachine,
  106. cszCurrentVersionKey,
  107. 0L,
  108. KEY_READ,
  109. & hKeyRemCurrentVersion);
  110. if (lStatus == ERROR_SUCCESS) {
  111. dwType=0;
  112. dwBufSize = OS_VER_SIZE * sizeof(WCHAR);
  113. lStatus = RegQueryValueExW(hKeyRemCurrentVersion,
  114. cszCurrentVersionValueName,
  115. 0L,
  116. & dwType,
  117. (LPBYTE) szOsVer,
  118. & dwBufSize);
  119. if ((lStatus == ERROR_SUCCESS) && (dwType == REG_SZ)) {
  120. StringCchCopyW(pThisMachine->szOsVer, OS_VER_SIZE, szOsVer);
  121. }
  122. RegCloseKey(hKeyRemCurrentVersion);
  123. }
  124. RegCloseKey(hKeyRemMachine);
  125. }
  126. }
  127. if (lStatus == ERROR_SUCCESS) {
  128. __try {
  129. // Connect to remote registry
  130. lStatus = RegConnectRegistryW(pThisMachine->szName,
  131. HKEY_PERFORMANCE_DATA,
  132. & pThisMachine->hKeyPerformanceData);
  133. }
  134. __except (EXCEPTION_EXECUTE_HANDLER) {
  135. lStatus = GetExceptionCode();
  136. }
  137. } // else pass error through
  138. }
  139. else {
  140. // not time to reconnect yet so save the old status and
  141. // clear the registry key
  142. pThisMachine->hKeyPerformanceData = NULL;
  143. lStatus = pThisMachine->dwStatus;
  144. }
  145. // clear the reconnecting flag
  146. InterlockedExchange((LONG *) & pThisMachine->dwRetryFlags, FALSE);
  147. }
  148. else {
  149. // some other thread is trying to connect
  150. pdhStatus = PDH_CANNOT_CONNECT_MACHINE;
  151. goto Cleanup;
  152. }
  153. }
  154. if ((pThisMachine->hKeyPerformanceData != NULL) && (pThisMachine->dwRetryFlags == 0)) {
  155. // successfully connected to computer's registry, so
  156. // get the performance names from that computer and cache them
  157. /*
  158. the shortcut of mapping local strings cannot be used reliably until
  159. more synchronization of the mapped file is implemented. Just Mapping
  160. to the file and not locking it or checking for updates leaves it
  161. vulnerable to the mapped file being changed by an external program
  162. and invalidating the pointer table built by the BuildLocalNameTable
  163. function.
  164. Until this synchronization and locking is implemented, the
  165. BuildLocalNameTable function should not be used.
  166. */
  167. if (pThisMachine->hKeyPerformanceData != HKEY_PERFORMANCE_DATA) {
  168. if (pThisMachine->szPerfStrings != NULL) {
  169. // reload the perf strings, incase new ones have been
  170. // installed
  171. if (pThisMachine->sz009PerfStrings != NULL
  172. && pThisMachine->sz009PerfStrings != pThisMachine->szPerfStrings) {
  173. G_FREE(pThisMachine->sz009PerfStrings);
  174. }
  175. G_FREE(pThisMachine->typePerfStrings);
  176. G_FREE(pThisMachine->szPerfStrings);
  177. pThisMachine->sz009PerfStrings = NULL;
  178. pThisMachine->typePerfStrings = NULL;
  179. pThisMachine->szPerfStrings = NULL;
  180. }
  181. BuildNameTable(pThisMachine->szName, GetUserDefaultUILanguage(), pThisMachine);
  182. if (pThisMachine->szPerfStrings == NULL) {
  183. BuildNameTable(pThisMachine->szName, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), pThisMachine);
  184. }
  185. }
  186. else {
  187. if (pThisMachine->szPerfStrings != NULL) {
  188. // reload the perf strings, incase new ones have been
  189. // installed
  190. if (pThisMachine->sz009PerfStrings != NULL
  191. && pThisMachine->sz009PerfStrings != pThisMachine->szPerfStrings) {
  192. G_FREE(pThisMachine->sz009PerfStrings);
  193. }
  194. G_FREE(pThisMachine->typePerfStrings);
  195. G_FREE(pThisMachine->szPerfStrings);
  196. pThisMachine->sz009PerfStrings = NULL;
  197. pThisMachine->typePerfStrings = NULL;
  198. pThisMachine->szPerfStrings = NULL;
  199. }
  200. BuildNameTable(NULL, GetUserDefaultUILanguage(), pThisMachine);
  201. if (pThisMachine->szPerfStrings == NULL) {
  202. BuildNameTable(NULL, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), pThisMachine);
  203. }
  204. pThisMachine->pLocalNameInfo = NULL;
  205. }
  206. if (pThisMachine->szPerfStrings != NULL) {
  207. pdhStatus = ERROR_SUCCESS;
  208. pThisMachine->dwStatus = ERROR_SUCCESS;
  209. }
  210. else {
  211. // unable to read system counter name strings
  212. pdhStatus = PDH_CANNOT_READ_NAME_STRINGS;
  213. ZeroMemory(& pThisMachine->LastStringUpdateTime, sizeof(pThisMachine->LastStringUpdateTime));
  214. pThisMachine->dwLastPerfString = 0;
  215. pThisMachine->dwStatus = PDH_CSTATUS_NO_MACHINE;
  216. }
  217. }
  218. else {
  219. // unable to connect to the specified machine
  220. pdhStatus = PDH_CANNOT_CONNECT_MACHINE;
  221. // Set error to either
  222. // "PDH_CSTATUS_NO_MACHINE" if no connection could be made
  223. // or
  224. // PDH_ACCESS_DENIED if ERROR_ACCESS_DENIED status is returned
  225. // since if ERROR_ACCESS_DENIED is returned, then reconnection will
  226. // probably be futile.
  227. if ((lStatus == ERROR_ACCESS_DENIED) || (lStatus == PDH_ACCESS_DENIED)) {
  228. pThisMachine->dwStatus = PDH_ACCESS_DENIED;
  229. }
  230. else {
  231. pThisMachine->dwStatus = PDH_CSTATUS_NO_MACHINE;
  232. }
  233. }
  234. if (pdhStatus != ERROR_SUCCESS) {
  235. if (bUpdateRetryTime) {
  236. // this attempt didn't work so reset retry counter to
  237. // wait some more for the machine to come back up.
  238. GetSystemTimeAsFileTime(& CurrentFileTime);
  239. llCurrentTime = MAKELONGLONG(CurrentFileTime.dwLowDateTime, CurrentFileTime.dwHighDateTime);
  240. pThisMachine->llRetryTime = llCurrentTime;
  241. if (pThisMachine->dwStatus != PDH_ACCESS_DENIED) {
  242. pThisMachine->llRetryTime += llRemoteRetryTime;
  243. }
  244. }
  245. }
  246. else {
  247. // clear the retry counter to allow function calls
  248. pThisMachine->llRetryTime = 0;
  249. }
  250. pThisMachine->dwRefCount --;
  251. RELEASE_MUTEX(pThisMachine->hMutex);
  252. }
  253. Cleanup:
  254. return pdhStatus;
  255. }
  256. PPERF_MACHINE
  257. PdhiAddNewMachine(
  258. PPERF_MACHINE pLastMachine,
  259. LPWSTR szMachineName
  260. )
  261. {
  262. PPERF_MACHINE pNewMachine = NULL;
  263. LPWSTR szNameBuffer = NULL;
  264. LPWSTR szIdList = NULL;
  265. DWORD dwNameSize = 0;
  266. BOOL bUseLocalName = TRUE;
  267. // reset the last error value
  268. SetLastError(ERROR_SUCCESS);
  269. if (szMachineName != NULL) {
  270. if (* szMachineName != L'\0') {
  271. bUseLocalName = FALSE;
  272. }
  273. }
  274. if (bUseLocalName) {
  275. dwNameSize = lstrlenW(szStaticLocalMachineName) + 1;
  276. } else {
  277. dwNameSize = lstrlenW(szMachineName) + 1;
  278. }
  279. pNewMachine = (PPERF_MACHINE) G_ALLOC(sizeof(PERF_MACHINE) + SMALL_BUFFER_SIZE + (sizeof(WCHAR) * dwNameSize));
  280. if (pNewMachine != NULL) {
  281. szIdList = (LPWSTR) ((LPBYTE) pNewMachine + sizeof(PERF_MACHINE));
  282. szNameBuffer = (LPWSTR) ((LPBYTE) szIdList + SMALL_BUFFER_SIZE);
  283. // initialize the new buffer
  284. pNewMachine->hKeyPerformanceData = NULL;
  285. pNewMachine->pLocalNameInfo = NULL;
  286. pNewMachine->szName = szNameBuffer;
  287. if (bUseLocalName) {
  288. StringCchCopyW(pNewMachine->szName, dwNameSize, szStaticLocalMachineName);
  289. }
  290. else {
  291. StringCchCopyW(pNewMachine->szName, dwNameSize, szMachineName);
  292. }
  293. pNewMachine->pSystemPerfData = NULL;
  294. pNewMachine->szPerfStrings = NULL;
  295. pNewMachine->sz009PerfStrings = NULL;
  296. pNewMachine->typePerfStrings = NULL;
  297. pNewMachine->dwLastPerfString = 0;
  298. pNewMachine->dwRefCount = 0;
  299. pNewMachine->szQueryObjects = szIdList;
  300. pNewMachine->dwStatus = PDH_CSTATUS_NO_MACHINE; // not connected yet
  301. pNewMachine->llRetryTime = 1; // retry connection immediately
  302. pNewMachine->dwRetryFlags = 0; // Not attempting a connection.
  303. pNewMachine->dwMachineFlags = 0;
  304. pNewMachine->hMutex = CreateMutex(NULL, FALSE, NULL);
  305. // everything went OK so far so add this entry to the list
  306. if (pLastMachine != NULL) {
  307. pNewMachine->pNext = pLastMachine->pNext;
  308. pLastMachine->pNext = pNewMachine;
  309. pNewMachine->pPrev = pLastMachine;
  310. pNewMachine->pNext->pPrev = pNewMachine;
  311. }
  312. else {
  313. // this is the first item in the list so it
  314. // points to itself
  315. pNewMachine->pNext = pNewMachine;
  316. pNewMachine->pPrev = pNewMachine;
  317. }
  318. }
  319. else {
  320. // unable to allocate machine data memory
  321. SetLastError(PDH_MEMORY_ALLOCATION_FAILURE);
  322. }
  323. return pNewMachine;
  324. }
  325. PPERF_MACHINE
  326. GetMachine(
  327. LPWSTR szMachineName,
  328. DWORD dwIndex,
  329. DWORD dwFlags
  330. )
  331. {
  332. PPERF_MACHINE pThisMachine = NULL;
  333. PPERF_MACHINE pLastMachine;
  334. BOOL bFound = FALSE;
  335. LPWSTR szFnMachineName;
  336. BOOL bNew = FALSE; // true if this is a new machine to the list
  337. BOOL bUseLocalName = TRUE;
  338. DWORD dwLocalStatus = ERROR_SUCCESS;
  339. WCHAR wszObject[MAX_PATH];
  340. // reset the last error value
  341. SetLastError(ERROR_SUCCESS);
  342. if (WAIT_FOR_AND_LOCK_MUTEX (hPdhDataMutex) == ERROR_SUCCESS) {
  343. if (szMachineName != NULL) {
  344. if (* szMachineName != L'\0') {
  345. bUseLocalName = FALSE;
  346. }
  347. }
  348. if (bUseLocalName) {
  349. szFnMachineName = szStaticLocalMachineName;
  350. }
  351. else {
  352. szFnMachineName = szMachineName;
  353. }
  354. // walk down list to find this machine
  355. pThisMachine = pFirstMachine;
  356. pLastMachine = NULL;
  357. // walk around entire list
  358. if (pThisMachine != NULL) {
  359. do {
  360. // walk down the list and look for a match
  361. if (lstrcmpiW(szFnMachineName, pThisMachine->szName) != 0) {
  362. pLastMachine = pThisMachine;
  363. pThisMachine = pThisMachine->pNext;
  364. }
  365. else {
  366. bFound = TRUE;
  367. break;
  368. }
  369. }
  370. while (pThisMachine != pFirstMachine);
  371. }
  372. // if thismachine == the first machine, then we couldn't find a match in
  373. // the list, if this machine is NULL, then there is no list
  374. if (! bFound) {
  375. // then this machine was not found so add it.
  376. pThisMachine = PdhiAddNewMachine(pLastMachine, szFnMachineName);
  377. if (pThisMachine != NULL) {
  378. bNew = TRUE;
  379. if (pFirstMachine == NULL) {
  380. // then update the first pointer
  381. pFirstMachine = pThisMachine;
  382. }
  383. }
  384. else {
  385. dwLocalStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  386. }
  387. }
  388. if (dwLocalStatus == ERROR_SUCCESS) {
  389. dwLocalStatus = WAIT_FOR_AND_LOCK_MUTEX(pThisMachine->hMutex);
  390. }
  391. if (dwLocalStatus == ERROR_SUCCESS) {
  392. if (! (dwFlags & PDH_GM_UPDATE_PERFNAME_ONLY)) {
  393. if (dwFlags & PDH_GM_UPDATE_PERFDATA) {
  394. pThisMachine->dwObjectId = dwIndex;
  395. pThisMachine->dwThreadId = GetCurrentThreadId();
  396. }
  397. else if (pThisMachine->dwThreadId != GetCurrentThreadId()) {
  398. dwFlags |= PDH_GM_UPDATE_PERFDATA;
  399. pThisMachine->dwThreadId = GetCurrentThreadId();
  400. pThisMachine->dwObjectId = dwIndex;
  401. }
  402. else if (pThisMachine->pSystemPerfData == NULL) {
  403. dwFlags |= PDH_GM_UPDATE_PERFDATA;
  404. pThisMachine->dwObjectId = dwIndex;
  405. }
  406. else if (pThisMachine->dwObjectId != 0 && pThisMachine->dwObjectId != dwIndex) {
  407. dwFlags |= PDH_GM_UPDATE_PERFDATA;
  408. pThisMachine->dwObjectId = dwIndex;
  409. }
  410. }
  411. if ((! bFound) || (dwFlags & PDH_GM_UPDATE_PERFDATA) || (dwFlags & PDH_GM_UPDATE_NAME)
  412. || (pThisMachine->dwStatus != ERROR_SUCCESS)) {
  413. // then this is a new machine or the caller wants the data refreshed or the machine
  414. // has an entry, but is not yet on line first try to connect to the machine
  415. // the call to ConnectMachine updates the machine status so there's no need to keep it here.
  416. BOOL bUpdateName = TRUE;
  417. if (! (dwFlags & PDH_GM_UPDATE_NAME)) {
  418. if (pThisMachine->szPerfStrings != NULL && pThisMachine->typePerfStrings != NULL) {
  419. // No need to update performance name/explain strings, assume that they are OK.
  420. //
  421. bUpdateName = FALSE;
  422. }
  423. }
  424. if (bUpdateName || pThisMachine->dwStatus != ERROR_SUCCESS) {
  425. G_FREE(pThisMachine->pSystemPerfData);
  426. pThisMachine->pSystemPerfData = NULL;
  427. dwLocalStatus = ConnectMachine(pThisMachine);
  428. }
  429. if (dwLocalStatus != ERROR_SUCCESS) {
  430. dwLocalStatus = pThisMachine->dwStatus;
  431. }
  432. else if (! (dwFlags & PDH_GM_UPDATE_PERFNAME_ONLY)) {
  433. // connected to the machine so
  434. // then lock access to it
  435. // the caller of this function must release the mutex
  436. if (dwFlags & PDH_GM_UPDATE_PERFDATA) {
  437. // get the current system counter info
  438. ZeroMemory(wszObject, MAX_PATH * sizeof(WCHAR));
  439. if (pThisMachine->dwObjectId == 0) {
  440. StringCchCopyW(wszObject, MAX_PATH, (LPWSTR) cszGlobal);
  441. }
  442. else {
  443. StringCchPrintfW(wszObject, MAX_PATH, L"%d", pThisMachine->dwObjectId);
  444. }
  445. pThisMachine->dwStatus = GetSystemPerfData(
  446. pThisMachine->hKeyPerformanceData,
  447. & pThisMachine->pSystemPerfData,
  448. wszObject,
  449. (BOOL) (dwFlags & PDH_GM_READ_COSTLY_DATA)
  450. );
  451. if ((dwFlags & PDH_GM_READ_COSTLY_DATA) && (pThisMachine->dwStatus == ERROR_SUCCESS)) {
  452. pThisMachine->dwMachineFlags |= PDHIPM_FLAGS_HAVE_COSTLY;
  453. }
  454. else {
  455. pThisMachine->dwMachineFlags &= ~PDHIPM_FLAGS_HAVE_COSTLY;
  456. }
  457. dwLocalStatus = pThisMachine->dwStatus;
  458. }
  459. }
  460. }
  461. }
  462. else {
  463. pThisMachine = NULL;
  464. dwLocalStatus = WAIT_TIMEOUT;
  465. }
  466. if (pThisMachine != NULL) {
  467. // machine found so bump the ref count
  468. // NOTE!!! the caller must release this!!!
  469. pThisMachine->dwRefCount ++;
  470. }
  471. // at this point if pThisMachine is NULL then it was not found, nor
  472. // could it be added otherwise it is pointing to the matching machine
  473. // structure
  474. RELEASE_MUTEX(hPdhDataMutex);
  475. }
  476. else {
  477. dwLocalStatus = WAIT_TIMEOUT;
  478. }
  479. if (dwLocalStatus != ERROR_SUCCESS) {
  480. SetLastError(dwLocalStatus);
  481. }
  482. return pThisMachine;
  483. }
  484. BOOL
  485. FreeMachine(
  486. PPERF_MACHINE pMachine,
  487. BOOL bForceRelease,
  488. BOOL bProcessExit
  489. )
  490. {
  491. PPERF_MACHINE pPrev;
  492. PPERF_MACHINE pNext;
  493. HANDLE hMutex;
  494. // unlink if this isn't the only one in the list
  495. if ((!bForceRelease) && (pMachine->dwRefCount)) return FALSE;
  496. hMutex = pMachine->hMutex;
  497. if (WAIT_FOR_AND_LOCK_MUTEX (hMutex) != ERROR_SUCCESS) {
  498. SetLastError(WAIT_TIMEOUT);
  499. return FALSE;
  500. }
  501. pPrev = pMachine->pPrev;
  502. pNext = pMachine->pNext;
  503. if ((pPrev != pMachine) && (pNext != pMachine)) {
  504. // this is not the only entry in the list
  505. pPrev->pNext = pNext;
  506. pNext->pPrev = pPrev;
  507. if (pMachine == pFirstMachine) {
  508. // then we are deleting the first one in the list so
  509. // update the list head to point to the next one in line
  510. pFirstMachine = pNext;
  511. }
  512. }
  513. else {
  514. // this is the only entry so clear the head pointer
  515. pFirstMachine = NULL;
  516. }
  517. // now free all allocated memory
  518. G_FREE(pMachine->pSystemPerfData);
  519. G_FREE(pMachine->typePerfStrings);
  520. if (pMachine->sz009PerfStrings != NULL && pMachine->sz009PerfStrings != pMachine->szPerfStrings) {
  521. G_FREE(pMachine->sz009PerfStrings);
  522. }
  523. G_FREE(pMachine->szPerfStrings);
  524. // close key
  525. if (pMachine->hKeyPerformanceData != NULL) {
  526. if ((! bProcessExit) || pMachine->hKeyPerformanceData != HKEY_PERFORMANCE_DATA) {
  527. RegCloseKey(pMachine->hKeyPerformanceData);
  528. }
  529. pMachine->hKeyPerformanceData = NULL;
  530. }
  531. // free memory block
  532. G_FREE(pMachine);
  533. // release and close mutex
  534. RELEASE_MUTEX(hMutex);
  535. if (hMutex != NULL) {
  536. CloseHandle(hMutex);
  537. }
  538. return TRUE;
  539. }
  540. BOOL
  541. FreeAllMachines (
  542. BOOL bProcessExit
  543. )
  544. {
  545. PPERF_MACHINE pThisMachine;
  546. // free any machines in the machine list
  547. if (pFirstMachine != NULL) {
  548. if (WAIT_FOR_AND_LOCK_MUTEX (hPdhDataMutex) == ERROR_SUCCESS) {
  549. pThisMachine = pFirstMachine;
  550. while (pFirstMachine != pFirstMachine->pNext) {
  551. // delete from list
  552. // the deletion routine updates the prev pointer as it
  553. // removes the specified entry.
  554. FreeMachine(pThisMachine->pPrev, TRUE, bProcessExit);
  555. if (pFirstMachine == NULL) break;
  556. }
  557. // remove last query
  558. if (pFirstMachine) {
  559. FreeMachine(pFirstMachine, TRUE, bProcessExit);
  560. }
  561. pFirstMachine = NULL;
  562. RELEASE_MUTEX (hPdhDataMutex);
  563. }
  564. else {
  565. SetLastError (WAIT_TIMEOUT);
  566. return FALSE;
  567. }
  568. }
  569. return TRUE;
  570. }
  571. DWORD
  572. GetObjectId(
  573. PPERF_MACHINE pMachine,
  574. LPWSTR szObjectName,
  575. BOOL * bInstances
  576. )
  577. {
  578. PPERF_OBJECT_TYPE pObject = NULL;
  579. DWORD dwIndex = 2;
  580. DWORD dwRtnIndex = (DWORD) -1;
  581. LPWSTR szName;
  582. WCHAR szIndex[MAX_PATH];
  583. BOOL bName = TRUE;
  584. BOOL bCheck;
  585. if (pMachine->szPerfStrings == NULL || dwIndex > pMachine->dwLastPerfString) return dwRtnIndex;
  586. while (dwRtnIndex == (DWORD) -1) {
  587. bCheck = TRUE;
  588. if (bName) {
  589. szName = pMachine->szPerfStrings[dwIndex];
  590. bCheck = (szName != NULL) ? TRUE : FALSE;
  591. if (bCheck) bCheck = (lstrcmpiW(szName, (LPWSTR) szObjectName) == 0) ? TRUE : FALSE;
  592. }
  593. if (bCheck) {
  594. if (pMachine->dwStatus != ERROR_SUCCESS) {
  595. bCheck = TRUE;
  596. }
  597. else if (pMachine->dwThreadId != GetCurrentThreadId()) {
  598. bCheck = TRUE;
  599. }
  600. else if (pMachine->pSystemPerfData == NULL) {
  601. bCheck = TRUE;
  602. }
  603. else if (pMachine->dwObjectId != 0 && pMachine->dwObjectId != dwIndex) {
  604. bCheck = TRUE;
  605. }
  606. else {
  607. bCheck = FALSE;
  608. }
  609. if (bCheck) {
  610. ZeroMemory(szIndex, MAX_PATH * sizeof(WCHAR));
  611. StringCchPrintfW(szIndex, MAX_PATH, L"%d", dwIndex);
  612. pMachine->dwStatus = GetSystemPerfData(
  613. pMachine->hKeyPerformanceData, & pMachine->pSystemPerfData, szIndex, FALSE);
  614. pMachine->dwThreadId = GetCurrentThreadId();
  615. pMachine->dwObjectId = dwIndex;
  616. }
  617. if (pMachine->dwStatus == ERROR_SUCCESS) {
  618. pObject = GetObjectDefByTitleIndex(pMachine->pSystemPerfData, dwIndex);
  619. if (pObject != NULL) {
  620. LPCWSTR szTmpObjectName = PdhiLookupPerfNameByIndex(pMachine, pObject->ObjectNameTitleIndex);
  621. TRACE((PDH_DBG_TRACE_INFO),
  622. (__LINE__,
  623. PDH_PERFUTIL,
  624. ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2),
  625. ERROR_SUCCESS,
  626. TRACE_WSTR(szObjectName),
  627. TRACE_WSTR(szTmpObjectName),
  628. TRACE_DWORD(pObject->ObjectNameTitleIndex),
  629. TRACE_DWORD(pObject->ObjectHelpTitleIndex),
  630. TRACE_DWORD(pObject->NumCounters),
  631. TRACE_DWORD(pObject->DefaultCounter),
  632. TRACE_DWORD(pObject->NumInstances),
  633. NULL));
  634. if (bInstances != NULL) {
  635. * bInstances = (pObject->NumInstances != PERF_NO_INSTANCES ? TRUE : FALSE);
  636. }
  637. dwRtnIndex = dwIndex;
  638. break;
  639. }
  640. }
  641. }
  642. if (! bName) {
  643. break;
  644. }
  645. else if (dwIndex >= pMachine->dwLastPerfString) {
  646. dwIndex = wcstoul(szObjectName, NULL, 10);
  647. bName = FALSE;
  648. if (dwIndex == 0) break;
  649. }
  650. else {
  651. dwIndex += 2;
  652. if (dwIndex > pMachine->dwLastPerfString) {
  653. dwIndex = wcstoul(szObjectName, NULL, 10);
  654. bName = FALSE;
  655. if (dwIndex == 0) break;
  656. }
  657. }
  658. }
  659. return dwRtnIndex;
  660. }
  661. DWORD
  662. GetCounterId (
  663. PPERF_MACHINE pMachine,
  664. DWORD dwObjectId,
  665. LPWSTR szCounterName
  666. )
  667. {
  668. PPERF_OBJECT_TYPE pObject;
  669. PPERF_COUNTER_DEFINITION pCounter;
  670. DWORD dwCounterTitle = (DWORD) -1;
  671. pObject = GetObjectDefByTitleIndex(pMachine->pSystemPerfData, dwObjectId);
  672. if (pObject != NULL) {
  673. pCounter = GetCounterDefByName(pObject, pMachine->dwLastPerfString, pMachine->szPerfStrings, szCounterName);
  674. if (pCounter != NULL) {
  675. // update counter name string
  676. LPCWSTR szTmpCounterName = PdhiLookupPerfNameByIndex(pMachine, pCounter->CounterNameTitleIndex);
  677. TRACE((PDH_DBG_TRACE_INFO),
  678. (__LINE__,
  679. PDH_PERFUTIL,
  680. ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2)
  681. | ARG_DEF(ARG_TYPE_ULONGX, 6),
  682. ERROR_SUCCESS,
  683. TRACE_WSTR(szCounterName),
  684. TRACE_WSTR(szTmpCounterName),
  685. TRACE_DWORD(dwObjectId),
  686. TRACE_DWORD(pCounter->CounterNameTitleIndex),
  687. TRACE_DWORD(pCounter->CounterHelpTitleIndex),
  688. TRACE_DWORD(pCounter->CounterType),
  689. TRACE_DWORD(pCounter->CounterSize),
  690. TRACE_DWORD(pCounter->CounterOffset),
  691. NULL));
  692. dwCounterTitle = pCounter->CounterNameTitleIndex;
  693. }
  694. else {
  695. dwCounterTitle = wcstoul(szCounterName, NULL, 10);
  696. if (dwCounterTitle == 0) dwCounterTitle = (DWORD) -1;
  697. }
  698. }
  699. return dwCounterTitle;
  700. }
  701. BOOL
  702. InitPerflibCounterInfo(
  703. PPDHI_COUNTER pCounter
  704. )
  705. /*++
  706. Routine Description:
  707. Initializes the perflib related fields of the counter structure
  708. Arguments:
  709. IN PPDHI_COUNTER pCounter
  710. pointer to the counter structure to initialize
  711. Return Value:
  712. TRUE
  713. --*/
  714. {
  715. PPERF_OBJECT_TYPE pPerfObject = NULL;
  716. PPERF_COUNTER_DEFINITION pPerfCounter = NULL;
  717. if (pCounter->pQMachine->pMachine == NULL) {
  718. pCounter->ThisValue.CStatus = PDH_CSTATUS_NO_MACHINE;
  719. return FALSE;
  720. } else if (pCounter->pQMachine->pMachine->dwStatus != ERROR_SUCCESS) {
  721. // machine not initialized
  722. return FALSE;
  723. }
  724. // get perf object definition from system data structure
  725. pPerfObject = GetObjectDefByTitleIndex (
  726. pCounter->pQMachine->pMachine->pSystemPerfData,
  727. pCounter->plCounterInfo.dwObjectId);
  728. if (pPerfObject != NULL) {
  729. // object was found now look up counter definition
  730. pPerfCounter = GetCounterDefByTitleIndex (pPerfObject, 0,
  731. pCounter->plCounterInfo.dwCounterId);
  732. if (pPerfCounter != NULL) {
  733. // get system perf data info
  734. // (pack into a DWORD)
  735. pCounter->CVersion = pCounter->pQMachine->pMachine->pSystemPerfData->Version;
  736. pCounter->CVersion &= 0x0000FFFF;
  737. pCounter->CVersion <<= 16;
  738. pCounter->CVersion &= 0xFFFF0000;
  739. pCounter->CVersion |= (pCounter->pQMachine->pMachine->pSystemPerfData->Revision & 0x0000FFFF);
  740. // get the counter's time base
  741. if (pPerfCounter->CounterType & PERF_TIMER_100NS) {
  742. pCounter->TimeBase = (LONGLONG)10000000;
  743. } else if (pPerfCounter->CounterType & PERF_OBJECT_TIMER) {
  744. // then get the time base freq from the object
  745. pCounter->TimeBase = pPerfObject->PerfFreq.QuadPart;
  746. } else { // if (pPerfCounter->CounterType & PERF_TIMER_TICK or other)
  747. pCounter->TimeBase = pCounter->pQMachine->pMachine->pSystemPerfData->PerfFreq.QuadPart;
  748. }
  749. // look up info from counter definition
  750. pCounter->plCounterInfo.dwCounterType =
  751. pPerfCounter->CounterType;
  752. pCounter->plCounterInfo.dwCounterSize =
  753. pPerfCounter->CounterSize;
  754. pCounter->plCounterInfo.lDefaultScale =
  755. pPerfCounter->DefaultScale;
  756. //
  757. // get explain text pointer
  758. pCounter->szExplainText =
  759. (LPWSTR)PdhiLookupPerfNameByIndex (
  760. pCounter->pQMachine->pMachine,
  761. pPerfCounter->CounterHelpTitleIndex);
  762. //
  763. // now clear/initialize the raw counter info
  764. //
  765. pCounter->ThisValue.TimeStamp.dwLowDateTime = 0;
  766. pCounter->ThisValue.TimeStamp.dwHighDateTime = 0;
  767. pCounter->ThisValue.MultiCount = 1;
  768. pCounter->ThisValue.FirstValue = 0;
  769. pCounter->ThisValue.SecondValue = 0;
  770. //
  771. pCounter->LastValue.TimeStamp.dwLowDateTime = 0;
  772. pCounter->LastValue.TimeStamp.dwHighDateTime = 0;
  773. pCounter->LastValue.MultiCount = 1;
  774. pCounter->LastValue.FirstValue = 0;
  775. pCounter->LastValue.SecondValue = 0;
  776. //
  777. // clear data array pointers
  778. //
  779. pCounter->pThisRawItemList = NULL;
  780. pCounter->pLastRawItemList = NULL;
  781. //
  782. // lastly update status
  783. //
  784. if (pCounter->ThisValue.CStatus == 0) {
  785. // don't overwrite any other status values
  786. pCounter->ThisValue.CStatus = PDH_CSTATUS_VALID_DATA;
  787. }
  788. return TRUE;
  789. } else {
  790. // unable to find counter
  791. pCounter->ThisValue.CStatus = PDH_CSTATUS_NO_COUNTER;
  792. return FALSE;
  793. }
  794. } else {
  795. // unable to find object
  796. pCounter->ThisValue.CStatus = PDH_CSTATUS_NO_OBJECT;
  797. return FALSE;
  798. }
  799. }
  800. #pragma warning ( disable : 4127 )
  801. STATIC_BOOL
  802. IsNumberInUnicodeList(
  803. DWORD dwNumber,
  804. LPWSTR lpwszUnicodeList
  805. )
  806. /*++
  807. IsNumberInUnicodeList
  808. Arguments:
  809. IN dwNumber
  810. DWORD number to find in list
  811. IN lpwszUnicodeList
  812. Null terminated, Space delimited list of decimal numbers
  813. Return Value:
  814. TRUE:
  815. dwNumber was found in the list of unicode number strings
  816. FALSE:
  817. dwNumber was not found in the list.
  818. --*/
  819. {
  820. DWORD dwThisNumber;
  821. LPWSTR pwcThisChar;
  822. BOOL bValidNumber;
  823. BOOL bNewItem;
  824. BOOL bReturn = FALSE;
  825. BOOL bDone = FALSE;
  826. WCHAR wcDelimiter; // could be an argument to be more flexible
  827. if (lpwszUnicodeList == 0) return FALSE; // null pointer, # not founde
  828. pwcThisChar = lpwszUnicodeList;
  829. dwThisNumber = 0;
  830. wcDelimiter = SPACE_L;
  831. bValidNumber = FALSE;
  832. bNewItem = TRUE;
  833. while (! bDone) {
  834. switch (EvalThisChar(* pwcThisChar, wcDelimiter)) {
  835. case DIGIT:
  836. // if this is the first digit after a delimiter, then
  837. // set flags to start computing the new number
  838. if (bNewItem) {
  839. bNewItem = FALSE;
  840. bValidNumber = TRUE;
  841. }
  842. if (bValidNumber) {
  843. dwThisNumber *= 10;
  844. dwThisNumber += (* pwcThisChar - (WCHAR) '0');
  845. }
  846. break;
  847. case DELIMITER:
  848. // a delimter is either the delimiter character or the
  849. // end of the string ('\0') if when the delimiter has been
  850. // reached a valid number was found, then compare it to the
  851. // number from the argument list. if this is the end of the
  852. // string and no match was found, then return.
  853. //
  854. if (bValidNumber) {
  855. if (dwThisNumber == dwNumber) {
  856. bDone = TRUE;
  857. bReturn = TRUE;
  858. }
  859. else {
  860. bValidNumber = FALSE;
  861. }
  862. }
  863. if (! bDone) {
  864. if (* pwcThisChar == L'\0') {
  865. bDone = TRUE;
  866. bReturn = FALSE;
  867. }
  868. else {
  869. bNewItem = TRUE;
  870. dwThisNumber = 0;
  871. }
  872. }
  873. break;
  874. case INVALID:
  875. // if an invalid character was encountered, ignore all
  876. // characters up to the next delimiter and then start fresh.
  877. // the invalid number is not compared.
  878. bValidNumber = FALSE;
  879. break;
  880. default:
  881. break;
  882. }
  883. pwcThisChar ++;
  884. }
  885. return bReturn;
  886. } // IsNumberInUnicodeList
  887. #pragma warning ( default : 4127 )
  888. BOOL
  889. AppendObjectToValueList(
  890. DWORD dwObjectId,
  891. PWSTR pwszValueList,
  892. DWORD dwValueList
  893. )
  894. /*++
  895. AppendObjectToValueList
  896. Arguments:
  897. IN dwNumber
  898. DWORD number to insert in list
  899. IN PWSTR
  900. pointer to wide char string that contains buffer that is
  901. Null terminated, Space delimited list of decimal numbers that
  902. may have this number appended to.
  903. Return Value:
  904. TRUE:
  905. dwNumber was added to list
  906. FALSE:
  907. dwNumber was not added. (because it's already there or
  908. an error occured)
  909. --*/
  910. {
  911. WCHAR tempString[16];
  912. BOOL bReturn = FALSE;
  913. LPWSTR szFormatString;
  914. if (!pwszValueList) {
  915. bReturn = FALSE;
  916. }
  917. else if (IsNumberInUnicodeList(dwObjectId, pwszValueList)) {
  918. bReturn = FALSE; // object already in list
  919. }
  920. else {
  921. __try {
  922. if (* pwszValueList == 0) {
  923. // then this is the first string so no delimiter
  924. szFormatString = (LPWSTR) fmtDecimal;
  925. }
  926. else {
  927. // this is being added to the end so include the delimiter
  928. szFormatString = (LPWSTR) fmtSpaceDecimal;
  929. }
  930. // format number and append the new object id the value list
  931. StringCchPrintfW(tempString, 16, szFormatString, dwObjectId);
  932. StringCchCatW(pwszValueList, dwValueList, tempString);
  933. bReturn = TRUE;
  934. }
  935. __except (EXCEPTION_EXECUTE_HANDLER) {
  936. bReturn = FALSE;
  937. }
  938. }
  939. return bReturn;
  940. }
  941. BOOL
  942. GetInstanceByNameMatch(
  943. PPERF_MACHINE pMachine,
  944. PPDHI_COUNTER pCounter
  945. )
  946. {
  947. PPERF_INSTANCE_DEFINITION pInstanceDef;
  948. PPERF_OBJECT_TYPE pObjectDef;
  949. LONG lInstanceId = PERF_NO_UNIQUE_ID;
  950. BOOL bReturn = FALSE;
  951. // get the instances object
  952. pObjectDef = GetObjectDefByTitleIndex(pMachine->pSystemPerfData, pCounter->plCounterInfo.dwObjectId);
  953. if (pObjectDef != NULL) {
  954. pInstanceDef = FirstInstance(pObjectDef);
  955. if (pInstanceDef != NULL) {
  956. if (pInstanceDef->UniqueID == PERF_NO_UNIQUE_ID) {
  957. // get instance in that object by comparing names
  958. // if there is no parent specified, then just look it up by name
  959. pInstanceDef = GetInstanceByName(pMachine->pSystemPerfData,
  960. pObjectDef,
  961. pCounter->pCounterPath->szInstanceName,
  962. pCounter->pCounterPath->szParentName,
  963. pCounter->pCounterPath->dwIndex);
  964. }
  965. else {
  966. // get numeric equivalent of Instance ID
  967. if (pCounter->pCounterPath->szInstanceName != NULL) {
  968. lInstanceId = wcstol(pCounter->pCounterPath->szInstanceName, NULL, 10);
  969. }
  970. pInstanceDef = GetInstanceByUniqueId(pObjectDef, lInstanceId);
  971. }
  972. // update counter fields
  973. pCounter->plCounterInfo.lInstanceId = lInstanceId;
  974. if (lInstanceId == -1) {
  975. // use instance NAME
  976. pCounter->plCounterInfo.szInstanceName = pCounter->pCounterPath->szInstanceName;
  977. pCounter->plCounterInfo.szParentInstanceName = pCounter->pCounterPath->szParentName;
  978. }
  979. else {
  980. // use instance ID number
  981. pCounter->plCounterInfo.szInstanceName = NULL;
  982. pCounter->plCounterInfo.szParentInstanceName = NULL;
  983. }
  984. }
  985. if (pInstanceDef != NULL) {
  986. // instance found
  987. bReturn = TRUE;
  988. }
  989. }
  990. return bReturn;
  991. }
  992. BOOL
  993. GetObjectPerfInfo(
  994. PPERF_DATA_BLOCK pPerfData,
  995. DWORD dwObjectId,
  996. LONGLONG * pPerfTime,
  997. LONGLONG * pPerfFreq
  998. )
  999. {
  1000. PPERF_OBJECT_TYPE pObject;
  1001. BOOL bReturn = FALSE;
  1002. pObject = GetObjectDefByTitleIndex(pPerfData, dwObjectId);
  1003. if (pObject != NULL) {
  1004. __try {
  1005. * pPerfTime = pObject->PerfTime.QuadPart;
  1006. * pPerfFreq = pObject->PerfFreq.QuadPart;
  1007. bReturn = TRUE;
  1008. }
  1009. __except (EXCEPTION_EXECUTE_HANDLER) {
  1010. bReturn = FALSE;
  1011. }
  1012. }
  1013. return bReturn;
  1014. }
  1015. PDH_STATUS
  1016. ValidateMachineConnection(
  1017. PPERF_MACHINE pMachine
  1018. )
  1019. {
  1020. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1021. HANDLE hThread;
  1022. DWORD ThreadId;
  1023. DWORD dwWaitStatus;
  1024. DWORD dwReconnecting;
  1025. LONGLONG llCurrentTime;
  1026. FILETIME CurrentFileTime;
  1027. // if a connection or request has failed, this will be
  1028. // set to an error status
  1029. if (pMachine != NULL) {
  1030. if (pMachine->dwStatus != ERROR_SUCCESS) {
  1031. // get the current time
  1032. GetSystemTimeAsFileTime(& CurrentFileTime);
  1033. llCurrentTime = MAKELONGLONG(CurrentFileTime.dwLowDateTime, CurrentFileTime.dwHighDateTime);
  1034. if (pMachine->llRetryTime <= llCurrentTime) {
  1035. if (pMachine->llRetryTime != 0) {
  1036. // see what's up by trying to reconnect
  1037. dwReconnecting = pMachine->dwRetryFlags;
  1038. if (!dwReconnecting) {
  1039. pdhStatus = ConnectMachine(pMachine);
  1040. }
  1041. else {
  1042. // a connection attempt is in process so do nothing here
  1043. pdhStatus = PDH_CANNOT_CONNECT_MACHINE;
  1044. }
  1045. }
  1046. }
  1047. else {
  1048. // it's not retry time, yet so machine is off line still
  1049. pdhStatus = PDH_CSTATUS_NO_MACHINE;
  1050. }
  1051. }
  1052. }
  1053. else {
  1054. pdhStatus = PDH_CSTATUS_NO_MACHINE;
  1055. }
  1056. return pdhStatus;
  1057. }