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

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