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.

2098 lines
73 KiB

  1. /*++
  2. Copyright (C) 1995-1999 Microsoft Corporation
  3. Module Name:
  4. query.c
  5. Abstract:
  6. Query management functions exposed in pdh.dll
  7. --*/
  8. #include <windows.h>
  9. #include <winperf.h>
  10. #include <math.h>
  11. #include "mbctype.h"
  12. #include "strsafe.h"
  13. #include <pdh.h>
  14. #include "pdhitype.h"
  15. #include "pdhidef.h"
  16. #include "pdhmsg.h"
  17. #include "strings.h"
  18. STATIC_BOOL IsValidLogHandle(IN HLOG hLog);
  19. PDH_FUNCTION PdhiRewindWmiLog(IN PPDHI_LOG pLog);
  20. // query link list head pointer
  21. PPDHI_QUERY PdhiDllHeadQueryPtr = NULL;
  22. STATIC_BOOL
  23. PdhiFreeQuery(
  24. PPDHI_QUERY pThisQuery
  25. )
  26. /*++
  27. Routine Description:
  28. removes the query from the list of queries and updates the list
  29. linkages
  30. Arguments:
  31. IN PPDHI_QUERY pThisQuery
  32. pointer to the query to remove. No testing is performed on
  33. this pointer so it's assumed to be a valid query pointer.
  34. The pointer is invalid when this function returns.
  35. Return Value:
  36. TRUE
  37. --*/
  38. {
  39. PPDHI_QUERY pPrevQuery;
  40. PPDHI_QUERY pNextQuery;
  41. PPDHI_COUNTER pThisCounter;
  42. PPDHI_QUERY_MACHINE pQMachine;
  43. PPDHI_QUERY_MACHINE pNextQMachine;
  44. LONG lStatus;
  45. BOOL bStatus;
  46. HANDLE hQueryMutex;
  47. if (WAIT_FOR_AND_LOCK_MUTEX(pThisQuery->hMutex) != ERROR_SUCCESS)
  48. return WAIT_TIMEOUT;
  49. TRACE((PDH_DBG_TRACE_INFO),
  50. (__LINE__,
  51. PDH_QUERY,
  52. ARG_DEF(ARG_TYPE_PTR, 1) | ARG_DEF(ARG_TYPE_ULONGX, 2),
  53. ERROR_SUCCESS,
  54. TRACE_PTR(pThisQuery),
  55. TRACE_DWORD(pThisQuery->dwFlags),
  56. NULL));
  57. hQueryMutex = pThisQuery->hMutex;
  58. // close any async data collection threads
  59. if (pThisQuery->hExitEvent != NULL) {
  60. RELEASE_MUTEX(pThisQuery->hMutex);
  61. // stop current thread first
  62. SetEvent(pThisQuery->hExitEvent);
  63. // wait 1 second for the thread to stop
  64. lStatus = WaitForSingleObject(pThisQuery->hAsyncThread, 10000L);
  65. if (lStatus == WAIT_TIMEOUT) {
  66. TRACE((PDH_DBG_TRACE_ERROR), (__LINE__, PDH_QUERY, 0, lStatus, NULL));
  67. }
  68. if (WAIT_FOR_AND_LOCK_MUTEX(pThisQuery->hMutex) != ERROR_SUCCESS)
  69. return WAIT_TIMEOUT;
  70. bStatus = CloseHandle(pThisQuery->hExitEvent);
  71. pThisQuery->hExitEvent = NULL;
  72. }
  73. // define pointers
  74. pPrevQuery = pThisQuery->next.blink;
  75. pNextQuery = pThisQuery->next.flink;
  76. // free any counters in counter list
  77. if ((pThisCounter = pThisQuery->pCounterListHead) != NULL) {
  78. while (pThisCounter->next.blink != pThisCounter->next.flink) {
  79. // delete from list
  80. // the deletion routine updates the blink pointer as it
  81. // removes the specified entry.
  82. FreeCounter(pThisCounter->next.blink);
  83. }
  84. // remove last counter
  85. FreeCounter(pThisCounter);
  86. pThisQuery->pCounterListHead = NULL;
  87. }
  88. if (!(pThisQuery->dwFlags & PDHIQ_WBEM_QUERY)) {
  89. // free allocated memory in the query
  90. if ((pQMachine = pThisQuery->pFirstQMachine) != NULL) {
  91. // Free list of machine pointers
  92. do {
  93. pNextQMachine = pQMachine->pNext;
  94. if (pQMachine->pPerfData != NULL) {
  95. G_FREE(pQMachine->pPerfData);
  96. }
  97. G_FREE(pQMachine);
  98. pQMachine = pNextQMachine;
  99. }
  100. while (pQMachine != NULL);
  101. pThisQuery->pFirstQMachine = NULL;
  102. }
  103. }
  104. if (pThisQuery->dwFlags & PDHIQ_WBEM_QUERY) {
  105. lStatus = PdhiFreeWbemQuery(pThisQuery);
  106. }
  107. if (pThisQuery->dwReleaseLog != FALSE && pThisQuery->hLog != H_REALTIME_DATASOURCE
  108. && pThisQuery->hLog != H_WBEM_DATASOURCE) {
  109. PdhCloseLog(pThisQuery->hLog, 0);
  110. pThisQuery->hLog = H_REALTIME_DATASOURCE;
  111. }
  112. if (pThisQuery->hOutLog != NULL && IsValidLogHandle(pThisQuery->hOutLog)) {
  113. PPDHI_LOG pOutLog = (PPDHI_LOG) pThisQuery->hOutLog;
  114. pOutLog->pQuery = NULL;
  115. }
  116. // update pointers
  117. if (pPrevQuery == pThisQuery && pNextQuery == pThisQuery) {
  118. // then this query is the only (i.e. last) one in the list
  119. PdhiDllHeadQueryPtr = NULL;
  120. }
  121. else {
  122. // update query list pointers
  123. pPrevQuery->next.flink = pNextQuery;
  124. pNextQuery->next.blink = pPrevQuery;
  125. if (PdhiDllHeadQueryPtr == pThisQuery) {
  126. // then this is the first entry in the list so point to the
  127. // next one in line
  128. PdhiDllHeadQueryPtr = pNextQuery;
  129. }
  130. }
  131. if (pThisQuery->hMutex != NULL) {
  132. pThisQuery->hMutex = NULL;
  133. }
  134. // delete this query
  135. G_FREE(pThisQuery);
  136. // release and free the query mutex
  137. RELEASE_MUTEX(hQueryMutex);
  138. CloseHandle(hQueryMutex);
  139. return TRUE;
  140. }
  141. PDH_FUNCTION
  142. PdhOpenQueryH(
  143. IN PDH_HLOG hDataSource,
  144. IN DWORD_PTR dwUserData,
  145. IN PDH_HQUERY * phQuery
  146. )
  147. {
  148. PPDHI_QUERY pNewQuery;
  149. PPDHI_QUERY pLastQuery;
  150. PDH_STATUS ReturnStatus = ERROR_SUCCESS;
  151. BOOL bWbemData = FALSE;
  152. PPDHI_LOG pDataSource = NULL;
  153. DWORD dwDataSource;
  154. DWORD_PTR dwLocalData;
  155. __try {
  156. dwLocalData = dwUserData;
  157. dwDataSource = DataSourceTypeH(hDataSource);
  158. }
  159. __except(EXCEPTION_EXECUTE_HANDLER) {
  160. ReturnStatus = PDH_INVALID_ARGUMENT;
  161. goto Cleanup;
  162. }
  163. if (phQuery == NULL) {
  164. ReturnStatus = PDH_INVALID_ARGUMENT;
  165. goto Cleanup;
  166. }
  167. if (dwDataSource == DATA_SOURCE_WBEM) {
  168. hDataSource = H_WBEM_DATASOURCE;
  169. bWbemData = TRUE;
  170. }
  171. if (dwDataSource == DATA_SOURCE_WBEM || dwDataSource == DATA_SOURCE_REGISTRY) {
  172. pDataSource = NULL;
  173. }
  174. else if (IsValidLogHandle(hDataSource)) {
  175. pDataSource = (PPDHI_LOG) hDataSource;
  176. }
  177. else {
  178. ReturnStatus = PDH_INVALID_ARGUMENT;
  179. goto Cleanup;
  180. }
  181. ReturnStatus = WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
  182. if (ReturnStatus == ERROR_SUCCESS) {
  183. pNewQuery = G_ALLOC(sizeof (PDHI_QUERY));
  184. if (pNewQuery == NULL) {
  185. ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  186. }
  187. if (ReturnStatus == ERROR_SUCCESS) {
  188. pNewQuery->hMutex = CreateMutexW(NULL, TRUE, NULL);
  189. * (DWORD *)(& pNewQuery->signature[0]) = SigQuery;
  190. if (PdhiDllHeadQueryPtr == NULL) {
  191. PdhiDllHeadQueryPtr = pNewQuery->next.flink = pNewQuery->next.blink = pNewQuery;
  192. }
  193. else {
  194. pLastQuery = PdhiDllHeadQueryPtr->next.blink;
  195. pNewQuery->next.flink = PdhiDllHeadQueryPtr;
  196. pNewQuery->next.blink = pLastQuery;
  197. PdhiDllHeadQueryPtr->next.blink = pNewQuery;
  198. pLastQuery->next.flink = pNewQuery;
  199. }
  200. pNewQuery->pCounterListHead = NULL;
  201. pNewQuery->pFirstQMachine = NULL;
  202. pNewQuery->dwLength = sizeof(PDHI_QUERY);
  203. pNewQuery->dwUserData = dwLocalData;
  204. pNewQuery->dwFlags = 0;
  205. pNewQuery->dwFlags |= (bWbemData ? PDHIQ_WBEM_QUERY : 0);
  206. pNewQuery->hLog = hDataSource;
  207. pNewQuery->dwReleaseLog = FALSE;
  208. if (pDataSource != NULL && LOWORD(pDataSource->dwLogFormat) == PDH_LOG_TYPE_BINARY) {
  209. ReturnStatus = PdhiRewindWmiLog(pDataSource);
  210. if (ReturnStatus != ERROR_SUCCESS) {
  211. RELEASE_MUTEX(pNewQuery->hMutex);
  212. RELEASE_MUTEX(hPdhDataMutex);
  213. goto Cleanup;
  214. }
  215. }
  216. pNewQuery->hOutLog = NULL;
  217. * (LONGLONG *)(& pNewQuery->TimeRange.StartTime) = MIN_TIME_VALUE;
  218. * (LONGLONG *)(& pNewQuery->TimeRange.EndTime) = MAX_TIME_VALUE;
  219. pNewQuery->TimeRange.SampleCount = 0;
  220. pNewQuery->dwLastLogIndex = 0;
  221. pNewQuery->dwInterval = 0;
  222. pNewQuery->hAsyncThread = NULL;
  223. pNewQuery->hExitEvent = NULL;
  224. pNewQuery->hNewDataEvent = NULL;
  225. pNewQuery->pRefresher = NULL;
  226. pNewQuery->pRefresherCfg = NULL;
  227. pNewQuery->LangID = GetUserDefaultUILanguage();
  228. RELEASE_MUTEX(pNewQuery->hMutex);
  229. __try {
  230. * phQuery = (HQUERY) pNewQuery;
  231. if(pDataSource != NULL) {
  232. pDataSource->pQuery = (HQUERY) pNewQuery;
  233. }
  234. ReturnStatus = ERROR_SUCCESS;
  235. }
  236. __except (EXCEPTION_EXECUTE_HANDLER) {
  237. if (pNewQuery != NULL) {
  238. PdhiFreeQuery(pNewQuery);
  239. }
  240. ReturnStatus = PDH_INVALID_ARGUMENT;
  241. }
  242. }
  243. RELEASE_MUTEX(hPdhDataMutex);
  244. }
  245. Cleanup:
  246. if (ReturnStatus == ERROR_SUCCESS) {
  247. if (hDataSource == H_REALTIME_DATASOURCE || hDataSource == H_WBEM_DATASOURCE) {
  248. dwCurrentRealTimeDataSource ++;
  249. }
  250. }
  251. TRACE((PDH_DBG_TRACE_INFO),
  252. (__LINE__,
  253. PDH_QUERY,
  254. ARG_DEF(ARG_TYPE_PTR, 1) | ARG_DEF(ARG_TYPE_PTR, 2)
  255. | ARG_DEF(ARG_TYPE_PTR, 3),
  256. ReturnStatus,
  257. TRACE_PTR(hDataSource),
  258. TRACE_PTR(phQuery),
  259. TRACE_PTR(pNewQuery),
  260. TRACE_DWORD(dwDataSource),
  261. TRACE_DWORD(dwCurrentRealTimeDataSource),
  262. NULL));
  263. return ReturnStatus;
  264. }
  265. PDH_FUNCTION
  266. PdhOpenQueryW(
  267. IN LPCWSTR szDataSource,
  268. IN DWORD_PTR dwUserData,
  269. IN PDH_HQUERY * phQuery
  270. )
  271. /*++
  272. Routine Description:
  273. allocates a new query structure and inserts it at the end of the
  274. query list.
  275. Arguments:
  276. IN LPCWSTR szDataSource
  277. the name of the data (log) file to read from or NULL if the
  278. current activity is desired.
  279. IN DWORD dwUserData
  280. the user defined data field for this query,
  281. Return Value:
  282. Returns ERROR_SUCCESS if a new query was created and initialized,
  283. and a PDH_ error value if not.
  284. PDH_INVALID_ARGUMENT is returned when one or more of the arguements
  285. is invalid or incorrect.
  286. PDH_MEMORY_ALLOCATION_FAILURE is returned when a memory buffer could
  287. not be allocated.
  288. --*/
  289. {
  290. PPDHI_QUERY pNewQuery;
  291. PPDHI_QUERY pLastQuery;
  292. PDH_STATUS ReturnStatus = ERROR_SUCCESS;
  293. HLOG hLogLocal = NULL;
  294. DWORD dwLogType = 0;
  295. BOOL bWbemData = FALSE;
  296. DWORD dwDataSource = 0;
  297. DWORD_PTR dwLocalData;
  298. // try writing to return pointer
  299. if (phQuery == NULL) {
  300. ReturnStatus = PDH_INVALID_ARGUMENT;
  301. }
  302. else {
  303. __try {
  304. if (szDataSource != NULL) {
  305. dwLocalData = lstrlenW(szDataSource);
  306. if (dwLocalData == 0 || dwLocalData > PDH_MAX_DATASOURCE_PATH) {
  307. ReturnStatus = PDH_INVALID_ARGUMENT;
  308. }
  309. else if (* szDataSource == L'\0') {
  310. // test for read access to the name
  311. ReturnStatus = PDH_INVALID_ARGUMENT;
  312. }
  313. } // else NULL is a valid arg
  314. if (ReturnStatus == ERROR_SUCCESS) {
  315. dwLocalData = dwUserData;
  316. dwDataSource = DataSourceTypeW(szDataSource);
  317. }
  318. }
  319. __except (EXCEPTION_EXECUTE_HANDLER) {
  320. ReturnStatus = PDH_INVALID_ARGUMENT;
  321. }
  322. }
  323. if (ReturnStatus == ERROR_SUCCESS) {
  324. // validate the data source
  325. switch (dwDataSource) {
  326. case DATA_SOURCE_LOGFILE:
  327. // then they are planning to read from a log file so
  328. // try to open it
  329. ReturnStatus = PdhOpenLogW(szDataSource,
  330. PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
  331. &dwLogType,
  332. NULL,
  333. 0,
  334. NULL,
  335. & hLogLocal);
  336. break;
  337. case DATA_SOURCE_WBEM:
  338. bWbemData = TRUE;
  339. // they want real-time data, so just keep going
  340. hLogLocal = NULL;
  341. break;
  342. case DATA_SOURCE_REGISTRY:
  343. // they want real-time data, so just keep going
  344. hLogLocal = NULL;
  345. break;
  346. default:
  347. break;
  348. }
  349. }
  350. if (ReturnStatus != ERROR_SUCCESS) goto Cleanup;
  351. ReturnStatus = WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
  352. if (ReturnStatus == ERROR_SUCCESS) {
  353. // allocate new memory
  354. pNewQuery = G_ALLOC(sizeof(PDHI_QUERY));
  355. if (pNewQuery == NULL) {
  356. ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  357. }
  358. if (ReturnStatus == ERROR_SUCCESS) {
  359. // create and capture the mutex for this query.
  360. pNewQuery->hMutex = CreateMutexW(NULL, TRUE, NULL);
  361. //initialize structures & list pointers
  362. // assign signature
  363. * (DWORD *) (& pNewQuery->signature[0]) = SigQuery;
  364. // update list pointers
  365. // test to see if this is the first query in the list
  366. if (PdhiDllHeadQueryPtr == NULL) {
  367. // then this is the first so fill in the static link pointers
  368. PdhiDllHeadQueryPtr = pNewQuery->next.flink = pNewQuery->next.blink = pNewQuery;
  369. }
  370. else {
  371. // get pointer to "last" entry in list
  372. pLastQuery = PdhiDllHeadQueryPtr->next.blink;
  373. // update new query pointers
  374. pNewQuery->next.flink = PdhiDllHeadQueryPtr;
  375. pNewQuery->next.blink = pLastQuery;
  376. // update existing pointers
  377. PdhiDllHeadQueryPtr->next.blink = pNewQuery;
  378. pLastQuery->next.flink = pNewQuery;
  379. }
  380. // initialize the counter linked list pointer
  381. pNewQuery->pCounterListHead = NULL;
  382. // initialize the machine list pointer
  383. pNewQuery->pFirstQMachine = NULL;
  384. // set length & user data
  385. pNewQuery->dwLength = sizeof(PDHI_QUERY);
  386. pNewQuery->dwUserData = dwLocalData;
  387. // initialize remaining data fields
  388. pNewQuery->dwFlags = 0;
  389. pNewQuery->dwFlags |= (bWbemData ? PDHIQ_WBEM_QUERY : 0);
  390. pNewQuery->hLog = hLogLocal;
  391. pNewQuery->hOutLog = NULL;
  392. pNewQuery->dwReleaseLog = TRUE;
  393. // initialize time range to include entire range
  394. * (LONGLONG *) (& pNewQuery->TimeRange.StartTime) = MIN_TIME_VALUE;
  395. * (LONGLONG *) (& pNewQuery->TimeRange.EndTime) = MAX_TIME_VALUE;
  396. pNewQuery->TimeRange.SampleCount = 0;
  397. pNewQuery->dwLastLogIndex = 0;
  398. pNewQuery->dwInterval = 0; // no auto interval
  399. pNewQuery->hAsyncThread = NULL; // timing thread;
  400. pNewQuery->hExitEvent = NULL; // async timing thread exit
  401. pNewQuery->hNewDataEvent = NULL; // no event
  402. // initialize WBEM Data fields
  403. pNewQuery->pRefresher = NULL;
  404. pNewQuery->pRefresherCfg = NULL;
  405. pNewQuery->LangID = GetUserDefaultUILanguage();
  406. // release the mutex for this query
  407. RELEASE_MUTEX(pNewQuery->hMutex);
  408. __try {
  409. // return new query pointer as a handle.
  410. * phQuery = (HQUERY) pNewQuery;
  411. ReturnStatus = ERROR_SUCCESS;
  412. }
  413. __except (EXCEPTION_EXECUTE_HANDLER) {
  414. if (pNewQuery != NULL) {
  415. // PdhiFreeQuery expects the data to be locked
  416. PdhiFreeQuery(pNewQuery);
  417. }
  418. ReturnStatus = PDH_INVALID_ARGUMENT;
  419. }
  420. }
  421. // release the data mutex
  422. RELEASE_MUTEX (hPdhDataMutex);
  423. }
  424. // if this query was added and it's a real-time query then disable
  425. // future calls to change the data source.
  426. if (ReturnStatus == ERROR_SUCCESS) {
  427. if (hLogLocal == NULL) {
  428. dwCurrentRealTimeDataSource ++;
  429. }
  430. else {
  431. PPDHI_LOG pLog = (PPDHI_LOG) hLogLocal;
  432. pLog->pQuery = pNewQuery;
  433. }
  434. }
  435. Cleanup:
  436. TRACE((PDH_DBG_TRACE_INFO),
  437. (__LINE__,
  438. PDH_QUERY,
  439. ARG_DEF(ARG_TYPE_PTR, 1) | ARG_DEF(ARG_TYPE_PTR, 2),
  440. ReturnStatus,
  441. TRACE_PTR(phQuery),
  442. TRACE_PTR(pNewQuery),
  443. TRACE_DWORD(dwDataSource),
  444. TRACE_DWORD(dwCurrentRealTimeDataSource),
  445. NULL));
  446. return ReturnStatus;
  447. }
  448. PDH_FUNCTION
  449. PdhOpenQueryA(
  450. IN LPCSTR szDataSource,
  451. IN DWORD_PTR dwUserData,
  452. IN PDH_HQUERY * phQuery
  453. )
  454. /*++
  455. Routine Description:
  456. allocates a new query structure and inserts it at the end of the
  457. query list.
  458. Arguments:
  459. IN LPCSTR szDataSource
  460. the name of the data (log) file to read from or NULL if the
  461. current activity is desired.
  462. IN DWORD dwUserData
  463. the user defined data field for this query,
  464. Return Value:
  465. Returns a valid query handle if successful or INVALID_HANDLE_VALUE
  466. if not. WIN32 Error status is retrieved using GetLastError()
  467. --*/
  468. {
  469. LPWSTR szWideArg = NULL;
  470. PDH_STATUS ReturnStatus = ERROR_SUCCESS;
  471. DWORD_PTR dwLocalData;
  472. if (phQuery == NULL) {
  473. ReturnStatus = PDH_INVALID_ARGUMENT;
  474. }
  475. else {
  476. __try {
  477. if (szDataSource != NULL) {
  478. DWORD dwLength = lstrlenA(szDataSource);
  479. if (dwLength == 0 || dwLength > PDH_MAX_DATASOURCE_PATH) {
  480. ReturnStatus = PDH_INVALID_ARGUMENT;
  481. }
  482. else {
  483. szWideArg = PdhiMultiByteToWideChar(_getmbcp(), (LPSTR) szDataSource);
  484. if (szWideArg == NULL) {
  485. // then a name was passed in but not converted to a wide
  486. // character string so a memory allocation failure occurred
  487. ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  488. }
  489. }
  490. }
  491. if (ReturnStatus == ERROR_SUCCESS) {
  492. * phQuery = NULL;
  493. dwLocalData = dwUserData;
  494. }
  495. }
  496. __except(EXCEPTION_EXECUTE_HANDLER) {
  497. ReturnStatus = PDH_INVALID_ARGUMENT;
  498. }
  499. }
  500. if (ReturnStatus == ERROR_SUCCESS) {
  501. // call wide char version of function
  502. ReturnStatus = PdhOpenQueryW(szWideArg, dwLocalData, phQuery);
  503. }
  504. G_FREE (szWideArg);
  505. // and return handle
  506. return ReturnStatus;
  507. }
  508. PDH_FUNCTION
  509. PdhiAddCounter(
  510. PDH_HQUERY hQuery,
  511. LPCWSTR szFullName,
  512. DWORD_PTR dwUserData,
  513. PDH_HCOUNTER * phCounter,
  514. PPDHI_COUNTER pNewCounter
  515. )
  516. /* Internal function called by PdhAddCounterW, PdhAddCounterA.
  517. Assumes that szFullName and pNewCounter are properly allocated,
  518. and initialized, i.e. szFullName has the counter path, and
  519. pNewCounter zeroed.
  520. */
  521. {
  522. PPDHI_COUNTER pLastCounter = NULL;
  523. PPDHI_QUERY pQuery = NULL;
  524. PDH_STATUS ReturnStatus = ERROR_SUCCESS;
  525. BOOL bStatus = TRUE;
  526. // we're changing the contents of PDH data so lock it
  527. * phCounter = NULL;
  528. ReturnStatus = WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
  529. if (ReturnStatus == ERROR_SUCCESS) {
  530. if (! IsValidQuery(hQuery)) {
  531. // invalid query handle
  532. ReturnStatus = PDH_INVALID_HANDLE;
  533. }
  534. else {
  535. // assign signature & length values
  536. * (DWORD *)(& pNewCounter->signature[0]) = SigCounter;
  537. pNewCounter->dwLength = sizeof(PDHI_COUNTER);
  538. pQuery = (PPDHI_QUERY) hQuery;
  539. ReturnStatus = WAIT_FOR_AND_LOCK_MUTEX(pQuery->hMutex);
  540. if (ReturnStatus == ERROR_SUCCESS) {
  541. // link to owning query
  542. pNewCounter->pOwner = pQuery;
  543. // set user data fields
  544. pNewCounter->dwUserData = (DWORD) dwUserData;
  545. // counter is not init'd yet
  546. pNewCounter->dwFlags = PDHIC_COUNTER_NOT_INIT;
  547. // initialize scale to 1X and let the caller make any changes
  548. pNewCounter->lScale = 0;
  549. pNewCounter->szFullName = (LPWSTR) szFullName;
  550. if (pQuery->dwFlags & PDHIQ_WBEM_QUERY) {
  551. pNewCounter->dwFlags |= PDHIC_WBEM_COUNTER;
  552. // then this is a WBEM query so use WBEM
  553. // functions to initialize it
  554. bStatus = WbemInitCounter(pNewCounter);
  555. }
  556. else {
  557. bStatus = InitCounter(pNewCounter);
  558. }
  559. // load counter data using data retrieved from system
  560. if (bStatus) {
  561. // update list pointers
  562. // test to see if this is the first query in the list
  563. if (pQuery->pCounterListHead == NULL) {
  564. // then this is the 1st so fill in the
  565. // static link pointers
  566. pQuery->pCounterListHead = pNewCounter->next.flink = pNewCounter->next.blink = pNewCounter;
  567. }
  568. else {
  569. pLastCounter = pQuery->pCounterListHead->next.blink;
  570. pNewCounter->next.flink = pQuery->pCounterListHead;
  571. pNewCounter->next.blink = pLastCounter;
  572. pLastCounter->next.flink = pNewCounter;
  573. pQuery->pCounterListHead->next.blink = pNewCounter;
  574. }
  575. * phCounter = (HCOUNTER) pNewCounter;
  576. ReturnStatus = ERROR_SUCCESS;
  577. }
  578. else {
  579. // get the error value
  580. ReturnStatus = GetLastError();
  581. }
  582. RELEASE_MUTEX (pQuery->hMutex);
  583. }
  584. }
  585. RELEASE_MUTEX(hPdhDataMutex);
  586. }
  587. TRACE((PDH_DBG_TRACE_INFO),
  588. (__LINE__,
  589. PDH_QUERY,
  590. ARG_DEF(ARG_TYPE_PTR, 1) | ARG_DEF(ARG_TYPE_PTR, 2)
  591. | ARG_DEF(ARG_TYPE_WSTR, 3),
  592. ReturnStatus,
  593. TRACE_PTR(pQuery),
  594. TRACE_PTR(pNewCounter),
  595. TRACE_WSTR(szFullName),
  596. TRACE_DWORD(pNewCounter->dwUserData),
  597. NULL));
  598. return ReturnStatus;
  599. }
  600. PDH_FUNCTION
  601. PdhAddCounterW(
  602. IN PDH_HQUERY hQuery,
  603. IN LPCWSTR szFullCounterPath,
  604. IN DWORD_PTR dwUserData,
  605. IN PDH_HCOUNTER * phCounter
  606. )
  607. /*++
  608. Routine Description:
  609. Creates and initializes a counter structure and attaches it to the
  610. specified query.
  611. Arguments:
  612. IN HQUERY hQuery
  613. handle of the query to attach this counter to once the counter
  614. entry has been successfully created.
  615. IN LPCWSTR szFullCounterPath
  616. pointer to the path string that describes the counter to add to
  617. the query referenced above. This string must specify a single
  618. counter. Wildcard path strings are not permitted.
  619. IN DWORD dwUserData
  620. the user defined data field for this query.
  621. IN HCOUNTER *phCounter
  622. pointer to the buffer that will get the handle value of the
  623. successfully created counter entry.
  624. Return Value:
  625. Returns ERROR_SUCCESS if a new query was created and initialized,
  626. and a PDH_ error value if not.
  627. PDH_INVALID_ARGUMENT is returned when one or more of the arguements
  628. is invalid or incorrect.
  629. PDH_MEMORY_ALLOCATION_FAILURE is returned when a memory buffer could
  630. not be allocated.
  631. PDH_INVALID_HANDLE is returned if the query handle is not valid.
  632. PDH_CSTATUS_NO_COUNTER is returned if the specified counter was
  633. not found
  634. PDH_CSTATUS_NO_OBJECT is returned if the specified object could
  635. not be found
  636. PDH_CSTATUS_NO_MACHINE is returned if a machine entry could not
  637. be created.
  638. PDH_CSTATUS_BAD_COUNTERNAME is returned if the counter name path
  639. string could not be parsed or interpreted
  640. PDH_CSTATUS_NO_COUNTERNAME is returned if an empty counter name
  641. path string is passed in
  642. PDH_FUNCTION_NOT_FOUND is returned if the calculation function
  643. for this counter could not be determined.
  644. --*/
  645. {
  646. PPDHI_COUNTER pNewCounter = NULL;
  647. PDH_STATUS ReturnStatus = ERROR_SUCCESS;
  648. SIZE_T nPathLen = 0;
  649. LPWSTR szFullName = NULL;
  650. PDH_HCOUNTER hLocalCounter = NULL;
  651. PDH_HQUERY hLocalQuery;
  652. DWORD_PTR dwLocalData;
  653. if (szFullCounterPath == NULL || phCounter == NULL) {
  654. return PDH_INVALID_ARGUMENT;
  655. }
  656. __try {
  657. hLocalQuery = hQuery;
  658. dwLocalData = dwUserData;
  659. * phCounter = NULL; // init to null
  660. nPathLen = lstrlenW(szFullCounterPath);
  661. if (nPathLen == 0 || nPathLen > PDH_MAX_COUNTER_PATH) {
  662. ReturnStatus = PDH_INVALID_ARGUMENT;
  663. }
  664. else {
  665. szFullName = G_ALLOC((nPathLen + 1) * sizeof(WCHAR));
  666. if (szFullName) {
  667. StringCchCopyW(szFullName, nPathLen + 1, szFullCounterPath);
  668. }
  669. else {
  670. ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  671. }
  672. }
  673. }
  674. __except (EXCEPTION_EXECUTE_HANDLER) {
  675. ReturnStatus = PDH_INVALID_ARGUMENT;
  676. }
  677. if (ReturnStatus == ERROR_SUCCESS) {
  678. pNewCounter = G_ALLOC(sizeof(PDHI_COUNTER));
  679. if (pNewCounter == NULL) {
  680. ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  681. }
  682. }
  683. // query handle is tested by PdhiAddCounter
  684. if (ReturnStatus == ERROR_SUCCESS) {
  685. ReturnStatus = PdhiAddCounter(hLocalQuery, szFullName, dwLocalData, & hLocalCounter, pNewCounter);
  686. if (ReturnStatus == ERROR_SUCCESS && hLocalCounter != NULL) {
  687. __try {
  688. * phCounter = hLocalCounter;
  689. }
  690. __except (EXCEPTION_EXECUTE_HANDLER) {
  691. ReturnStatus = PDH_INVALID_ARGUMENT;
  692. }
  693. }
  694. }
  695. if (ReturnStatus != ERROR_SUCCESS) {
  696. if (pNewCounter != NULL) {
  697. if (pNewCounter->szFullName == NULL) {
  698. G_FREE(szFullName);
  699. }
  700. if (! FreeCounter(pNewCounter)) {
  701. if (pNewCounter->szFullName != NULL) {
  702. G_FREE(pNewCounter->szFullName);
  703. }
  704. G_FREE(pNewCounter);
  705. }
  706. }
  707. else if (szFullName != NULL) { // allocated this, but not pNewCounter
  708. G_FREE(szFullName);
  709. }
  710. }
  711. return ReturnStatus;
  712. }
  713. PDH_FUNCTION
  714. PdhAddCounterA(
  715. IN PDH_HQUERY hQuery,
  716. IN LPCSTR szFullCounterPath,
  717. IN DWORD_PTR dwUserData,
  718. IN PDH_HCOUNTER * phCounter
  719. )
  720. /*++
  721. Routine Description:
  722. Creates and initializes a counter structure and attaches it to the
  723. specified query.
  724. Arguments:
  725. IN HQUERY hQuery
  726. handle of the query to attach this counter to once the counter
  727. entry has been successfully created.
  728. IN LPCSTR szFullCounterPath
  729. pointer to the path string that describes the counter to add to
  730. the query referenced above. This string must specify a single
  731. counter. Wildcard path strings are not permitted.
  732. IN DWORD dwUserData
  733. the user defined data field for this query.
  734. IN HCOUNTER *phCounter
  735. pointer to the buffer that will get the handle value of the
  736. successfully created counter entry.
  737. Return Value:
  738. Returns ERROR_SUCCESS if a new query was created and initialized,
  739. and a PDH_ error value if not.
  740. PDH_INVALID_ARGUMENT is returned when one or more of the arguements
  741. is invalid or incorrect.
  742. PDH_MEMORY_ALLOCATION_FAILURE is returned when a memory buffer could
  743. not be allocated.
  744. PDH_INVALID_HANDLE is returned if the query handle is not valid.
  745. PDH_CSTATUS_NO_COUNTER is returned if the specified counter was
  746. not found
  747. PDH_CSTATUS_NO_OBJECT is returned if the specified object could
  748. not be found
  749. PDH_CSTATUS_NO_MACHINE is returned if a machine entry could not
  750. be created.
  751. PDH_CSTATUS_BAD_COUNTERNAME is returned if the counter name path
  752. string could not be parsed or interpreted
  753. PDH_CSTATUS_NO_COUNTERNAME is returned if an empty counter name
  754. path string is passed in
  755. PDH_FUNCTION_NOT_FOUND is returned if the calculation function
  756. for this counter could not be determined.
  757. --*/
  758. {
  759. LPWSTR szFullName = NULL;
  760. PDH_STATUS ReturnStatus = ERROR_SUCCESS;
  761. PDH_HCOUNTER hLocalCounter = NULL;
  762. PDH_HQUERY hLocalQuery;
  763. DWORD_PTR dwLocalData;
  764. PPDHI_COUNTER pNewCounter = NULL;
  765. if (phCounter == NULL || szFullCounterPath == NULL) {
  766. return PDH_INVALID_ARGUMENT;
  767. }
  768. __try {
  769. DWORD dwLength = lstrlenA(szFullCounterPath);
  770. // try writing to return pointer
  771. hLocalQuery = hQuery;
  772. dwLocalData = dwUserData;
  773. * phCounter = NULL;
  774. if (dwLength == 0 || dwLength > PDH_MAX_COUNTER_PATH) {
  775. ReturnStatus = PDH_INVALID_ARGUMENT;
  776. }
  777. else {
  778. szFullName = PdhiMultiByteToWideChar(_getmbcp(), (LPSTR) szFullCounterPath);
  779. if (szFullName == NULL) {
  780. ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  781. }
  782. }
  783. }
  784. __except (EXCEPTION_EXECUTE_HANDLER) {
  785. ReturnStatus = PDH_INVALID_ARGUMENT;
  786. }
  787. if (ReturnStatus == ERROR_SUCCESS) {
  788. pNewCounter = G_ALLOC(sizeof (PDHI_COUNTER));
  789. if (pNewCounter == NULL) {
  790. ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  791. }
  792. }
  793. // query handle is tested by PdhiAddCounter
  794. if (ReturnStatus == ERROR_SUCCESS) {
  795. ReturnStatus = PdhiAddCounter( hLocalQuery, szFullName, dwLocalData, & hLocalCounter, pNewCounter);
  796. if (ReturnStatus == ERROR_SUCCESS && hLocalCounter != NULL) {
  797. __try {
  798. * phCounter = hLocalCounter;
  799. }
  800. __except (EXCEPTION_EXECUTE_HANDLER) {
  801. ReturnStatus = PDH_INVALID_ARGUMENT;
  802. }
  803. }
  804. }
  805. if (ReturnStatus != ERROR_SUCCESS) {
  806. if (pNewCounter != NULL) {
  807. if (pNewCounter->szFullName == NULL) {
  808. G_FREE(szFullName);
  809. }
  810. if (! FreeCounter(pNewCounter)) {
  811. if (pNewCounter->szFullName != NULL) {
  812. G_FREE(pNewCounter->szFullName);
  813. }
  814. G_FREE(pNewCounter);
  815. }
  816. }
  817. else if (szFullName != NULL) { // allocated this, but not pNewCounter
  818. G_FREE(szFullName);
  819. }
  820. }
  821. return ReturnStatus;
  822. }
  823. PDH_FUNCTION
  824. PdhRemoveCounter(
  825. IN PDH_HCOUNTER hCounter
  826. )
  827. /*++
  828. Routine Description:
  829. Removes the specified counter from the query it is attached to and
  830. closes any handles and frees any memory associated with this
  831. counter
  832. Arguments:
  833. IN HCOUNTER hCounter
  834. handle of the counter to remove from the query.
  835. Return Value:
  836. Returns ERROR_SUCCESS if a new query was created and initialized,
  837. and a PDH_ error value if not.
  838. PDH_INVALID_HANDLE is returned if the counter handle is not valid.
  839. --*/
  840. {
  841. PPDHI_COUNTER pThisCounter;
  842. PPDHI_QUERY pThisQuery;
  843. PPDHI_COUNTER pNextCounter;
  844. PPDHI_QUERY_MACHINE pQMachine;
  845. PPDHI_QUERY_MACHINE pNextQMachine;
  846. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  847. // we're changing the contents PDH data so lock it
  848. if (WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex) != ERROR_SUCCESS) return WAIT_TIMEOUT;
  849. if (IsValidCounter(hCounter)) {
  850. // it's ok to cast it to a pointer now.
  851. pThisCounter = (PPDHI_COUNTER) hCounter;
  852. pThisQuery = pThisCounter->pOwner;
  853. if (! IsValidQuery(pThisQuery)) {
  854. pdhStatus = PDH_INVALID_HANDLE;
  855. goto Cleanup;
  856. }
  857. if (WAIT_FOR_AND_LOCK_MUTEX(pThisQuery->hMutex) != ERROR_SUCCESS) {
  858. pdhStatus = WAIT_TIMEOUT;
  859. goto Cleanup;
  860. }
  861. if (pThisCounter == pThisQuery->pCounterListHead) {
  862. if (pThisCounter->next.flink == pThisCounter){
  863. // then this is the only counter in the query
  864. FreeCounter(pThisCounter);
  865. pThisQuery->pCounterListHead = NULL;
  866. if (!(pThisQuery->dwFlags & PDHIQ_WBEM_QUERY)) {
  867. // remove the QMachine list since there are now no more
  868. // counters to query
  869. if ((pQMachine = pThisQuery->pFirstQMachine) != NULL) {
  870. // Free list of machine pointers
  871. do {
  872. pNextQMachine = pQMachine->pNext;
  873. if (pQMachine->pPerfData != NULL) {
  874. G_FREE(pQMachine->pPerfData);
  875. }
  876. G_FREE(pQMachine);
  877. pQMachine = pNextQMachine;
  878. }
  879. while (pQMachine != NULL);
  880. pThisQuery->pFirstQMachine = NULL;
  881. }
  882. }
  883. }
  884. else {
  885. // they are deleting the first counter from the list
  886. // so update the list pointer
  887. // Free Counter takes care of the list links, we just
  888. // need to manage the list head pointer
  889. pNextCounter = pThisCounter->next.flink;
  890. FreeCounter(pThisCounter);
  891. pThisQuery->pCounterListHead = pNextCounter;
  892. }
  893. }
  894. else {
  895. // remove this from the list
  896. FreeCounter(pThisCounter);
  897. }
  898. RELEASE_MUTEX(pThisQuery->hMutex);
  899. }
  900. else {
  901. pdhStatus = PDH_INVALID_HANDLE;
  902. }
  903. Cleanup:
  904. RELEASE_MUTEX(hPdhDataMutex);
  905. return pdhStatus;
  906. }
  907. PDH_FUNCTION
  908. PdhSetQueryTimeRange(
  909. IN PDH_HQUERY hQuery,
  910. IN PPDH_TIME_INFO pInfo
  911. )
  912. {
  913. PPDHI_QUERY pQuery;
  914. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  915. if (pInfo == NULL) {
  916. pdhStatus = PDH_INVALID_ARGUMENT;
  917. }
  918. else {
  919. if (IsValidQuery(hQuery)) {
  920. pQuery = (PPDHI_QUERY) hQuery;
  921. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX(pQuery->hMutex);
  922. if (pdhStatus == ERROR_SUCCESS) {
  923. if (IsValidQuery(hQuery)) {
  924. if (pQuery->hLog == NULL) {
  925. pdhStatus = ERROR_SUCCESS;
  926. }
  927. else {
  928. __try {
  929. if (* (LONGLONG *) (& pInfo->EndTime) > * (LONGLONG *) (& pInfo->StartTime)) {
  930. // reset log file pointers to beginning so next query
  931. // will read from the start of the time range
  932. pdhStatus = PdhiResetLogBuffers(pQuery->hLog);
  933. // ok so now load new time range
  934. if (pdhStatus == ERROR_SUCCESS) {
  935. pQuery->TimeRange = * pInfo;
  936. pQuery->dwLastLogIndex = 0;
  937. }
  938. }
  939. else {
  940. // end time is smaller (earlier) than start time
  941. pdhStatus = PDH_INVALID_ARGUMENT;
  942. }
  943. }
  944. __except (EXCEPTION_EXECUTE_HANDLER) {
  945. pdhStatus = PDH_INVALID_ARGUMENT;
  946. }
  947. }
  948. }
  949. else {
  950. // the query disappeared while we were waiting for it
  951. pdhStatus = PDH_INVALID_HANDLE;
  952. }
  953. RELEASE_MUTEX(pQuery->hMutex);
  954. } // else couldn't lock query
  955. }
  956. else {
  957. pdhStatus = PDH_INVALID_HANDLE;
  958. }
  959. }
  960. return pdhStatus;
  961. }
  962. PDH_FUNCTION
  963. PdhiCollectQueryData(
  964. PPDHI_QUERY pQuery,
  965. LONGLONG * pllTimeStamp
  966. )
  967. {
  968. PDH_STATUS Status;
  969. if (WAIT_FOR_AND_LOCK_MUTEX(pQuery->hMutex) != ERROR_SUCCESS) return WAIT_TIMEOUT;
  970. if (pQuery->dwFlags & PDHIQ_WBEM_QUERY) {
  971. Status = GetQueryWbemData(pQuery, pllTimeStamp);
  972. }
  973. else {
  974. Status = GetQueryPerfData(pQuery, pllTimeStamp);
  975. }
  976. RELEASE_MUTEX(pQuery->hMutex);
  977. return Status;
  978. }
  979. PDH_FUNCTION
  980. PdhCollectQueryData(
  981. IN PDH_HQUERY hQuery
  982. )
  983. /*++
  984. Routine Description:
  985. Retrieves the current value of each counter attached to the specified
  986. query.
  987. For this version, each machine associated with this query is polled
  988. sequentially. This is simple and safe, but potentially slow so a
  989. multi-threaded approach will be reviewed for the next version.
  990. Note that while the call may succeed, no data may be available. The
  991. status of each counter MUST be checked before its data is used.
  992. Arguments:
  993. IN HQUERY hQuery
  994. handle of the query to update.
  995. Return Value:
  996. Returns ERROR_SUCCESS if a new query was created and initialized,
  997. and a PDH_ error value if not.
  998. PDH_INVALID_HANDLE is returned if the query handle is not valid.
  999. PDH_NO_DATA is returned if the query does not have any counters defined
  1000. yet.
  1001. --*/
  1002. {
  1003. PDH_STATUS Status;
  1004. PPDHI_QUERY pQuery;
  1005. LONGLONG llTimeStamp;
  1006. if (WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex) != ERROR_SUCCESS) return WAIT_TIMEOUT;
  1007. if (IsValidQuery(hQuery)) {
  1008. pQuery = (PPDHI_QUERY) hQuery;
  1009. Status = PdhiCollectQueryData(pQuery, & llTimeStamp);
  1010. }
  1011. else {
  1012. Status = PDH_INVALID_HANDLE;
  1013. }
  1014. RELEASE_MUTEX(hPdhDataMutex);
  1015. return Status;
  1016. }
  1017. PDH_FUNCTION
  1018. PdhCollectQueryDataEx(
  1019. IN HQUERY hQuery,
  1020. IN DWORD dwIntervalTime,
  1021. IN HANDLE hNewDataEvent
  1022. )
  1023. /*++
  1024. Routine Description:
  1025. Retrieves the current value of each counter attached to the specified
  1026. query periodically based on the interval time specified.
  1027. For this version, each machine associated with this query is polled
  1028. sequentially.
  1029. Note that while the call may succeed, no data may be available. The
  1030. status of each counter MUST be checked before its data is used.
  1031. Arguments:
  1032. IN HQUERY hQuery
  1033. handle of the query to update.
  1034. IN DWORD dwIntervalTime
  1035. Interval to poll for new data in seconds
  1036. this value must be > 0. A value of 0 will terminate any current
  1037. data collection threads.
  1038. IN HANDLE hNewDataEvent
  1039. Handle to an Event that should be signaled when new data is
  1040. available. This can be NULL if no notification is desired.
  1041. Return Value:
  1042. Returns ERROR_SUCCESS if a new query was created and initialized,
  1043. and a PDH_ error value if not.
  1044. PDH_INVALID_HANDLE is returned if the query handle is not valid.
  1045. --*/
  1046. {
  1047. PDH_STATUS lStatus = ERROR_SUCCESS;
  1048. PPDHI_QUERY pQuery;
  1049. DWORD dwThreadId;
  1050. BOOL bStatus;
  1051. if (WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex) != ERROR_SUCCESS) return WAIT_TIMEOUT;
  1052. if (IsValidQuery(hQuery)) {
  1053. // set the query structure's interval to the caller specified
  1054. // value then start the timing thread.
  1055. pQuery = (PPDHI_QUERY) hQuery;
  1056. if (WAIT_FOR_AND_LOCK_MUTEX(pQuery->hMutex) != ERROR_SUCCESS) {
  1057. lStatus = WAIT_TIMEOUT;
  1058. goto Cleanup;
  1059. }
  1060. if (pQuery->hExitEvent != NULL) {
  1061. RELEASE_MUTEX(pQuery->hMutex);
  1062. // stop current thread first
  1063. SetEvent(pQuery->hExitEvent);
  1064. // wait 1 second for the thread to stop
  1065. lStatus = WaitForSingleObject(pQuery->hAsyncThread, 10000L);
  1066. if (lStatus == WAIT_TIMEOUT) {
  1067. TRACE((PDH_DBG_TRACE_ERROR), (__LINE__, PDH_QUERY, 0, lStatus, NULL));
  1068. }
  1069. lStatus = WAIT_FOR_AND_LOCK_MUTEX(pQuery->hMutex);
  1070. if (lStatus == ERROR_SUCCESS) {
  1071. bStatus = CloseHandle(pQuery->hExitEvent);
  1072. pQuery->hExitEvent = NULL;
  1073. bStatus = CloseHandle(pQuery->hAsyncThread);
  1074. pQuery->hAsyncThread = NULL;
  1075. }
  1076. }
  1077. if (lStatus == ERROR_SUCCESS) {
  1078. // query mutex is still locked at this point
  1079. if (dwIntervalTime > 0) {
  1080. // start a new interval
  1081. // initialize new values
  1082. __try {
  1083. pQuery->dwInterval = dwIntervalTime;
  1084. pQuery->hNewDataEvent = hNewDataEvent;
  1085. }
  1086. __except(EXCEPTION_EXECUTE_HANDLER) {
  1087. lStatus = PDH_INVALID_ARGUMENT;
  1088. }
  1089. if (lStatus == ERROR_SUCCESS) {
  1090. pQuery->hExitEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
  1091. pQuery->hAsyncThread = CreateThread(NULL,
  1092. 0,
  1093. PdhiAsyncTimerThreadProc,
  1094. (LPVOID) pQuery,
  1095. 0,
  1096. & dwThreadId);
  1097. }
  1098. RELEASE_MUTEX(pQuery->hMutex);
  1099. if (pQuery->hAsyncThread == NULL) {
  1100. lStatus = WAIT_FOR_AND_LOCK_MUTEX(pQuery->hMutex);
  1101. if (lStatus == ERROR_SUCCESS) {
  1102. pQuery->dwInterval = 0;
  1103. pQuery->hNewDataEvent = NULL;
  1104. bStatus = CloseHandle(pQuery->hExitEvent);
  1105. pQuery->hExitEvent = NULL;
  1106. RELEASE_MUTEX(pQuery->hMutex);
  1107. lStatus = GetLastError();
  1108. }
  1109. }
  1110. }
  1111. else {
  1112. // they just wanted to stop so clean up Query struct
  1113. pQuery->dwInterval = 0;
  1114. pQuery->hNewDataEvent = NULL;
  1115. RELEASE_MUTEX(pQuery->hMutex);
  1116. // lstatus = ERROR_SUCCESS from above
  1117. }
  1118. }
  1119. }
  1120. else {
  1121. lStatus = PDH_INVALID_HANDLE;
  1122. }
  1123. Cleanup:
  1124. RELEASE_MUTEX (hPdhDataMutex);
  1125. return lStatus;
  1126. }
  1127. PDH_FUNCTION
  1128. PdhCloseQuery(
  1129. IN PDH_HQUERY hQuery
  1130. )
  1131. /*++
  1132. Routine Description:
  1133. closes the query, all counters, connections and other resources
  1134. related to this query are freed as well.
  1135. Arguments:
  1136. IN HQUERY hQuery
  1137. the handle of the query to free.
  1138. Return Value:
  1139. Returns ERROR_SUCCESS if a new query was created and initialized,
  1140. and a PDH_ error value if not.
  1141. PDH_INVALID_HANDLE is returned if the query handle is not valid.
  1142. --*/
  1143. {
  1144. PDH_STATUS dwReturn;
  1145. // lock system data
  1146. if (WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex) != ERROR_SUCCESS) return WAIT_TIMEOUT;
  1147. if (IsValidQuery(hQuery)) {
  1148. // dispose of query
  1149. PPDHI_QUERY pQuery = (PPDHI_QUERY) hQuery;
  1150. if (pQuery->hLog == H_REALTIME_DATASOURCE || pQuery->hLog == H_WBEM_DATASOURCE) {
  1151. dwCurrentRealTimeDataSource --;
  1152. if (dwCurrentRealTimeDataSource < 0) {
  1153. dwCurrentRealTimeDataSource = 0;
  1154. }
  1155. }
  1156. PdhiFreeQuery(pQuery);
  1157. // release data lock
  1158. dwReturn = ERROR_SUCCESS;
  1159. }
  1160. else {
  1161. dwReturn = PDH_INVALID_HANDLE;
  1162. }
  1163. RELEASE_MUTEX(hPdhDataMutex);
  1164. return dwReturn;
  1165. }
  1166. BOOL
  1167. PdhiQueryCleanup(
  1168. )
  1169. {
  1170. PPDHI_QUERY pThisQuery;
  1171. BOOL bReturn = FALSE;
  1172. if (WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex) == ERROR_SUCCESS) {
  1173. // free any queries in the query list
  1174. pThisQuery = PdhiDllHeadQueryPtr;
  1175. if (pThisQuery != NULL) {
  1176. while (pThisQuery->next.blink != pThisQuery->next.flink) {
  1177. // delete from list
  1178. // the deletion routine updates the blink pointer as it
  1179. // removes the specified entry.
  1180. PdhiFreeQuery(pThisQuery->next.blink);
  1181. }
  1182. // remove last query
  1183. PdhiFreeQuery(pThisQuery);
  1184. PdhiDllHeadQueryPtr = NULL;
  1185. dwCurrentRealTimeDataSource = 0;
  1186. }
  1187. RELEASE_MUTEX(hPdhDataMutex);
  1188. bReturn = TRUE;
  1189. }
  1190. return bReturn;
  1191. }
  1192. PDH_FUNCTION
  1193. PdhGetDllVersion(
  1194. IN LPDWORD lpdwVersion
  1195. )
  1196. {
  1197. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1198. __try {
  1199. * lpdwVersion = PDH_VERSION;
  1200. }
  1201. __except (EXCEPTION_EXECUTE_HANDLER) {
  1202. pdhStatus = PDH_INVALID_ARGUMENT;
  1203. }
  1204. return pdhStatus;
  1205. }
  1206. BOOL
  1207. PdhIsRealTimeQuery(
  1208. IN PDH_HQUERY hQuery
  1209. )
  1210. {
  1211. PPDHI_QUERY pQuery;
  1212. BOOL bReturn = FALSE;
  1213. SetLastError (ERROR_SUCCESS);
  1214. if (IsValidQuery(hQuery)) {
  1215. __try {
  1216. pQuery = (PPDHI_QUERY) hQuery;
  1217. if (pQuery->hLog == NULL) {
  1218. bReturn = TRUE;
  1219. }
  1220. else {
  1221. bReturn = FALSE;
  1222. }
  1223. }
  1224. __except (EXCEPTION_EXECUTE_HANDLER) {
  1225. SetLastError(GetExceptionCode());
  1226. }
  1227. }
  1228. else {
  1229. bReturn = FALSE;
  1230. }
  1231. return bReturn;
  1232. }
  1233. PDH_FUNCTION
  1234. PdhFormatFromRawValue(
  1235. IN DWORD dwCounterType,
  1236. IN DWORD dwFormat,
  1237. IN LONGLONG * pTimeBase,
  1238. IN PPDH_RAW_COUNTER pRawValue1,
  1239. IN PPDH_RAW_COUNTER pRawValue2,
  1240. IN PPDH_FMT_COUNTERVALUE pFmtValue
  1241. )
  1242. /*++
  1243. Routine Description:
  1244. Calculates the formatted counter value using the data in the RawValue
  1245. buffer in the format requested by the format field using the
  1246. calculation functions of the counter type specified by the
  1247. dwCounterType field.
  1248. Arguments:
  1249. IN DWORD dwCounterType
  1250. The type of the counter to use in order to determine the
  1251. calculation functions for interpretation of the raw value buffers
  1252. IN DWORD dwFormat
  1253. Format in which the requested data should be returned. The
  1254. values for this field are described in the PDH.H header
  1255. file.
  1256. IN LONGLONG *pTimeBase
  1257. pointer to the _int64 value containing the timebase (i.e. counter
  1258. unit frequency) used by this counter. This can be NULL if it's not
  1259. required by the counter type
  1260. IN PPDH_RAW_COUNTER rawValue1
  1261. pointer to the buffer that contains the first raw value structure
  1262. IN PPDH_RAW_COUNTER rawValue2
  1263. pointer to the buffer that contains the second raw value structure.
  1264. This argument may be null if only one value is required for the
  1265. computation.
  1266. IN PPDH_FMT_COUNTERVALUE fmtValue
  1267. the pointer to the data buffer passed by the caller to receive
  1268. the data requested. If the counter requires 2 values, (as in the
  1269. case of a rate counter), rawValue1 is assumed to be the most
  1270. recent value and rawValue2, the older value.
  1271. Return Value:
  1272. The WIN32 Error status of the function's operation. Common values
  1273. returned are:
  1274. ERROR_SUCCESS when all requested data is returned
  1275. PDH_INVALID_HANDLE if the counter handle is incorrect
  1276. PDH_INVALID_ARGUMENT if an argument is incorrect
  1277. --*/
  1278. {
  1279. PDH_STATUS lStatus = ERROR_SUCCESS;
  1280. LPCOUNTERCALC pCalcFunc;
  1281. LPCOUNTERSTAT pStatFunc;
  1282. LONGLONG llTimeBase;
  1283. BOOL bReturn;
  1284. // TODO: Need to check for pRawValue1
  1285. // bad arguments are caught in the PdhiComputeFormattedValue function
  1286. // NOTE: postW2k pTimeBase really do not need to be a pointer, since it is
  1287. // not returned
  1288. if (pTimeBase != NULL) {
  1289. __try {
  1290. DWORD dwTempStatus;
  1291. DWORD dwTypeMask;
  1292. // read access to the timebase
  1293. llTimeBase = * pTimeBase;
  1294. // we should have read access to the rawValues
  1295. dwTempStatus = * ((DWORD volatile *) & pRawValue1->CStatus);
  1296. // this one could be NULL
  1297. if (pRawValue2 != NULL) {
  1298. dwTempStatus = * ((DWORD volatile *) & pRawValue2->CStatus);
  1299. }
  1300. // and write access to the fmtValue
  1301. pFmtValue->CStatus = 0;
  1302. // validate format flags:
  1303. // only one of the following can be set at a time
  1304. dwTypeMask = dwFormat & (PDH_FMT_LONG | PDH_FMT_DOUBLE | PDH_FMT_LARGE);
  1305. if (! ((dwTypeMask == PDH_FMT_LONG) || (dwTypeMask == PDH_FMT_DOUBLE) ||
  1306. (dwTypeMask == PDH_FMT_LARGE))) {
  1307. lStatus = PDH_INVALID_ARGUMENT;
  1308. }
  1309. }
  1310. __except (EXCEPTION_EXECUTE_HANDLER) {
  1311. lStatus = PDH_INVALID_ARGUMENT;
  1312. }
  1313. }
  1314. else {
  1315. llTimeBase = 0;
  1316. }
  1317. if (lStatus == ERROR_SUCCESS) {
  1318. // get calc func for counter type this will also test the
  1319. // validity of the counter type argument
  1320. bReturn = AssignCalcFunction(dwCounterType, & pCalcFunc, & pStatFunc);
  1321. if (!bReturn) {
  1322. lStatus = GetLastError();
  1323. }
  1324. else {
  1325. lStatus = PdhiComputeFormattedValue(pCalcFunc,
  1326. dwCounterType,
  1327. 0L,
  1328. dwFormat,
  1329. pRawValue1,
  1330. pRawValue2,
  1331. & llTimeBase,
  1332. 0L,
  1333. pFmtValue);
  1334. }
  1335. }
  1336. return lStatus;
  1337. }
  1338. LPWSTR
  1339. PdhiMatchObjectNameInList(
  1340. LPWSTR szObjectName,
  1341. LPWSTR * szSrcPerfStrings,
  1342. LPWSTR * szDestPerfStrings,
  1343. DWORD dwLastString
  1344. )
  1345. {
  1346. LPWSTR szRtnName = NULL;
  1347. DWORD i;
  1348. for (i = 0; i <= dwLastString; i ++) {
  1349. if (szSrcPerfStrings[i] && szSrcPerfStrings[i] != L'\0'
  1350. && lstrcmpiW(szObjectName, szSrcPerfStrings[i]) == 0) {
  1351. szRtnName = szDestPerfStrings[i];
  1352. break;
  1353. }
  1354. }
  1355. return szRtnName;
  1356. }
  1357. PDH_FUNCTION
  1358. PdhiBuildFullCounterPath(
  1359. BOOL bMachine,
  1360. PPDHI_COUNTER_PATH pCounterPath,
  1361. LPWSTR szObjectName,
  1362. LPWSTR szCounterName,
  1363. LPWSTR szFullPath,
  1364. DWORD dwFullPath
  1365. )
  1366. {
  1367. PDH_STATUS Status = ERROR_SUCCESS;
  1368. // Internal routine,
  1369. // Build full counter path name from counter path structure, assume
  1370. // passed-in string buffer is large enough to hold.
  1371. if (bMachine) {
  1372. StringCchCopyW(szFullPath, dwFullPath, pCounterPath->szMachineName);
  1373. StringCchCatW(szFullPath, dwFullPath, cszBackSlash);
  1374. }
  1375. else {
  1376. StringCchCopyW(szFullPath, dwFullPath, cszBackSlash);
  1377. }
  1378. StringCchCatW(szFullPath, dwFullPath, szObjectName);
  1379. if (pCounterPath->szInstanceName != NULL && pCounterPath->szInstanceName[0] != L'\0') {
  1380. StringCchCatW(szFullPath, dwFullPath, cszLeftParen);
  1381. if (pCounterPath->szParentName != NULL && pCounterPath->szParentName[0] != L'\0') {
  1382. StringCchCatW(szFullPath, dwFullPath, pCounterPath->szParentName);
  1383. StringCchCatW(szFullPath, dwFullPath, cszSlash);
  1384. TRACE((PDH_DBG_TRACE_INFO),
  1385. (__LINE__,
  1386. PDH_QUERY,
  1387. ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2)
  1388. | ARG_DEF(ARG_TYPE_WSTR, 3)
  1389. | ARG_DEF(ARG_TYPE_WSTR, 4)
  1390. | ARG_DEF(ARG_TYPE_WSTR, 5),
  1391. ERROR_SUCCESS,
  1392. TRACE_WSTR(pCounterPath->szMachineName),
  1393. TRACE_WSTR(szObjectName),
  1394. TRACE_WSTR(szCounterName),
  1395. TRACE_WSTR(pCounterPath->szParentName),
  1396. TRACE_WSTR(pCounterPath->szInstanceName),
  1397. TRACE_DWORD(pCounterPath->dwIndex),
  1398. NULL));
  1399. }
  1400. else {
  1401. TRACE((PDH_DBG_TRACE_INFO),
  1402. (__LINE__,
  1403. PDH_QUERY,
  1404. ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2)
  1405. | ARG_DEF(ARG_TYPE_WSTR, 3)
  1406. | ARG_DEF(ARG_TYPE_WSTR, 4),
  1407. ERROR_SUCCESS,
  1408. TRACE_WSTR(pCounterPath->szMachineName),
  1409. TRACE_WSTR(szObjectName),
  1410. TRACE_WSTR(szCounterName),
  1411. TRACE_WSTR(pCounterPath->szInstanceName),
  1412. TRACE_DWORD(pCounterPath->dwIndex),
  1413. NULL));
  1414. }
  1415. StringCchCatW(szFullPath, dwFullPath, pCounterPath->szInstanceName);
  1416. if (pCounterPath->dwIndex != ((DWORD) -1) && pCounterPath->dwIndex != 0) {
  1417. WCHAR szDigits[16];
  1418. ZeroMemory(szDigits, 16 * sizeof(WCHAR));
  1419. StringCchCatW(szFullPath, dwFullPath, cszPoundSign);
  1420. _ltow((long) pCounterPath->dwIndex, szDigits, 10);
  1421. StringCchCatW(szFullPath, dwFullPath, szDigits);
  1422. }
  1423. StringCchCatW(szFullPath, dwFullPath, cszRightParen);
  1424. }
  1425. else {
  1426. TRACE((PDH_DBG_TRACE_INFO),
  1427. (__LINE__,
  1428. PDH_QUERY,
  1429. ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2)
  1430. | ARG_DEF(ARG_TYPE_WSTR, 3),
  1431. ERROR_SUCCESS,
  1432. TRACE_WSTR(pCounterPath->szMachineName),
  1433. TRACE_WSTR(szObjectName),
  1434. TRACE_WSTR(szCounterName),
  1435. TRACE_DWORD(pCounterPath->dwIndex),
  1436. NULL));
  1437. }
  1438. StringCchCatW(szFullPath, dwFullPath, cszBackSlash);
  1439. StringCchCatW(szFullPath, dwFullPath, szCounterName);
  1440. return Status;
  1441. }
  1442. PDH_FUNCTION
  1443. PdhiTranslateCounter(
  1444. LPWSTR szSourcePath,
  1445. LPVOID pFullPathName,
  1446. LPDWORD pcchPathLength,
  1447. BOOL bLocaleTo009,
  1448. BOOL bUnicode
  1449. )
  1450. {
  1451. PDH_STATUS Status = ERROR_SUCCESS;
  1452. PPERF_MACHINE pMachine = NULL;
  1453. PPDHI_COUNTER_PATH pCounterPath = NULL;
  1454. LPWSTR szRtnPath = NULL;
  1455. DWORD dwPathSize;
  1456. DWORD dwRtnPathSize;
  1457. DWORD dwSize;
  1458. BOOL bMachineThere = FALSE;
  1459. bMachineThere = (lstrlenW(szSourcePath) >= 2) && (szSourcePath[0] == BACKSLASH_L)
  1460. && (szSourcePath[1] == BACKSLASH_L);
  1461. dwPathSize = sizeof(WCHAR) * (lstrlenW(szStaticLocalMachineName) + lstrlenW(szSourcePath) + 2);
  1462. dwSize = sizeof(PDHI_COUNTER_PATH) + 2 * dwPathSize;
  1463. pCounterPath = G_ALLOC(dwSize);
  1464. if (pCounterPath == NULL) {
  1465. Status = PDH_MEMORY_ALLOCATION_FAILURE;
  1466. goto Cleanup;
  1467. }
  1468. if (ParseFullPathNameW(szSourcePath, & dwSize, pCounterPath, FALSE)) {
  1469. pMachine = GetMachine(pCounterPath->szMachineName, 0, PDH_GM_UPDATE_PERFNAME_ONLY);
  1470. if (pMachine == NULL) {
  1471. Status = PDH_CSTATUS_NO_MACHINE;
  1472. }
  1473. else if (pMachine->dwStatus != ERROR_SUCCESS) {
  1474. pMachine->dwRefCount --;
  1475. RELEASE_MUTEX(pMachine->hMutex);
  1476. Status = PDH_CSTATUS_NO_MACHINE;
  1477. }
  1478. else {
  1479. LPWSTR szObjectName = NULL;
  1480. LPWSTR szCounterName = NULL;
  1481. BOOLEAN bInstance = TRUE;
  1482. if (bLocaleTo009) {
  1483. szObjectName = PdhiMatchObjectNameInList(pCounterPath->szObjectName,
  1484. pMachine->szPerfStrings,
  1485. pMachine->sz009PerfStrings,
  1486. pMachine->dwLastPerfString);
  1487. szCounterName = PdhiMatchObjectNameInList(pCounterPath->szCounterName,
  1488. pMachine->szPerfStrings,
  1489. pMachine->sz009PerfStrings,
  1490. pMachine->dwLastPerfString);
  1491. }
  1492. else {
  1493. szObjectName = PdhiMatchObjectNameInList(pCounterPath->szObjectName,
  1494. pMachine->sz009PerfStrings,
  1495. pMachine->szPerfStrings,
  1496. pMachine->dwLastPerfString);
  1497. szCounterName = PdhiMatchObjectNameInList(pCounterPath->szCounterName,
  1498. pMachine->sz009PerfStrings,
  1499. pMachine->szPerfStrings,
  1500. pMachine->dwLastPerfString);
  1501. }
  1502. if (szObjectName == NULL) {
  1503. DWORD dwObjectTitle = wcstoul(pCounterPath->szObjectName, NULL, 10);
  1504. if (dwObjectTitle != 0) {
  1505. szObjectName = pCounterPath->szObjectName;
  1506. }
  1507. }
  1508. if (szCounterName == NULL) {
  1509. DWORD dwCounterTitle = wcstoul(pCounterPath->szCounterName, NULL, 10);
  1510. if (dwCounterTitle != 0) {
  1511. szCounterName = pCounterPath->szCounterName;
  1512. }
  1513. }
  1514. if ((szObjectName == NULL) && (* pCounterPath->szObjectName == SPLAT_L)) {
  1515. szObjectName = pCounterPath->szObjectName;
  1516. }
  1517. if ((szCounterName == NULL) && (* pCounterPath->szCounterName == SPLAT_L)) {
  1518. szCounterName = pCounterPath->szCounterName;
  1519. }
  1520. if (szObjectName == NULL || szCounterName == NULL) {
  1521. Status = PDH_INVALID_ARGUMENT;
  1522. }
  1523. else {
  1524. if (pCounterPath->szInstanceName != NULL
  1525. && pCounterPath->szInstanceName[0] != L'\0') {
  1526. dwRtnPathSize = sizeof(WCHAR) * ( lstrlenW(pCounterPath->szMachineName)
  1527. + lstrlenW(szObjectName)
  1528. + lstrlenW(pCounterPath->szInstanceName)
  1529. + lstrlenW(szCounterName) + 5);
  1530. if (pCounterPath->szParentName != NULL && pCounterPath->szParentName[0] != L'\0') {
  1531. dwRtnPathSize += (sizeof(WCHAR) * (lstrlenW(pCounterPath->szParentName) + 1));
  1532. }
  1533. if (pCounterPath->dwIndex != ((DWORD) -1) && pCounterPath->dwIndex != 0) {
  1534. dwRtnPathSize += (sizeof(WCHAR) * 16);
  1535. }
  1536. }
  1537. else {
  1538. dwRtnPathSize = sizeof(WCHAR) * (lstrlenW(pCounterPath->szMachineName)
  1539. + lstrlenW(szObjectName) + lstrlenW(szCounterName) + 3);
  1540. bInstance = FALSE;
  1541. }
  1542. szRtnPath = G_ALLOC(dwRtnPathSize);
  1543. if (szRtnPath == NULL) {
  1544. Status = PDH_MEMORY_ALLOCATION_FAILURE;
  1545. }
  1546. else {
  1547. PdhiBuildFullCounterPath(
  1548. bMachineThere, pCounterPath, szObjectName, szCounterName, szRtnPath, dwRtnPathSize);
  1549. __try {
  1550. if (bUnicode) {
  1551. if ((pFullPathName != NULL) && ((* pcchPathLength) >= (DWORD) (lstrlenW(szRtnPath) + 1))) {
  1552. StringCchCopyW(pFullPathName, * pcchPathLength, szRtnPath);
  1553. }
  1554. else {
  1555. Status = PDH_MORE_DATA;
  1556. }
  1557. * pcchPathLength = lstrlenW(szRtnPath) + 1;
  1558. }
  1559. else {
  1560. dwRtnPathSize = * pcchPathLength;
  1561. if (bLocaleTo009) {
  1562. Status = PdhiConvertUnicodeToAnsi(
  1563. CP_ACP, szRtnPath, pFullPathName, & dwRtnPathSize);
  1564. }
  1565. else {
  1566. Status = PdhiConvertUnicodeToAnsi(
  1567. _getmbcp(), szRtnPath, pFullPathName, & dwRtnPathSize);
  1568. }
  1569. * pcchPathLength = dwRtnPathSize;
  1570. }
  1571. }
  1572. __except(EXCEPTION_EXECUTE_HANDLER) {
  1573. Status = PDH_INVALID_ARGUMENT;
  1574. }
  1575. }
  1576. }
  1577. pMachine->dwRefCount --;
  1578. RELEASE_MUTEX(pMachine->hMutex);
  1579. }
  1580. }
  1581. else {
  1582. Status = PDH_CSTATUS_BAD_COUNTERNAME;
  1583. }
  1584. Cleanup:
  1585. G_FREE(szRtnPath);
  1586. G_FREE(pCounterPath);
  1587. return Status;
  1588. }
  1589. PDH_FUNCTION
  1590. PdhTranslate009CounterW(
  1591. IN LPWSTR szLocalePath,
  1592. IN LPWSTR pszFullPathName,
  1593. IN LPDWORD pcchPathLength
  1594. )
  1595. {
  1596. PDH_STATUS Status = ERROR_SUCCESS;
  1597. if (szLocalePath == NULL || pcchPathLength == NULL) {
  1598. Status = PDH_INVALID_ARGUMENT;
  1599. }
  1600. else {
  1601. __try {
  1602. DWORD dwPathLength = * pcchPathLength;
  1603. if (* szLocalePath == L'\0' || lstrlenW(szLocalePath) > PDH_MAX_COUNTER_PATH) {
  1604. Status = PDH_INVALID_ARGUMENT;
  1605. }
  1606. else if (dwPathLength > 0) {
  1607. if (pszFullPathName == NULL) {
  1608. Status = PDH_INVALID_ARGUMENT;
  1609. }
  1610. else {
  1611. * pszFullPathName = L'\0';
  1612. * (LPWSTR) (pszFullPathName + (dwPathLength - 1)) = L'\0';
  1613. }
  1614. }
  1615. }
  1616. __except (EXCEPTION_EXECUTE_HANDLER) {
  1617. Status = PDH_INVALID_ARGUMENT;
  1618. }
  1619. }
  1620. if (Status == ERROR_SUCCESS) {
  1621. Status = PdhiTranslateCounter(szLocalePath, pszFullPathName, pcchPathLength, TRUE, TRUE);
  1622. }
  1623. return Status;
  1624. }
  1625. PDH_FUNCTION
  1626. PdhTranslate009CounterA(
  1627. IN LPSTR szLocalePath,
  1628. IN LPSTR pszFullPathName,
  1629. IN LPDWORD pcchPathLength
  1630. )
  1631. {
  1632. PDH_STATUS Status = ERROR_SUCCESS;
  1633. LPWSTR szTmpPath = NULL;
  1634. if (szLocalePath == NULL || pcchPathLength == NULL) {
  1635. Status = PDH_INVALID_ARGUMENT;
  1636. }
  1637. else {
  1638. __try {
  1639. DWORD dwPathLength = * pcchPathLength;
  1640. if (* szLocalePath == '\0' || lstrlenA(szLocalePath) > PDH_MAX_COUNTER_PATH) {
  1641. Status = PDH_INVALID_ARGUMENT;
  1642. }
  1643. else {
  1644. szTmpPath = PdhiMultiByteToWideChar(_getmbcp(), szLocalePath);
  1645. if (szTmpPath == NULL) {
  1646. Status = PDH_MEMORY_ALLOCATION_FAILURE;
  1647. }
  1648. }
  1649. if (Status == ERROR_SUCCESS) {
  1650. if (dwPathLength > 0) {
  1651. if (pszFullPathName == NULL) {
  1652. Status = PDH_INVALID_ARGUMENT;
  1653. }
  1654. else {
  1655. * pszFullPathName = '\0';
  1656. * (LPWSTR) (pszFullPathName + (dwPathLength - 1)) = '\0';
  1657. }
  1658. }
  1659. }
  1660. }
  1661. __except (EXCEPTION_EXECUTE_HANDLER) {
  1662. Status = PDH_INVALID_ARGUMENT;
  1663. }
  1664. }
  1665. if (Status == ERROR_SUCCESS) {
  1666. Status = PdhiTranslateCounter(szTmpPath, pszFullPathName, pcchPathLength, TRUE, FALSE);
  1667. }
  1668. G_FREE(szTmpPath);
  1669. return Status;
  1670. }
  1671. PDH_FUNCTION
  1672. PdhTranslateLocaleCounterW(
  1673. IN LPWSTR sz009Path,
  1674. IN LPWSTR pszFullPathName,
  1675. IN LPDWORD pcchPathLength
  1676. )
  1677. {
  1678. PDH_STATUS Status = ERROR_SUCCESS;
  1679. if (sz009Path == NULL || pcchPathLength == NULL) {
  1680. Status = PDH_INVALID_ARGUMENT;
  1681. }
  1682. else {
  1683. __try {
  1684. DWORD dwPathLength = * pcchPathLength;
  1685. if (* sz009Path == L'\0' || lstrlenW(sz009Path) > PDH_MAX_COUNTER_PATH) {
  1686. Status = PDH_INVALID_ARGUMENT;
  1687. }
  1688. else if (dwPathLength > 0) {
  1689. if (pszFullPathName == NULL) {
  1690. Status = PDH_INVALID_ARGUMENT;
  1691. }
  1692. else {
  1693. * pszFullPathName = L'\0';
  1694. * (LPWSTR) (pszFullPathName + (dwPathLength - 1)) = L'\0';
  1695. }
  1696. }
  1697. }
  1698. __except (EXCEPTION_EXECUTE_HANDLER) {
  1699. Status = PDH_INVALID_ARGUMENT;
  1700. }
  1701. }
  1702. if (Status == ERROR_SUCCESS) {
  1703. Status = PdhiTranslateCounter(sz009Path, pszFullPathName, pcchPathLength, FALSE, TRUE);
  1704. }
  1705. return Status;
  1706. }
  1707. PDH_FUNCTION
  1708. PdhTranslateLocaleCounterA(
  1709. IN LPSTR sz009Path,
  1710. IN LPSTR pszFullPathName,
  1711. IN LPDWORD pcchPathLength
  1712. )
  1713. {
  1714. PDH_STATUS Status = ERROR_SUCCESS;
  1715. LPWSTR szTmpPath = NULL;
  1716. DWORD dwPathSize;
  1717. if (sz009Path == NULL || pcchPathLength == NULL) {
  1718. Status = PDH_INVALID_ARGUMENT;
  1719. }
  1720. else {
  1721. __try {
  1722. DWORD dwPathLength = * pcchPathLength;
  1723. if (* sz009Path == '\0' || lstrlenA(sz009Path) > PDH_MAX_COUNTER_PATH) {
  1724. Status = PDH_INVALID_ARGUMENT;
  1725. }
  1726. else {
  1727. szTmpPath = PdhiMultiByteToWideChar(CP_ACP, sz009Path);
  1728. if (szTmpPath == NULL) {
  1729. Status = PDH_MEMORY_ALLOCATION_FAILURE;
  1730. }
  1731. }
  1732. if (Status == ERROR_SUCCESS) {
  1733. if (dwPathLength > 0) {
  1734. if (pszFullPathName == NULL) {
  1735. Status = PDH_INVALID_ARGUMENT;
  1736. }
  1737. else {
  1738. * pszFullPathName = '\0';
  1739. * (LPWSTR) (pszFullPathName + (dwPathLength - 1)) = '\0';
  1740. }
  1741. }
  1742. }
  1743. }
  1744. __except (EXCEPTION_EXECUTE_HANDLER) {
  1745. Status = PDH_INVALID_ARGUMENT;
  1746. }
  1747. }
  1748. if (Status == ERROR_SUCCESS) {
  1749. Status = PdhiTranslateCounter(szTmpPath, pszFullPathName, pcchPathLength, FALSE, FALSE);
  1750. }
  1751. G_FREE(szTmpPath);
  1752. return Status;
  1753. }
  1754. PDH_FUNCTION
  1755. PdhAdd009CounterW(
  1756. IN PDH_HQUERY hQuery,
  1757. IN LPWSTR szFullPath,
  1758. IN DWORD_PTR dwUserData,
  1759. OUT PDH_HCOUNTER * phCounter
  1760. )
  1761. {
  1762. PDH_STATUS Status = ERROR_SUCCESS;
  1763. LPWSTR szLocalePath = NULL;
  1764. DWORD dwPathLength;
  1765. if (szFullPath == NULL || phCounter == NULL) {
  1766. Status = PDH_INVALID_ARGUMENT;
  1767. }
  1768. else if (IsValidQuery(hQuery)) {
  1769. __try {
  1770. DWORD_PTR dwLocalData = dwUserData;
  1771. * phCounter = NULL;
  1772. dwPathLength = lstrlenW(szFullPath);
  1773. if (dwPathLength > PDH_MAX_COUNTER_PATH) {
  1774. Status = PDH_INVALID_ARGUMENT;
  1775. }
  1776. else {
  1777. dwPathLength ++;
  1778. szLocalePath = G_ALLOC(sizeof(WCHAR) * dwPathLength);
  1779. if (szLocalePath != NULL) {
  1780. Status = PdhTranslateLocaleCounterW(szFullPath, szLocalePath, & dwPathLength);
  1781. while (Status == PDH_MORE_DATA) {
  1782. G_FREE(szLocalePath);
  1783. szLocalePath = G_ALLOC(sizeof(WCHAR) * dwPathLength);
  1784. if (szLocalePath == NULL) {
  1785. Status = PDH_MEMORY_ALLOCATION_FAILURE;
  1786. }
  1787. else {
  1788. Status = PdhTranslateLocaleCounterW(szFullPath, szLocalePath, & dwPathLength);
  1789. }
  1790. }
  1791. }
  1792. else {
  1793. Status = PDH_MEMORY_ALLOCATION_FAILURE;
  1794. }
  1795. }
  1796. }
  1797. __except(EXCEPTION_EXECUTE_HANDLER) {
  1798. Status = PDH_INVALID_ARGUMENT;
  1799. }
  1800. }
  1801. else {
  1802. Status = PDH_INVALID_ARGUMENT;
  1803. }
  1804. if (Status == ERROR_SUCCESS) {
  1805. Status = PdhAddCounterW(hQuery, szLocalePath, dwUserData, phCounter);
  1806. }
  1807. G_FREE(szLocalePath);
  1808. return Status;
  1809. }
  1810. PDH_FUNCTION
  1811. PdhAdd009CounterA(
  1812. IN PDH_HQUERY hQuery,
  1813. IN LPSTR szFullPath,
  1814. IN DWORD_PTR dwUserData,
  1815. OUT PDH_HCOUNTER * phCounter
  1816. )
  1817. {
  1818. PDH_STATUS Status = ERROR_SUCCESS;
  1819. LPSTR szLocalePath = NULL;
  1820. DWORD dwPathLength;
  1821. if (szFullPath == NULL || phCounter == NULL) {
  1822. Status = PDH_INVALID_ARGUMENT;
  1823. }
  1824. else if (IsValidQuery(hQuery)) {
  1825. __try {
  1826. DWORD_PTR dwLocalData = dwUserData;
  1827. * phCounter = NULL;
  1828. dwPathLength = lstrlenA(szFullPath) + 1;
  1829. if (dwPathLength > PDH_MAX_COUNTER_PATH) {
  1830. Status = PDH_INVALID_ARGUMENT;
  1831. }
  1832. else {
  1833. dwPathLength ++;
  1834. szLocalePath = G_ALLOC(sizeof(CHAR) * dwPathLength);
  1835. if (szLocalePath != NULL) {
  1836. Status = PdhTranslateLocaleCounterA(szFullPath, szLocalePath, & dwPathLength);
  1837. while (Status == PDH_MORE_DATA) {
  1838. G_FREE(szLocalePath);
  1839. szLocalePath = G_ALLOC(sizeof(CHAR) * dwPathLength);
  1840. if (szLocalePath == NULL) {
  1841. Status = PDH_MEMORY_ALLOCATION_FAILURE;
  1842. }
  1843. else {
  1844. Status = PdhTranslateLocaleCounterA(szFullPath, szLocalePath, & dwPathLength);
  1845. }
  1846. }
  1847. }
  1848. else {
  1849. Status = PDH_MEMORY_ALLOCATION_FAILURE;
  1850. }
  1851. }
  1852. }
  1853. __except(EXCEPTION_EXECUTE_HANDLER) {
  1854. Status = PDH_INVALID_ARGUMENT;
  1855. }
  1856. }
  1857. else {
  1858. Status = PDH_INVALID_ARGUMENT;
  1859. }
  1860. if (Status == ERROR_SUCCESS) {
  1861. Status = PdhAddCounterA(hQuery, szLocalePath, dwUserData, phCounter);
  1862. }
  1863. G_FREE(szLocalePath);
  1864. return Status;
  1865. }
  1866. PDH_FUNCTION
  1867. PdhiConvertUnicodeToAnsi(
  1868. UINT uCodePage,
  1869. LPWSTR wszSrc,
  1870. LPSTR aszDest,
  1871. LPDWORD pdwSize
  1872. )
  1873. {
  1874. PDH_STATUS Status = ERROR_SUCCESS;
  1875. DWORD dwDest;
  1876. DWORD dwSrc = 0;
  1877. DWORD dwSize = * pdwSize;
  1878. if (wszSrc == NULL || pdwSize == NULL) {
  1879. Status = PDH_INVALID_ARGUMENT;
  1880. }
  1881. else if (* wszSrc == L'\0') {
  1882. Status = PDH_INVALID_ARGUMENT;
  1883. }
  1884. else {
  1885. dwSrc = lstrlenW(wszSrc);
  1886. dwDest = WideCharToMultiByte(uCodePage, 0, wszSrc, dwSrc, NULL, 0, NULL, NULL);
  1887. if (aszDest != NULL && (dwDest + 1) <= dwSize) {
  1888. ZeroMemory(aszDest, dwSize * sizeof(CHAR));
  1889. WideCharToMultiByte(_getmbcp(), 0, wszSrc, dwSrc, aszDest, * pdwSize, NULL, NULL);
  1890. TRACE((PDH_DBG_TRACE_INFO),
  1891. (__LINE__,
  1892. PDH_QUERY,
  1893. ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_STR, 2),
  1894. ERROR_SUCCESS,
  1895. TRACE_WSTR(wszSrc),
  1896. TRACE_STR(aszDest),
  1897. TRACE_DWORD(dwSrc),
  1898. TRACE_DWORD(dwDest),
  1899. TRACE_DWORD(dwSize),
  1900. NULL));
  1901. }
  1902. else {
  1903. Status = PDH_MORE_DATA;
  1904. TRACE((PDH_DBG_TRACE_WARNING),
  1905. (__LINE__,
  1906. PDH_QUERY,
  1907. ARG_DEF(ARG_TYPE_WSTR, 1),
  1908. PDH_MORE_DATA,
  1909. TRACE_WSTR(wszSrc),
  1910. TRACE_DWORD(dwSrc),
  1911. TRACE_DWORD(dwDest),
  1912. TRACE_DWORD(dwSize),
  1913. NULL));
  1914. }
  1915. * pdwSize = dwDest + 1;
  1916. }
  1917. return Status;
  1918. }