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.

3660 lines
119 KiB

  1. /*++
  2. Copyright (C) 1995-1999 Microsoft Corporation
  3. Module Name:
  4. log.c
  5. Abstract:
  6. Log file interface functions exposed in pdh.dll
  7. --*/
  8. #include <windows.h>
  9. #ifndef _PRSHT_H_ // to eliminate W4 errors in commdlg.h
  10. #define _PRSHT_H_
  11. #endif
  12. #include <commdlg.h>
  13. #include <stdlib.h>
  14. #include <assert.h>
  15. #include <mbctype.h>
  16. #include <pdh.h>
  17. #include "pdhidef.h"
  18. //#include "pdhdlgs.h"
  19. #include "strings.h"
  20. #include "log_text.h"
  21. #include "log_bin.h"
  22. #include "log_sql.h"
  23. #include "log_pm.h"
  24. #include "log_wmi.h"
  25. //#include "datasrc.h"
  26. #include "resource.h"
  27. #include "pdhmsg.h"
  28. #pragma warning ( disable : 4213)
  29. // note that when the log file headers are written
  30. // they will be prefixed with a double quote character
  31. LPCSTR szTsvLogFileHeader = "(PDH-TSV 4.0)";
  32. LPCSTR szCsvLogFileHeader = "(PDH-CSV 4.0)";
  33. LPCSTR szBinLogFileHeader = "(PDH-BIN 4.0)";
  34. LPCSTR szTsvType = "PDH-TSV";
  35. LPCSTR szCsvType = "PDH-CSV";
  36. LPCSTR szBinaryType = "PDH-BIN";
  37. const DWORD dwFileHeaderLength = 13;
  38. const DWORD dwTypeLoc = 2;
  39. const DWORD dwVersionLoc = 10;
  40. const DWORD dwFieldLength = 7;
  41. const DWORD dwPerfmonTypeLength = 5; //size in chars
  42. // max mapping size of headers for binary log files
  43. #define PDH_LOG_HEADER_MAP_SIZE 8192
  44. #define VALUE_BUFFER_SIZE 32
  45. typedef struct _FILE_FILTER_INFO {
  46. UINT nDisplayTextResourceId;
  47. LPWSTR szFilterText;
  48. DWORD dwFilterTextSize;
  49. } FILE_FILTER_INFO;
  50. //
  51. // global variables
  52. //
  53. PPDHI_LOG PdhiFirstLogEntry = NULL;
  54. PPDHI_MAPPED_LOG_FILE PdhipFirstLogFile = NULL;
  55. FILE_FILTER_INFO ffiLogFilterInfo[] = {
  56. {IDS_LOGTYPE_PDH_LOGS, (LPWSTR)L"*.blg;*.csv;*.tsv", 17},
  57. {IDS_LOGTYPE_BIN_LOGS, (LPWSTR)L"*.blg", 5},
  58. {IDS_LOGTYPE_CSV_LOGS, (LPWSTR)L"*.csv", 5},
  59. {IDS_LOGTYPE_TSV_LOGS, (LPWSTR)L"*.tsv", 5},
  60. {IDS_LOGTYPE_PM_LOGS, (LPWSTR)L"*.log", 5},
  61. {IDS_LOGTYPE_ALL_LOGS, (LPWSTR)L"*.blg;*.csv;*.tsv;*.log", 23},
  62. {IDS_LOGTYPE_ALL_FILES, (LPWSTR)L"*.*", 4},
  63. {0, NULL, 0}
  64. };
  65. STATIC_DWORD
  66. MakeLogFilterInfoString (
  67. LPWSTR szLogFilter,
  68. DWORD cchLogFilterSize
  69. )
  70. {
  71. FILE_FILTER_INFO *pFFI;
  72. WCHAR szThisEntry[512];
  73. LPWSTR szDestPtr;
  74. LPWSTR szEndPtr;
  75. DWORD dwThisStringLen;
  76. szDestPtr = szLogFilter;
  77. szEndPtr = szDestPtr + cchLogFilterSize;
  78. pFFI = &ffiLogFilterInfo[0];
  79. while ((szEndPtr > szDestPtr) && (pFFI->szFilterText != NULL)) {
  80. dwThisStringLen = LoadStringW(ThisDLLHandle,
  81. pFFI->nDisplayTextResourceId,
  82. szThisEntry, (sizeof(szThisEntry)/sizeof(szThisEntry[0])));
  83. if ((szDestPtr + dwThisStringLen) < szEndPtr) {
  84. // add in this string
  85. lstrcpyW (szDestPtr, szThisEntry);
  86. szDestPtr += dwThisStringLen;
  87. // add in NULL
  88. *szDestPtr++ = 0;
  89. }
  90. dwThisStringLen = pFFI->dwFilterTextSize;
  91. if ((szDestPtr + dwThisStringLen) < szEndPtr) {
  92. // add in this string
  93. lstrcpyW (szDestPtr, pFFI->szFilterText);
  94. szDestPtr += dwThisStringLen;
  95. // add in NULL
  96. *szDestPtr++ = 0;
  97. }
  98. pFFI++;
  99. }
  100. if (szEndPtr > szDestPtr) {
  101. // add MSZ NULL
  102. *szDestPtr++ = 0;
  103. return ERROR_SUCCESS;
  104. } else {
  105. return ERROR_INSUFFICIENT_BUFFER;
  106. }
  107. }
  108. //
  109. // Internal Logging utility functions
  110. //
  111. STATIC_DWORD
  112. OpenReadonlyMappedFile (
  113. PPDHI_LOG pLog,
  114. LPCWSTR szFileName,
  115. PPDHI_MAPPED_LOG_FILE * pFileEntry,
  116. DWORD dwLogType
  117. )
  118. {
  119. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  120. DWORD dwStatus;
  121. DWORD dwSize;
  122. PPDHI_MAPPED_LOG_FILE pOpenedFile;
  123. WCHAR szSectionName[MAX_PATH * 4];
  124. LPWSTR szThisChar;
  125. DWORD dwLoSize, dwHiSize;
  126. dwStatus = WaitForSingleObject (hPdhContextMutex, 10000);
  127. if (dwStatus == WAIT_TIMEOUT) {
  128. pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
  129. }
  130. if (pdhStatus == ERROR_SUCCESS) {
  131. if (PdhipFirstLogFile == NULL) {
  132. // then there are no mapped files so create a new entry and
  133. // fill it with this file
  134. pOpenedFile = NULL;
  135. } else {
  136. for (pOpenedFile = PdhipFirstLogFile;
  137. pOpenedFile != NULL;
  138. pOpenedFile = pOpenedFile->pNext) {
  139. if (lstrcmpiW (szFileName, pOpenedFile->szLogFileName) == 0) break;
  140. }
  141. // here pOpenedFile will either be NULL or a ponter
  142. }
  143. if (pOpenedFile == NULL) {
  144. // create a new entry
  145. dwSize = lstrlenW (szFileName) + 1;
  146. dwSize *= sizeof(WCHAR);
  147. dwSize = QWORD_MULTIPLE (dwSize);
  148. dwSize += sizeof (PDHI_MAPPED_LOG_FILE);
  149. pOpenedFile = (PPDHI_MAPPED_LOG_FILE)G_ALLOC (dwSize);
  150. if (pOpenedFile != NULL) {
  151. // initialize the pointers
  152. pOpenedFile->szLogFileName = (LPWSTR)&pOpenedFile[1];
  153. lstrcpyW (pOpenedFile->szLogFileName, szFileName);
  154. pOpenedFile->hFileHandle = CreateFileW (
  155. pOpenedFile->szLogFileName,
  156. GENERIC_READ, // Read Access for input
  157. FILE_SHARE_READ | FILE_SHARE_WRITE, // allow read sharing
  158. NULL, // default security
  159. OPEN_EXISTING,
  160. FILE_ATTRIBUTE_NORMAL, // ignored
  161. NULL); // no template file
  162. if (pOpenedFile->hFileHandle != INVALID_HANDLE_VALUE) {
  163. DWORD dwPID;
  164. dwPID = GetCurrentProcessId ();
  165. swprintf (szSectionName, (LPCWSTR)L"%s_%8.8x_%s",
  166. cszLogSectionName, dwPID, pOpenedFile->szLogFileName);
  167. // remove filename type characters
  168. for (szThisChar = &szSectionName[0]; *szThisChar != 0; szThisChar++) {
  169. switch (*szThisChar) {
  170. case L'\\':
  171. case L':':
  172. case L'.':
  173. *szThisChar = L'_';
  174. break;
  175. default:
  176. break;
  177. }
  178. }
  179. dwLoSize = GetFileSize (
  180. pOpenedFile->hFileHandle,
  181. & dwHiSize);
  182. pOpenedFile->llFileSize = dwHiSize;
  183. pOpenedFile->llFileSize <<= 32;
  184. pOpenedFile->llFileSize &= 0xFFFFFFFF00000000;
  185. pOpenedFile->llFileSize += dwLoSize;
  186. // just map the header for starters
  187. if (pOpenedFile->llFileSize > 0) {
  188. pLog->iRunidSQL = 0;
  189. if (dwLogType == PDH_LOG_TYPE_RETIRED_BIN) {
  190. pOpenedFile->hMappedFile = CreateFileMappingW(
  191. pOpenedFile->hFileHandle,
  192. NULL,
  193. PAGE_READONLY,
  194. dwHiSize,
  195. dwLoSize,
  196. szSectionName);
  197. if (pOpenedFile->hMappedFile == NULL) {
  198. dwHiSize = 0;
  199. dwLoSize = PDH_LOG_HEADER_MAP_SIZE;
  200. }
  201. else {
  202. pOpenedFile->pData = MapViewOfFile(
  203. pOpenedFile->hMappedFile,
  204. FILE_MAP_READ,
  205. 0,
  206. 0,
  207. dwLoSize);
  208. if (pOpenedFile->pData == NULL) {
  209. dwHiSize = 0;
  210. dwLoSize = PDH_LOG_HEADER_MAP_SIZE;
  211. }
  212. else {
  213. pLog->iRunidSQL = 1;
  214. }
  215. }
  216. }
  217. if (pLog->iRunidSQL == 0) {
  218. pOpenedFile->hMappedFile = CreateFileMappingW(
  219. pOpenedFile->hFileHandle,
  220. NULL, PAGE_READONLY,
  221. dwHiSize, dwLoSize, szSectionName);
  222. if (pOpenedFile->hMappedFile != NULL) {
  223. pOpenedFile->pData = MapViewOfFile (
  224. pOpenedFile->hMappedFile,
  225. FILE_MAP_READ,
  226. 0, 0, dwLoSize);
  227. if (pOpenedFile->pData == NULL) {
  228. pdhStatus = GetLastError();
  229. }
  230. }
  231. else {
  232. pdhStatus = GetLastError();
  233. }
  234. }
  235. } else {
  236. // 0-length file
  237. pdhStatus = ERROR_FILE_INVALID;
  238. }
  239. } else {
  240. pdhStatus = GetLastError();
  241. }
  242. if (pdhStatus == ERROR_SUCCESS) {
  243. // then add this to the list and return the answer
  244. pOpenedFile->pNext = PdhipFirstLogFile;
  245. PdhipFirstLogFile = pOpenedFile;
  246. // init ref count
  247. pOpenedFile->dwRefCount = 1;
  248. *pFileEntry = pOpenedFile;
  249. } else {
  250. // delete it from the list and return NULL
  251. if (pOpenedFile->pData) UnmapViewOfFile (pOpenedFile->pData);
  252. if (pOpenedFile->hMappedFile) CloseHandle (pOpenedFile->hMappedFile);
  253. if (pOpenedFile->hFileHandle) CloseHandle (pOpenedFile->hFileHandle);
  254. G_FREE (pOpenedFile);
  255. *pFileEntry = NULL;
  256. }
  257. } else {
  258. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  259. }
  260. } else {
  261. *pFileEntry = pOpenedFile;
  262. pOpenedFile->dwRefCount++;
  263. }
  264. RELEASE_MUTEX (hPdhContextMutex);
  265. }
  266. return pdhStatus;
  267. }
  268. DWORD
  269. UnmapReadonlyMappedFile (
  270. LPVOID pMemoryBase,
  271. BOOL *bNeedToCloseHandles
  272. )
  273. {
  274. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  275. DWORD dwStatus;
  276. PPDHI_MAPPED_LOG_FILE pOpenedFile;
  277. PPDHI_MAPPED_LOG_FILE pPrevFile = NULL;
  278. dwStatus = WaitForSingleObject (hPdhContextMutex, 10000);
  279. if (dwStatus == WAIT_TIMEOUT) {
  280. pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
  281. }
  282. if (pdhStatus == ERROR_SUCCESS) {
  283. // find file to close
  284. for (pOpenedFile = PdhipFirstLogFile;
  285. pOpenedFile != NULL;
  286. pOpenedFile = pOpenedFile->pNext) {
  287. if (pOpenedFile->pData == pMemoryBase) {
  288. break;
  289. } else {
  290. pPrevFile = pOpenedFile;
  291. }
  292. }
  293. // here pOpenedFile will either be NULL or a ponter
  294. if (pOpenedFile != NULL) {
  295. --pOpenedFile->dwRefCount;
  296. if (!pOpenedFile->dwRefCount) {
  297. // found so remove from list and close
  298. if (pOpenedFile == PdhipFirstLogFile) {
  299. PdhipFirstLogFile = pOpenedFile->pNext;
  300. } else {
  301. #pragma warning( disable: 4701 ) // pPrevFile will only be used if the opened log is not the first log
  302. pPrevFile->pNext = pOpenedFile->pNext;
  303. #pragma warning (default : 4701 )
  304. }
  305. // close open resources
  306. if (pOpenedFile->pData) UnmapViewOfFile (pOpenedFile->pData);
  307. if (pOpenedFile->hMappedFile) CloseHandle (pOpenedFile->hMappedFile);
  308. if (pOpenedFile->hFileHandle) CloseHandle (pOpenedFile->hFileHandle);
  309. G_FREE (pOpenedFile);
  310. }
  311. *bNeedToCloseHandles = FALSE;
  312. } else {
  313. // then this must be a normal mapped file
  314. if (!UnmapViewOfFile (pMemoryBase)) {
  315. pdhStatus = GetLastError();
  316. }
  317. *bNeedToCloseHandles = TRUE;
  318. }
  319. RELEASE_MUTEX (hPdhContextMutex);
  320. }
  321. return pdhStatus;
  322. }
  323. STATIC_BOOL
  324. IsValidLogHandle (
  325. IN HLOG hLog
  326. )
  327. /*++
  328. Routine Description:
  329. examines the log handle to verify it is a valid log entry. For now
  330. the test amounts to:
  331. the Handle is NOT NULL
  332. the memory is accessible (i.e. it doesn't AV)
  333. the signature array is valid
  334. the size field is correct
  335. if any tests fail, the handle is presumed to be invalid
  336. Arguments:
  337. IN HLOG hLog
  338. the handle of the log entry to test
  339. Return Value:
  340. TRUE the handle passes all the tests
  341. FALSE one of the test's failed and the handle is not a valid counter
  342. --*/
  343. {
  344. BOOL bReturn = FALSE; // assume it's not a valid query
  345. PPDHI_LOG pLog;
  346. #if DBG
  347. LONG lStatus = ERROR_SUCCESS;
  348. #endif
  349. __try {
  350. if (hLog != NULL) {
  351. // see if a valid signature
  352. pLog = (PPDHI_LOG) hLog;
  353. if ((*(DWORD *)&pLog->signature[0] == SigLog) &&
  354. (pLog->dwLength == sizeof (PDHI_LOG))){
  355. bReturn = TRUE;
  356. } else {
  357. // this is not a valid log entry because the sig is bad
  358. // or the structure is the wrong size
  359. }
  360. } else {
  361. // this is not a valid counter because the handle is NULL
  362. }
  363. } __except (EXCEPTION_EXECUTE_HANDLER) {
  364. // something failed miserably so we can assume this is invalid
  365. #if DBG
  366. lStatus = GetExceptionCode();
  367. #endif
  368. }
  369. return bReturn;
  370. }
  371. STATIC_DWORD
  372. GetLogFileType (
  373. IN HANDLE hLogFile
  374. )
  375. {
  376. CHAR cBuffer[MAX_PATH];
  377. CHAR cType[MAX_PATH];
  378. WCHAR wcType[MAX_PATH];
  379. BOOL bStatus;
  380. DWORD dwResult;
  381. DWORD dwBytesRead;
  382. memset (&cBuffer[0], 0, sizeof(cBuffer));
  383. memset (&cType[0], 0, sizeof(cType));
  384. memset (&wcType[0], 0, sizeof(wcType));
  385. // read first log file record
  386. SetFilePointer (hLogFile, 0, NULL, FILE_BEGIN);
  387. bStatus = ReadFile (hLogFile,
  388. (LPVOID)cBuffer,
  389. dwFileHeaderLength,
  390. &dwBytesRead,
  391. NULL);
  392. if (bStatus) {
  393. // read header record to get type
  394. lstrcpynA (cType, (LPSTR)(cBuffer+dwTypeLoc), dwFieldLength+1);
  395. if (lstrcmpiA(cType, szTsvType) == 0) {
  396. dwResult = PDH_LOG_TYPE_TSV;
  397. } else if (lstrcmpiA(cType, szCsvType) == 0) {
  398. dwResult = PDH_LOG_TYPE_CSV;
  399. } else if (lstrcmpiA(cType, szBinaryType) == 0) {
  400. dwResult = PDH_LOG_TYPE_RETIRED_BIN;
  401. } else {
  402. // perfmon log file type string is in a different
  403. // location than sysmon logs and used wide chars.
  404. lstrcpynW (wcType, (LPWSTR)cBuffer, dwPerfmonTypeLength+1);
  405. if (lstrcmpiW(wcType, cszPerfmonLogSig) == 0) {
  406. dwResult = PDH_LOG_TYPE_PERFMON;
  407. } else {
  408. dwResult = PDH_LOG_TYPE_UNDEFINED;
  409. }
  410. }
  411. } else {
  412. // unable to read file
  413. dwResult = PDH_LOG_TYPE_UNDEFINED;
  414. }
  415. return dwResult;
  416. }
  417. STATIC_PDH_FUNCTION
  418. CreateNewLogEntry (
  419. IN LPCWSTR szLogFileName,
  420. IN HQUERY hQuery,
  421. IN DWORD dwMaxSize,
  422. IN PPDHI_LOG *pLog
  423. )
  424. /*++
  425. creates a new log entry and inserts it in the list of open log files
  426. --*/
  427. {
  428. PPDHI_LOG pNewLog;
  429. PPDHI_LOG pFirstLog;
  430. PPDHI_LOG pLastLog;
  431. DWORD dwSize;
  432. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  433. DWORD dwLogFileNameSize;
  434. dwLogFileNameSize = lstrlenW(szLogFileName) + 1;
  435. dwSize = dwLogFileNameSize;
  436. dwSize *= sizeof (WCHAR);
  437. dwSize *= 2; // double to make room for cat file name
  438. dwSize = DWORD_MULTIPLE (dwSize); // ... rounded to the next DWORD
  439. dwSize += sizeof (PDHI_LOG); // + room for the data block
  440. pNewLog = G_ALLOC (dwSize); // allocate new structure
  441. if (pNewLog == NULL) {
  442. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  443. *pLog = NULL;
  444. } else {
  445. // initialize the elements in the structure
  446. *((LPDWORD)(&pNewLog->signature[0])) = SigLog;
  447. // create and acquire a data mutex for this
  448. pNewLog->hLogMutex = CreateMutexW (NULL, TRUE, NULL);
  449. assert (pNewLog->hLogMutex != NULL);
  450. // insert this item at the end of the list
  451. if (PdhiFirstLogEntry == NULL) {
  452. // then this is the first entry
  453. PdhiFirstLogEntry = pNewLog;
  454. pNewLog->next.flink =
  455. pNewLog->next.blink = pNewLog;
  456. } else {
  457. // go to the first entry and insert this one just before it
  458. pFirstLog = PdhiFirstLogEntry;
  459. pLastLog = pFirstLog->next.blink;
  460. pNewLog->next.flink = pLastLog->next.flink;
  461. pLastLog->next.flink = pNewLog;
  462. pNewLog->next.blink = pFirstLog->next.blink;
  463. pFirstLog->next.blink = pNewLog;
  464. }
  465. // set length field (this is used more for validation
  466. // than anything else
  467. pNewLog->dwLength = sizeof (PDHI_LOG);
  468. // append filename strings immediately after this block
  469. pNewLog->szLogFileName = (LPWSTR)(&pNewLog[1]);
  470. lstrcpyW (pNewLog->szLogFileName, szLogFileName);
  471. // locate catalog name immediately after log file name
  472. pNewLog->szCatFileName = pNewLog->szLogFileName + dwLogFileNameSize;
  473. //
  474. // NOTE: Catalog should be in the logfile itself, so no need for
  475. // yet another file extension
  476. lstrcpyW (pNewLog->szCatFileName, szLogFileName);
  477. // initialize the file handles
  478. pNewLog->hLogFileHandle = INVALID_HANDLE_VALUE;
  479. pNewLog->hCatFileHandle = INVALID_HANDLE_VALUE;
  480. // initialize the Record Length size
  481. pNewLog->llMaxSize = (LONGLONG) ((ULONGLONG) dwMaxSize);
  482. pNewLog->dwRecord1Size = 0;
  483. // assign the query
  484. pNewLog->pQuery = (PPDHI_QUERY)hQuery;
  485. pNewLog->dwLogFormat = 0; // for now
  486. pNewLog->pPerfmonInfo = NULL;
  487. *pLog = pNewLog;
  488. }
  489. return pdhStatus;
  490. }
  491. OpenSQLLog (
  492. IN PPDHI_LOG pLog,
  493. IN DWORD dwAccessFlags,
  494. IN LPDWORD lpdwLogType
  495. )
  496. {
  497. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  498. pLog->dwLogFormat = PDH_LOG_TYPE_SQL;
  499. pLog->dwLogFormat |=
  500. dwAccessFlags & (PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
  501. if ((dwAccessFlags & PDH_LOG_WRITE_ACCESS) == PDH_LOG_WRITE_ACCESS) {
  502. pdhStatus = PdhiOpenOutputSQLLog (pLog);
  503. } else {
  504. pdhStatus = PdhiOpenInputSQLLog (pLog);
  505. }
  506. *lpdwLogType = (DWORD)(LOWORD(pLog->dwLogFormat));
  507. return pdhStatus;
  508. }
  509. STATIC_PDH_FUNCTION
  510. OpenInputLogFile (
  511. IN PPDHI_LOG pLog,
  512. IN DWORD dwAccessFlags,
  513. IN LPDWORD lpdwLogType
  514. )
  515. {
  516. LONG Win32Error;
  517. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  518. DWORD dwFileCreate = 0;
  519. PPDHI_MAPPED_LOG_FILE pMappedFileInfo = NULL;
  520. // for input, the query handle is NULL
  521. pLog->pQuery = NULL;
  522. ////////////////
  523. // SQL goes here
  524. ///////////////
  525. // First test whether logfile is WMI Event Trace format.
  526. // If all logfiles are WMI Event Trace format, return immediately;
  527. // otherwise try other formats.
  528. //
  529. pdhStatus = PdhiOpenInputWmiLog(pLog);
  530. if (pdhStatus == ERROR_SUCCESS) {
  531. pLog->dwLogFormat = PDH_LOG_TYPE_BINARY;
  532. pLog->dwLogFormat |=
  533. dwAccessFlags & (PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
  534. * lpdwLogType = PDH_LOG_TYPE_BINARY;
  535. return pdhStatus;
  536. }
  537. pdhStatus = ERROR_SUCCESS;
  538. // open file for input based on the specified access flags
  539. switch (dwAccessFlags & PDH_LOG_CREATE_MASK) {
  540. case PDH_LOG_OPEN_EXISTING:
  541. dwFileCreate = OPEN_EXISTING;
  542. break;
  543. case PDH_LOG_CREATE_NEW:
  544. case PDH_LOG_CREATE_ALWAYS:
  545. case PDH_LOG_OPEN_ALWAYS:
  546. // a log file to be read from must not be empty or non-existent
  547. default:
  548. // unrecognized value
  549. pdhStatus = PDH_INVALID_ARGUMENT;
  550. break;
  551. }
  552. if (pdhStatus == ERROR_SUCCESS) {
  553. pLog->hLogFileHandle = CreateFileW (
  554. pLog->szLogFileName,
  555. GENERIC_READ, // Read Access for input
  556. FILE_SHARE_READ | FILE_SHARE_WRITE, // allow read sharing
  557. NULL, // default security
  558. dwFileCreate,
  559. FILE_ATTRIBUTE_NORMAL, // ignored
  560. NULL); // no template file
  561. if (pLog->hLogFileHandle == INVALID_HANDLE_VALUE) {
  562. Win32Error = GetLastError();
  563. // translate to PDH_ERROR
  564. switch (Win32Error) {
  565. case ERROR_FILE_NOT_FOUND:
  566. pdhStatus = PDH_FILE_NOT_FOUND;
  567. break;
  568. case ERROR_ALREADY_EXISTS:
  569. pdhStatus = PDH_FILE_ALREADY_EXISTS;
  570. break;
  571. default:
  572. switch (dwAccessFlags & PDH_LOG_CREATE_MASK) {
  573. case PDH_LOG_CREATE_NEW:
  574. case PDH_LOG_CREATE_ALWAYS:
  575. pdhStatus = PDH_LOG_FILE_CREATE_ERROR;
  576. break;
  577. case PDH_LOG_OPEN_EXISTING:
  578. case PDH_LOG_OPEN_ALWAYS:
  579. default:
  580. pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
  581. break;
  582. }
  583. break;
  584. }
  585. }
  586. }
  587. if (pdhStatus == ERROR_SUCCESS) {
  588. // read the log header and determine the log file type
  589. pLog->dwLogFormat = GetLogFileType (pLog->hLogFileHandle);
  590. if (pLog->dwLogFormat != 0) {
  591. pLog->dwLogFormat |=
  592. dwAccessFlags & (PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
  593. } else {
  594. pdhStatus = PDH_LOG_TYPE_NOT_FOUND;
  595. }
  596. switch (LOWORD(pLog->dwLogFormat)) {
  597. break;
  598. case PDH_LOG_TYPE_RETIRED_BIN:
  599. case PDH_LOG_TYPE_PERFMON:
  600. // close file opened above
  601. CloseHandle (pLog->hLogFileHandle);
  602. pLog->iRunidSQL = 0;
  603. pdhStatus = OpenReadonlyMappedFile (
  604. pLog,
  605. pLog->szLogFileName,
  606. & pMappedFileInfo,
  607. (DWORD) LOWORD(pLog->dwLogFormat));
  608. if (pdhStatus == ERROR_SUCCESS) {
  609. // then update log fields
  610. pLog->hLogFileHandle = pMappedFileInfo->hFileHandle;
  611. pLog->hMappedLogFile = pMappedFileInfo->hMappedFile;
  612. pLog->lpMappedFileBase = pMappedFileInfo->pData;
  613. pLog->llFileSize = pMappedFileInfo->llFileSize;
  614. }
  615. break;
  616. case PDH_LOG_TYPE_CSV:
  617. case PDH_LOG_TYPE_TSV:
  618. default:
  619. break;
  620. }
  621. }
  622. if (pdhStatus == ERROR_SUCCESS) {
  623. // call any type-specific open functions
  624. switch (LOWORD(pLog->dwLogFormat)) {
  625. case PDH_LOG_TYPE_CSV:
  626. case PDH_LOG_TYPE_TSV:
  627. pdhStatus = PdhiOpenInputTextLog (pLog);
  628. break;
  629. case PDH_LOG_TYPE_RETIRED_BIN:
  630. pdhStatus = PdhiOpenInputBinaryLog (pLog);
  631. break;
  632. case PDH_LOG_TYPE_PERFMON:
  633. pdhStatus = PdhiOpenInputPerfmonLog (pLog);
  634. break;
  635. default:
  636. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  637. break;
  638. }
  639. *lpdwLogType = (DWORD)(LOWORD(pLog->dwLogFormat));
  640. }
  641. return pdhStatus;
  642. }
  643. STATIC_PDH_FUNCTION
  644. OpenUpdateLogFile (
  645. IN PPDHI_LOG pLog,
  646. IN DWORD dwAccessFlags,
  647. IN LPDWORD lpdwLogType
  648. )
  649. {
  650. LONG Win32Error;
  651. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  652. DWORD dwFileCreate = 0;
  653. // for input, the query handle is NULL
  654. pLog->pQuery = NULL;
  655. // open file for input based on the specified access flags
  656. switch (dwAccessFlags & PDH_LOG_CREATE_MASK) {
  657. case PDH_LOG_OPEN_EXISTING:
  658. dwFileCreate = OPEN_EXISTING;
  659. break;
  660. case PDH_LOG_CREATE_NEW:
  661. case PDH_LOG_CREATE_ALWAYS:
  662. case PDH_LOG_OPEN_ALWAYS:
  663. // a log file to be updated must not be empty or non-existent
  664. default:
  665. // unrecognized value
  666. pdhStatus = PDH_INVALID_ARGUMENT;
  667. break;
  668. }
  669. if (pdhStatus == ERROR_SUCCESS) {
  670. pLog->hLogFileHandle = CreateFileW (
  671. pLog->szLogFileName,
  672. GENERIC_READ | GENERIC_WRITE, // Read & Write Access for input
  673. FILE_SHARE_READ, // allow read sharing
  674. NULL, // default security
  675. dwFileCreate,
  676. FILE_ATTRIBUTE_NORMAL, // ignored
  677. NULL); // no template file
  678. if (pLog->hLogFileHandle == INVALID_HANDLE_VALUE) {
  679. Win32Error = GetLastError();
  680. // translate to PDH_ERROR
  681. switch (Win32Error) {
  682. case ERROR_FILE_NOT_FOUND:
  683. pdhStatus = PDH_FILE_NOT_FOUND;
  684. break;
  685. case ERROR_ALREADY_EXISTS:
  686. pdhStatus = PDH_FILE_ALREADY_EXISTS;
  687. break;
  688. default:
  689. switch (dwAccessFlags & PDH_LOG_CREATE_MASK) {
  690. case PDH_LOG_CREATE_NEW:
  691. case PDH_LOG_CREATE_ALWAYS:
  692. pdhStatus = PDH_LOG_FILE_CREATE_ERROR;
  693. break;
  694. case PDH_LOG_OPEN_EXISTING:
  695. case PDH_LOG_OPEN_ALWAYS:
  696. default:
  697. pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
  698. break;
  699. }
  700. break;
  701. }
  702. }
  703. }
  704. if (pdhStatus == ERROR_SUCCESS) {
  705. // read the log header and determine the log file type
  706. pLog->dwLogFormat = GetLogFileType (pLog->hLogFileHandle);
  707. if (pLog->dwLogFormat != 0) {
  708. pLog->dwLogFormat |=
  709. dwAccessFlags & (PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
  710. } else {
  711. pdhStatus = PDH_LOG_TYPE_NOT_FOUND;
  712. }
  713. // call any type-specific open functions
  714. switch (LOWORD(pLog->dwLogFormat)) {
  715. case PDH_LOG_TYPE_CSV:
  716. case PDH_LOG_TYPE_TSV:
  717. case PDH_LOG_TYPE_BINARY:
  718. // this will be added later
  719. // updating a text file will be limited to appending, but that
  720. // has it's own problems (e.g. insuring the counter list
  721. // is the same in the new query as the one stored in the log file
  722. pdhStatus = PDH_NOT_IMPLEMENTED;
  723. break;
  724. case PDH_LOG_TYPE_RETIRED_BIN:
  725. pdhStatus = PdhiOpenUpdateBinaryLog (pLog);
  726. break;
  727. default:
  728. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  729. break;
  730. }
  731. *lpdwLogType = (DWORD)(LOWORD(pLog->dwLogFormat));
  732. }
  733. return pdhStatus;
  734. }
  735. STATIC_PDH_FUNCTION
  736. OpenOutputLogFile (
  737. IN PPDHI_LOG pLog,
  738. IN DWORD dwAccessFlags,
  739. IN LPDWORD lpdwLogType
  740. )
  741. {
  742. LONG Win32Error;
  743. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  744. DWORD dwFileCreate = 0;
  745. // for output, the query handle must be valid
  746. if (!IsValidQuery ((HQUERY)pLog->pQuery)) {
  747. pdhStatus = PDH_INVALID_HANDLE;
  748. }
  749. // special handling PDH_LOG_TYPE_BINARY
  750. //
  751. if (* lpdwLogType == PDH_LOG_TYPE_BINARY) {
  752. * lpdwLogType = PDH_LOG_TYPE_BINARY;
  753. pLog->dwLogFormat =
  754. dwAccessFlags & (PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
  755. pLog->dwLogFormat |=
  756. *lpdwLogType & ~(PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
  757. return (PdhiOpenOutputWmiLog(pLog));
  758. }
  759. // open file for output based on the specified access flags
  760. if (pdhStatus == ERROR_SUCCESS) {
  761. switch (dwAccessFlags & PDH_LOG_CREATE_MASK) {
  762. case PDH_LOG_CREATE_NEW:
  763. dwFileCreate = CREATE_NEW;
  764. break;
  765. case PDH_LOG_CREATE_ALWAYS:
  766. dwFileCreate = CREATE_ALWAYS;
  767. break;
  768. case PDH_LOG_OPEN_EXISTING:
  769. dwFileCreate = OPEN_EXISTING;
  770. break;
  771. case PDH_LOG_OPEN_ALWAYS:
  772. dwFileCreate = OPEN_ALWAYS;
  773. break;
  774. default:
  775. // unrecognized value
  776. pdhStatus = PDH_INVALID_ARGUMENT;
  777. break;
  778. }
  779. }
  780. if (pdhStatus == ERROR_SUCCESS) {
  781. pLog->hLogFileHandle = CreateFileW (
  782. pLog->szLogFileName,
  783. GENERIC_WRITE | GENERIC_READ, // write access for output
  784. FILE_SHARE_READ, // allow read sharing
  785. NULL, // default security
  786. dwFileCreate,
  787. FILE_ATTRIBUTE_NORMAL,
  788. NULL); // no template file
  789. if (pLog->hLogFileHandle == INVALID_HANDLE_VALUE) {
  790. Win32Error = GetLastError();
  791. // translate to PDH_ERROR
  792. switch (Win32Error) {
  793. case ERROR_FILE_NOT_FOUND:
  794. pdhStatus = PDH_FILE_NOT_FOUND;
  795. break;
  796. case ERROR_ALREADY_EXISTS:
  797. pdhStatus = PDH_FILE_ALREADY_EXISTS;
  798. break;
  799. default:
  800. switch (dwAccessFlags & PDH_LOG_CREATE_MASK) {
  801. case PDH_LOG_CREATE_NEW:
  802. case PDH_LOG_CREATE_ALWAYS:
  803. pdhStatus = PDH_LOG_FILE_CREATE_ERROR;
  804. break;
  805. case PDH_LOG_OPEN_EXISTING:
  806. case PDH_LOG_OPEN_ALWAYS:
  807. default:
  808. pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
  809. break;
  810. }
  811. break;
  812. }
  813. }
  814. }
  815. if (pdhStatus == ERROR_SUCCESS) {
  816. // the file opened successfully so update the data structure
  817. // this assumes the access flags are in the HIWORD and the...
  818. pLog->dwLogFormat =
  819. dwAccessFlags & (PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
  820. // the type id is in the LOWORD
  821. pLog->dwLogFormat |=
  822. *lpdwLogType & ~(PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
  823. // call any type-specific open functions
  824. switch (LOWORD(pLog->dwLogFormat)) {
  825. case PDH_LOG_TYPE_CSV:
  826. case PDH_LOG_TYPE_TSV:
  827. pdhStatus = PdhiOpenOutputTextLog(pLog);
  828. break;
  829. case PDH_LOG_TYPE_RETIRED_BIN:
  830. pdhStatus = PDH_NOT_IMPLEMENTED;
  831. break;
  832. case PDH_LOG_TYPE_PERFMON:
  833. pdhStatus = PDH_NOT_IMPLEMENTED;
  834. break;
  835. case PDH_LOG_TYPE_SQL:
  836. // SQL data soruce should be handled in PdhOpenLogW() before
  837. // it calls OpenOutputLogFile(). If it goes here, this is
  838. // an incorrect SQL datasoruce format.
  839. //
  840. pdhStatus = PDH_INVALID_SQL_LOG_FORMAT;
  841. break;
  842. default:
  843. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  844. break;
  845. }
  846. }
  847. return pdhStatus;
  848. }
  849. STATIC_PDH_FUNCTION
  850. WriteLogHeader (
  851. IN PPDHI_LOG pLog,
  852. IN LPCWSTR szUserCaption
  853. )
  854. {
  855. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  856. switch (LOWORD(pLog->dwLogFormat)) {
  857. case PDH_LOG_TYPE_CSV:
  858. case PDH_LOG_TYPE_TSV:
  859. pdhStatus = PdhiWriteTextLogHeader (pLog, szUserCaption);
  860. break;
  861. case PDH_LOG_TYPE_RETIRED_BIN:
  862. pdhStatus = PdhiWriteBinaryLogHeader (pLog, szUserCaption);
  863. break;
  864. case PDH_LOG_TYPE_BINARY:
  865. break;
  866. case PDH_LOG_TYPE_SQL:
  867. pdhStatus = PdhiWriteSQLLogHeader (pLog, szUserCaption);
  868. break;
  869. default:
  870. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  871. break;
  872. }
  873. return pdhStatus;
  874. }
  875. STATIC_PDH_FUNCTION
  876. DeleteLogEntry (
  877. PPDHI_LOG pLog
  878. )
  879. {
  880. PDH_STATUS pdhStatus;
  881. PPDHI_LOG pLogNext;
  882. // assumes structure is locked
  883. if (IsValidLogHandle ((HLOG)pLog)) {
  884. if (PdhiFirstLogEntry == pLog) {
  885. // then this is the first entry in the list so the
  886. // the "first" entry will be the next forward entry
  887. if ((pLog->next.flink == pLog->next.blink) &&
  888. (pLog->next.flink == pLog)){
  889. // then this is the only entry in the list so clear the first
  890. // log entry
  891. PdhiFirstLogEntry = NULL;
  892. } else {
  893. // remove this entry from the list
  894. (pLog->next.flink)->next.blink = pLog->next.blink;
  895. (pLog->next.blink)->next.flink = pLog->next.flink;
  896. PdhiFirstLogEntry = pLog->next.flink;
  897. }
  898. } else {
  899. // it's not the first one, so
  900. // just remove it from the list
  901. (pLog->next.flink)->next.blink = pLog->next.blink;
  902. (pLog->next.blink)->next.flink = pLog->next.flink;
  903. }
  904. // and release the memory block;
  905. RELEASE_MUTEX (pLog->hLogMutex);
  906. CloseHandle (pLog->hLogMutex);
  907. while (pLog) {
  908. pLogNext = pLog->NextLog;
  909. G_FREE (pLog);
  910. pLog = pLogNext;
  911. }
  912. pdhStatus = ERROR_SUCCESS;
  913. } else {
  914. pdhStatus = PDH_INVALID_HANDLE;
  915. }
  916. return pdhStatus;
  917. }
  918. STATIC_PDH_FUNCTION
  919. CloseAndDeleteLogEntry (
  920. IN PPDHI_LOG pLog,
  921. IN DWORD dwFlags,
  922. IN BOOLEAN bForceDelete
  923. )
  924. {
  925. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  926. BOOL bStatus;
  927. BOOL bNeedToCloseHandles = TRUE;
  928. // call any type-specific open functions
  929. switch (LOWORD(pLog->dwLogFormat)) {
  930. case PDH_LOG_TYPE_CSV:
  931. case PDH_LOG_TYPE_TSV:
  932. pdhStatus = PdhiCloseTextLog(pLog, dwFlags);
  933. break;
  934. case PDH_LOG_TYPE_RETIRED_BIN:
  935. pdhStatus = PdhiCloseBinaryLog(pLog, dwFlags);
  936. break;
  937. case PDH_LOG_TYPE_PERFMON:
  938. pdhStatus = PdhiClosePerfmonLog(pLog, dwFlags);
  939. break;
  940. case PDH_LOG_TYPE_BINARY:
  941. pdhStatus = PdhiCloseWmiLog(pLog, dwFlags);
  942. break;
  943. case PDH_LOG_TYPE_SQL:
  944. pdhStatus = PdhiCloseSQLLog(pLog, dwFlags);
  945. break;
  946. default:
  947. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  948. break;
  949. }
  950. if (bForceDelete || pdhStatus == ERROR_SUCCESS) {
  951. if (pLog->lpMappedFileBase != NULL) {
  952. UnmapReadonlyMappedFile (pLog->lpMappedFileBase, &bNeedToCloseHandles);
  953. } else {
  954. // if this wasn't a mapped file, then delete
  955. // the "current record" buffer
  956. if (pLog->pLastRecordRead != NULL) {
  957. G_FREE (pLog->pLastRecordRead);
  958. pLog->pLastRecordRead = NULL;
  959. }
  960. }
  961. if (bNeedToCloseHandles) {
  962. if (pLog->hMappedLogFile != NULL) {
  963. bStatus = CloseHandle (pLog->hMappedLogFile);
  964. assert (bStatus);
  965. pLog->hMappedLogFile = NULL;
  966. }
  967. if (pLog->hLogFileHandle != INVALID_HANDLE_VALUE) {
  968. bStatus = CloseHandle (pLog->hLogFileHandle);
  969. assert (bStatus);
  970. pLog->hLogFileHandle = INVALID_HANDLE_VALUE;
  971. }
  972. } else {
  973. // the handles have already been closed so just
  974. // clear their values
  975. pLog->lpMappedFileBase = NULL;
  976. pLog->hMappedLogFile = NULL;
  977. pLog->hLogFileHandle = INVALID_HANDLE_VALUE;
  978. }
  979. if (pLog->pPerfmonInfo != NULL) {
  980. G_FREE (pLog->pPerfmonInfo);
  981. pLog->pPerfmonInfo = NULL;
  982. }
  983. pLog->dwLastRecordRead = 0;
  984. if (pLog->hCatFileHandle != INVALID_HANDLE_VALUE) {
  985. bStatus = CloseHandle (pLog->hCatFileHandle);
  986. assert (bStatus);
  987. pLog->hCatFileHandle = INVALID_HANDLE_VALUE;
  988. }
  989. if ((dwFlags & PDH_FLAGS_CLOSE_QUERY) == PDH_FLAGS_CLOSE_QUERY) {
  990. pdhStatus = PdhCloseQuery ((HQUERY)pLog->pQuery);
  991. }
  992. pdhStatus = DeleteLogEntry (pLog);
  993. }
  994. return pdhStatus;
  995. }
  996. //
  997. // Local utility functions
  998. //
  999. PDH_FUNCTION
  1000. PdhiGetLogCounterInfo (
  1001. IN HLOG hLog,
  1002. IN PPDHI_COUNTER pCounter
  1003. )
  1004. // validates the counter is in the log file and initializes the data fields
  1005. {
  1006. PPDHI_LOG pLog;
  1007. PDH_STATUS pdhStatus;
  1008. if (IsValidLogHandle(hLog)) {
  1009. pLog = (PPDHI_LOG)hLog;
  1010. switch (LOWORD(pLog->dwLogFormat)) {
  1011. case PDH_LOG_TYPE_CSV:
  1012. case PDH_LOG_TYPE_TSV:
  1013. pdhStatus = PdhiGetTextLogCounterInfo (
  1014. pLog, pCounter);
  1015. break;
  1016. case PDH_LOG_TYPE_BINARY:
  1017. case PDH_LOG_TYPE_RETIRED_BIN:
  1018. pdhStatus = PdhiGetBinaryLogCounterInfo (
  1019. pLog, pCounter);
  1020. break;
  1021. case PDH_LOG_TYPE_PERFMON:
  1022. pdhStatus = PdhiGetPerfmonLogCounterInfo (
  1023. pLog, pCounter);
  1024. break;
  1025. case PDH_LOG_TYPE_SQL:
  1026. pdhStatus = PdhiGetSQLLogCounterInfo (
  1027. pLog, pCounter);
  1028. break;
  1029. default:
  1030. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  1031. break;
  1032. }
  1033. } else {
  1034. pdhStatus = PDH_INVALID_HANDLE;
  1035. }
  1036. return pdhStatus;
  1037. }
  1038. DWORD
  1039. AddUniqueWideStringToMultiSz (
  1040. IN LPVOID mszDest,
  1041. IN LPWSTR szSource,
  1042. IN BOOL bUnicodeDest
  1043. )
  1044. /*++
  1045. Routine Description:
  1046. searches the Multi-SZ list, mszDest for szSource and appends it
  1047. to mszDest if it wasn't found
  1048. Arguments:
  1049. OUT LPVOID mszDest Multi-SZ list to get new string
  1050. IN LPWSTR szSource string to add if it's not already in list
  1051. ReturnValue:
  1052. The new length of the destination string including both
  1053. trailing NULL characters if the string was added, or 0 if the
  1054. string is already in the list.
  1055. --*/
  1056. {
  1057. LPVOID szDestElem;
  1058. DWORD dwReturnLength;
  1059. LPSTR aszSource = NULL;
  1060. DWORD dwLength;
  1061. // check arguments
  1062. if ((mszDest == NULL) || (szSource == NULL)) return 0; // invalid buffers
  1063. if (*szSource == '\0') return 0; // no source string to add
  1064. // if not a unicode list, make an ansi copy of the source string to
  1065. // compare
  1066. // and ultimately copy if it's not already in the list
  1067. if (!bUnicodeDest) {
  1068. dwLength = lstrlenW(szSource) + 1;
  1069. aszSource = G_ALLOC ((dwLength * 3 * sizeof(CHAR))); // DBCS concern
  1070. if (aszSource != NULL) {
  1071. dwReturnLength = WideCharToMultiByte(_getmbcp(),
  1072. 0,
  1073. szSource,
  1074. lstrlenW(szSource),
  1075. aszSource,
  1076. dwLength,
  1077. NULL,
  1078. NULL);
  1079. } else {
  1080. // unable to allocate memory for the temp string
  1081. dwReturnLength = 0;
  1082. }
  1083. } else {
  1084. // just use the ANSI version of the source file name
  1085. dwReturnLength = 1;
  1086. }
  1087. if (dwReturnLength > 0) {
  1088. // go to end of dest string
  1089. //
  1090. for (szDestElem = mszDest;
  1091. (bUnicodeDest ? (*(LPWSTR)szDestElem != 0) :
  1092. (*(LPSTR)szDestElem != 0));
  1093. ) {
  1094. if (bUnicodeDest) {
  1095. // bail out if string already in list
  1096. if (lstrcmpiW((LPCWSTR)szDestElem, szSource) == 0) {
  1097. dwReturnLength = 0;
  1098. goto AddString_Bailout;
  1099. } else {
  1100. // goto the next item
  1101. szDestElem = (LPVOID)((LPWSTR)szDestElem +
  1102. (lstrlenW((LPCWSTR)szDestElem)+1));
  1103. }
  1104. } else {
  1105. // bail out if string already in list
  1106. if (lstrcmpiA((LPSTR)szDestElem, aszSource) == 0) {
  1107. dwReturnLength = 0;
  1108. goto AddString_Bailout;
  1109. } else {
  1110. // goto the next item
  1111. szDestElem = (LPVOID)((LPSTR)szDestElem +
  1112. (lstrlenA((LPCSTR)szDestElem)+1));
  1113. }
  1114. }
  1115. }
  1116. // if here, then add string
  1117. // szDestElem is at end of list
  1118. if (bUnicodeDest) {
  1119. lstrcpyW ((LPWSTR)szDestElem, szSource);
  1120. szDestElem = (LPVOID)((LPWSTR)szDestElem + lstrlenW(szSource) + 1);
  1121. *((LPWSTR)szDestElem) = L'\0';
  1122. dwReturnLength = (DWORD)((LPWSTR)szDestElem - (LPWSTR)mszDest);
  1123. } else {
  1124. lstrcpyA ((LPSTR)szDestElem, aszSource);
  1125. szDestElem = (LPVOID)((LPSTR)szDestElem + lstrlenA(szDestElem) + 1);
  1126. *((LPSTR)szDestElem) = '\0'; // add second NULL
  1127. dwReturnLength = (DWORD)((LPSTR)szDestElem - (LPSTR)mszDest);
  1128. }
  1129. }
  1130. AddString_Bailout:
  1131. if (aszSource != NULL) {
  1132. G_FREE (aszSource);
  1133. }
  1134. return (DWORD)dwReturnLength;
  1135. }
  1136. DWORD
  1137. AddUniqueStringToMultiSz (
  1138. IN LPVOID mszDest,
  1139. IN LPSTR szSource,
  1140. IN BOOL bUnicodeDest
  1141. )
  1142. /*++
  1143. Routine Description:
  1144. searches the Multi-SZ list, mszDest for szSource and appends it
  1145. to mszDest if it wasn't found
  1146. Arguments:
  1147. OUT LPVOID mszDest Multi-SZ list to get new string
  1148. IN LPSTR szSource string to add if it's not already in list
  1149. ReturnValue:
  1150. The new length of the destination string including both
  1151. trailing NULL characters if the string was added, or 0 if the
  1152. string is already in the list.
  1153. --*/
  1154. {
  1155. LPVOID szDestElem;
  1156. DWORD dwReturnLength;
  1157. LPWSTR wszSource = NULL;
  1158. DWORD dwLength;
  1159. // check arguments
  1160. if ((mszDest == NULL) || (szSource == NULL)) return 0; // invalid buffers
  1161. if (*szSource == '\0') return 0; // no source string to add
  1162. // if unicode list, make a unicode copy of the source string to compare
  1163. // and ultimately copy if it's not already in the list
  1164. if (bUnicodeDest) {
  1165. dwLength = lstrlenA(szSource);
  1166. wszSource = G_ALLOC ((dwLength + 1) * sizeof(WCHAR));
  1167. if (wszSource != NULL) {
  1168. dwReturnLength = MultiByteToWideChar(
  1169. _getmbcp(),
  1170. 0,
  1171. szSource,
  1172. dwLength,
  1173. (LPWSTR) wszSource,
  1174. dwLength + 1);
  1175. } else {
  1176. // unable to allocate memory for the temp string
  1177. dwReturnLength = 0;
  1178. }
  1179. } else {
  1180. // just use the ANSI version of the source file name
  1181. dwReturnLength = 1;
  1182. }
  1183. if (dwReturnLength > 0) {
  1184. // go to end of dest string
  1185. //
  1186. for (szDestElem = mszDest;
  1187. (bUnicodeDest ? (*(LPWSTR)szDestElem != 0) :
  1188. (*(LPSTR)szDestElem != 0));
  1189. ) {
  1190. if (bUnicodeDest) {
  1191. // bail out if string already in lsit
  1192. if (lstrcmpiW((LPCWSTR)szDestElem, wszSource) == 0) {
  1193. dwReturnLength = 0;
  1194. goto AddString_Bailout;
  1195. } else {
  1196. // goto the next item
  1197. szDestElem = (LPVOID)((LPWSTR)szDestElem +
  1198. (lstrlenW((LPCWSTR)szDestElem)+1));
  1199. }
  1200. } else {
  1201. // bail out if string already in list
  1202. if (lstrcmpiA((LPSTR)szDestElem, szSource) == 0) {
  1203. dwReturnLength = 0;
  1204. goto AddString_Bailout;
  1205. } else {
  1206. // goto the next item
  1207. szDestElem = (LPVOID)((LPSTR)szDestElem +
  1208. (lstrlenA((LPCSTR)szDestElem)+1));
  1209. }
  1210. }
  1211. }
  1212. // if here, then add string
  1213. // szDestElem is at end of list
  1214. if (bUnicodeDest) {
  1215. lstrcpyW ((LPWSTR)szDestElem, wszSource);
  1216. szDestElem = (LPVOID)((LPWSTR)szDestElem + lstrlenW(wszSource) + 1);
  1217. *((LPWSTR)szDestElem) = L'\0';
  1218. dwReturnLength = (DWORD)((LPWSTR)szDestElem - (LPWSTR)mszDest);
  1219. } else {
  1220. lstrcpyA ((LPSTR)szDestElem, szSource);
  1221. szDestElem = (LPVOID)((LPSTR)szDestElem + lstrlenA(szDestElem) + 1);
  1222. *((LPSTR)szDestElem) = '\0'; // add second NULL
  1223. dwReturnLength = (DWORD)((LPSTR)szDestElem - (LPSTR)mszDest);
  1224. }
  1225. }
  1226. AddString_Bailout:
  1227. if (wszSource != NULL) {
  1228. G_FREE (wszSource);
  1229. }
  1230. return (DWORD) dwReturnLength;
  1231. }
  1232. //
  1233. // Exported Logging Functions
  1234. //
  1235. PDH_FUNCTION
  1236. PdhOpenLogW (
  1237. IN LPCWSTR szLogFileName,
  1238. IN DWORD dwAccessFlags,
  1239. IN LPDWORD lpdwLogType,
  1240. IN HQUERY hQuery,
  1241. IN DWORD dwMaxSize,
  1242. IN LPCWSTR szUserCaption,
  1243. IN HLOG *phLog
  1244. )
  1245. {
  1246. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1247. DWORD dwLocalLogType = 0;
  1248. PPDHI_LOG pLog;
  1249. WCHAR wcType[VALUE_BUFFER_SIZE];
  1250. if ((szLogFileName == NULL) ||
  1251. (lpdwLogType == NULL) ||
  1252. (phLog == NULL)) {
  1253. pdhStatus = PDH_INVALID_ARGUMENT;
  1254. } else {
  1255. __try {
  1256. if (*szLogFileName == 0) {
  1257. pdhStatus = PDH_INVALID_ARGUMENT;
  1258. }
  1259. dwLocalLogType = *lpdwLogType;
  1260. * lpdwLogType = dwLocalLogType;
  1261. if (szUserCaption != NULL) {
  1262. // if not NULL, it must be valid
  1263. if (*szUserCaption == 0) {
  1264. pdhStatus = PDH_INVALID_ARGUMENT;
  1265. }
  1266. } else {
  1267. // NULL is a valid argument
  1268. }
  1269. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1270. // something failed so give up here
  1271. pdhStatus = PDH_INVALID_ARGUMENT;
  1272. }
  1273. }
  1274. if (pdhStatus == ERROR_SUCCESS) {
  1275. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (hPdhDataMutex);
  1276. if (pdhStatus == ERROR_SUCCESS) {
  1277. // create a log entry
  1278. // if successful, this also acquires the lock for this structure
  1279. pdhStatus = CreateNewLogEntry (
  1280. (LPCWSTR)szLogFileName,
  1281. hQuery,
  1282. dwMaxSize,
  1283. &pLog);
  1284. // Here we must check for SQL: in the file name, and branch off to do SQL
  1285. // Processing /end SJM/
  1286. // open the file
  1287. if (pdhStatus == ERROR_SUCCESS) {
  1288. // find out if SQL file type
  1289. ZeroMemory((LPWSTR) wcType, sizeof(WCHAR) * VALUE_BUFFER_SIZE);
  1290. lstrcpynW((LPWSTR) wcType,
  1291. (LPWSTR) szLogFileName,
  1292. lstrlenW(cszSQL) + 1);
  1293. if (lstrcmpiW((LPWSTR)wcType, (LPWSTR) cszSQL) == 0) {
  1294. dwLocalLogType = PDH_LOG_TYPE_SQL;
  1295. pLog->llMaxSize = (LONGLONG) ((ULONGLONG) dwMaxSize);
  1296. pdhStatus = OpenSQLLog(pLog, dwAccessFlags, &dwLocalLogType);
  1297. if ((dwAccessFlags & PDH_LOG_WRITE_ACCESS) == PDH_LOG_WRITE_ACCESS) {
  1298. pLog->pQuery->hOutLog = (HLOG) pLog;
  1299. if (pdhStatus == ERROR_SUCCESS) {
  1300. pdhStatus = WriteLogHeader (pLog, (LPCWSTR)szUserCaption);
  1301. }
  1302. }
  1303. // dispatch based on read/write attribute
  1304. } else if ((dwAccessFlags & PDH_LOG_READ_ACCESS) ==
  1305. PDH_LOG_READ_ACCESS) {
  1306. pdhStatus = OpenInputLogFile (pLog,
  1307. dwAccessFlags, &dwLocalLogType);
  1308. } else if ((dwAccessFlags & PDH_LOG_WRITE_ACCESS) ==
  1309. PDH_LOG_WRITE_ACCESS) {
  1310. pdhStatus = OpenOutputLogFile (pLog,
  1311. dwAccessFlags,
  1312. &dwLocalLogType);
  1313. if (pdhStatus == ERROR_SUCCESS) {
  1314. pLog->pQuery->hOutLog = (HLOG) pLog;
  1315. pdhStatus = WriteLogHeader (pLog,
  1316. (LPCWSTR)szUserCaption);
  1317. }
  1318. } else if ((dwAccessFlags & PDH_LOG_UPDATE_ACCESS) ==
  1319. PDH_LOG_UPDATE_ACCESS) {
  1320. pdhStatus = OpenUpdateLogFile (pLog,
  1321. dwAccessFlags, &dwLocalLogType);
  1322. } else {
  1323. pdhStatus = PDH_INVALID_ARGUMENT;
  1324. }
  1325. if (pdhStatus == ERROR_SUCCESS) {
  1326. __try {
  1327. // return handle to caller
  1328. *phLog = (HLOG)pLog;
  1329. *lpdwLogType = dwLocalLogType;
  1330. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1331. // something failed so give up here
  1332. pdhStatus = PDH_INVALID_ARGUMENT;
  1333. }
  1334. }
  1335. // release the lock for the next thread
  1336. if (pdhStatus != ERROR_SUCCESS) {
  1337. // unable to complete this operation so toss this entry
  1338. // since it isn't really a valid log entry.
  1339. // NOTE: DeleteLogEntry will release the mutex
  1340. DeleteLogEntry (pLog);
  1341. }
  1342. else {
  1343. RELEASE_MUTEX (pLog->hLogMutex);
  1344. }
  1345. }
  1346. RELEASE_MUTEX (hPdhDataMutex);
  1347. } else {
  1348. // unable to lock global data structures
  1349. }
  1350. }
  1351. return pdhStatus;
  1352. }
  1353. PDH_FUNCTION
  1354. PdhOpenLogA (
  1355. IN LPCSTR szLogFileName,
  1356. IN DWORD dwAccessFlags,
  1357. IN LPDWORD lpdwLogType,
  1358. IN HQUERY hQuery,
  1359. IN DWORD dwMaxRecords,
  1360. IN LPCSTR szUserCaption,
  1361. IN HLOG *phLog
  1362. )
  1363. {
  1364. LPWSTR wszLogName = NULL;
  1365. LPWSTR wszUserCaption = NULL;
  1366. DWORD dwSize;
  1367. DWORD dwLocalLogType;
  1368. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1369. if ((szLogFileName == NULL) ||
  1370. (lpdwLogType == NULL) ||
  1371. (phLog == NULL)) {
  1372. pdhStatus = PDH_INVALID_ARGUMENT;
  1373. } else {
  1374. __try {
  1375. if (*szLogFileName == 0) {
  1376. pdhStatus = PDH_INVALID_ARGUMENT;
  1377. }
  1378. dwLocalLogType = *lpdwLogType; // test read
  1379. * lpdwLogType = dwLocalLogType;
  1380. if (szUserCaption != NULL) {
  1381. // if not NULL, it must be valid
  1382. if (*szUserCaption == 0) {
  1383. pdhStatus = PDH_INVALID_ARGUMENT;
  1384. }
  1385. } else {
  1386. // NULL is a valid argument
  1387. }
  1388. if (pdhStatus == ERROR_SUCCESS) {
  1389. // copy ANSI names to Wide Character strings
  1390. dwSize = lstrlenA (szLogFileName);
  1391. wszLogName = (LPWSTR)G_ALLOC ((dwSize + 1) * sizeof(WCHAR));
  1392. if (wszLogName != NULL) {
  1393. MultiByteToWideChar(_getmbcp(),
  1394. 0,
  1395. szLogFileName,
  1396. dwSize,
  1397. (LPWSTR) wszLogName,
  1398. dwSize + 1);
  1399. }
  1400. if (szUserCaption != NULL) {
  1401. dwSize = lstrlenA (szUserCaption);
  1402. wszUserCaption = (LPWSTR)G_ALLOC ((dwSize + 1) * sizeof(WCHAR));
  1403. if (wszUserCaption != NULL) {
  1404. MultiByteToWideChar(_getmbcp(),
  1405. 0,
  1406. szUserCaption,
  1407. dwSize,
  1408. (LPWSTR) wszUserCaption,
  1409. dwSize + 1);
  1410. }
  1411. }
  1412. }
  1413. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1414. // assume a bad parameter caused the exception
  1415. pdhStatus = PDH_INVALID_ARGUMENT;
  1416. }
  1417. }
  1418. if (pdhStatus == ERROR_SUCCESS) {
  1419. pdhStatus = PdhOpenLogW (
  1420. wszLogName,
  1421. dwAccessFlags,
  1422. &dwLocalLogType,
  1423. hQuery,
  1424. dwMaxRecords,
  1425. wszUserCaption,
  1426. phLog);
  1427. __try {
  1428. // return handle to caller
  1429. *lpdwLogType = dwLocalLogType;
  1430. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1431. // something failed so give up here
  1432. pdhStatus = PDH_INVALID_ARGUMENT;
  1433. }
  1434. }
  1435. if (wszLogName != NULL) {
  1436. G_FREE (wszLogName);
  1437. }
  1438. if (wszUserCaption != NULL) {
  1439. G_FREE (wszUserCaption);
  1440. }
  1441. return pdhStatus;
  1442. }
  1443. PDH_FUNCTION
  1444. PdhUpdateLogW (
  1445. IN HLOG hLog,
  1446. IN LPCWSTR szUserString
  1447. )
  1448. {
  1449. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1450. SYSTEMTIME st;
  1451. FILETIME ft;
  1452. PPDHI_LOG pLog;
  1453. if (szUserString != NULL) {
  1454. __try {
  1455. if (*szUserString == 0) {
  1456. pdhStatus = PDH_INVALID_ARGUMENT;
  1457. }
  1458. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1459. pdhStatus = PDH_INVALID_ARGUMENT;
  1460. }
  1461. } else {
  1462. //NULL is ok
  1463. }
  1464. if (pdhStatus == ERROR_SUCCESS) {
  1465. if (IsValidLogHandle (hLog)) {
  1466. pLog = (PPDHI_LOG)hLog;
  1467. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
  1468. if (pdhStatus == ERROR_SUCCESS) {
  1469. // make sure it's still valid as it could have
  1470. // been deleted while we were waiting
  1471. if (IsValidLogHandle (hLog)) {
  1472. if (pLog->pQuery == NULL) {
  1473. pdhStatus = PDH_INVALID_ARGUMENT;
  1474. }
  1475. else {
  1476. // get the timestamp and update the log's query,
  1477. // then write the data to the log file in the
  1478. // appropriate format
  1479. // update data samples
  1480. pdhStatus = PdhiCollectQueryData(
  1481. (HQUERY) pLog->pQuery, (LONGLONG *) & ft);
  1482. if (pdhStatus == ERROR_SUCCESS) {
  1483. FILETIME LocFileTime;
  1484. if (DataSourceTypeH(pLog->pQuery->hLog)
  1485. == DATA_SOURCE_REGISTRY) {
  1486. FileTimeToLocalFileTime(& ft, & LocFileTime);
  1487. }
  1488. else {
  1489. LocFileTime = ft;
  1490. }
  1491. FileTimeToSystemTime(& LocFileTime, & st);
  1492. }
  1493. else {
  1494. GetLocalTime(& st);
  1495. }
  1496. // test for end of log file in case the caller is
  1497. // reading from a log file. If this value is returned,
  1498. // then don't update the output log file any more.
  1499. if (pdhStatus != PDH_NO_MORE_DATA) {
  1500. switch (LOWORD(pLog->dwLogFormat)) {
  1501. case PDH_LOG_TYPE_CSV:
  1502. case PDH_LOG_TYPE_TSV:
  1503. pdhStatus =PdhiWriteTextLogRecord (
  1504. pLog,
  1505. &st,
  1506. (LPCWSTR)szUserString);
  1507. break;
  1508. case PDH_LOG_TYPE_RETIRED_BIN:
  1509. pdhStatus =PdhiWriteBinaryLogRecord (
  1510. pLog,
  1511. &st,
  1512. (LPCWSTR)szUserString);
  1513. break;
  1514. case PDH_LOG_TYPE_BINARY:
  1515. pdhStatus = PdhiWriteWmiLogRecord(
  1516. pLog,
  1517. &st,
  1518. (LPCWSTR) szUserString);
  1519. break;
  1520. // add case for SQL
  1521. case PDH_LOG_TYPE_SQL:
  1522. pdhStatus =PdhiWriteSQLLogRecord (
  1523. pLog,
  1524. &st,
  1525. (LPCWSTR)szUserString);
  1526. break;
  1527. case PDH_LOG_TYPE_PERFMON:
  1528. default:
  1529. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  1530. break;
  1531. }
  1532. } else {
  1533. // return the NO_MORE_DATA error to the caller
  1534. // so they know not to call this function any more
  1535. }
  1536. }
  1537. } else {
  1538. pdhStatus = PDH_INVALID_HANDLE;
  1539. }
  1540. RELEASE_MUTEX (pLog->hLogMutex);
  1541. } // else couldn't lock the log
  1542. } else {
  1543. pdhStatus = PDH_INVALID_HANDLE;
  1544. }
  1545. }
  1546. return pdhStatus;
  1547. }
  1548. PDH_FUNCTION
  1549. PdhUpdateLogA (
  1550. IN HLOG hLog,
  1551. IN LPCSTR szUserString
  1552. )
  1553. {
  1554. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1555. LPWSTR wszLocalUserString = NULL;
  1556. DWORD dwUserStringLen;
  1557. __try {
  1558. if (szUserString != NULL) {
  1559. if (*szUserString == 0) {
  1560. pdhStatus = PDH_INVALID_ARGUMENT;
  1561. }
  1562. } else {
  1563. //NULL is ok
  1564. }
  1565. if (pdhStatus == ERROR_SUCCESS) {
  1566. if (szUserString != NULL) {
  1567. dwUserStringLen = lstrlenA(szUserString);
  1568. wszLocalUserString = (LPWSTR)G_ALLOC (
  1569. (dwUserStringLen + 1) * sizeof (WCHAR));
  1570. if (wszLocalUserString != NULL) {
  1571. MultiByteToWideChar(_getmbcp(),
  1572. 0,
  1573. szUserString,
  1574. dwUserStringLen,
  1575. (LPWSTR) wszLocalUserString,
  1576. dwUserStringLen + 1);
  1577. } else {
  1578. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  1579. }
  1580. } // else continue with NULL pointer
  1581. }
  1582. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1583. pdhStatus = PDH_INVALID_ARGUMENT;
  1584. }
  1585. if (pdhStatus == ERROR_SUCCESS) {
  1586. pdhStatus = PdhUpdateLogW (hLog, wszLocalUserString);
  1587. }
  1588. if (wszLocalUserString != NULL) {
  1589. G_FREE (wszLocalUserString);
  1590. }
  1591. return pdhStatus;
  1592. }
  1593. PDH_FUNCTION
  1594. PdhUpdateLogFileCatalog (
  1595. IN HLOG hLog
  1596. )
  1597. {
  1598. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1599. PPDHI_LOG pLog;
  1600. if (IsValidLogHandle (hLog)) {
  1601. pLog = (PPDHI_LOG)hLog;
  1602. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
  1603. // make sure it's still valid as it could have
  1604. // been deleted while we were waiting
  1605. if (pdhStatus == ERROR_SUCCESS) {
  1606. if (IsValidLogHandle (hLog)) {
  1607. pLog = (PPDHI_LOG)hLog;
  1608. switch (LOWORD(pLog->dwLogFormat)) {
  1609. case PDH_LOG_TYPE_CSV:
  1610. case PDH_LOG_TYPE_TSV:
  1611. case PDH_LOG_TYPE_BINARY:
  1612. case PDH_LOG_TYPE_SQL:
  1613. pdhStatus = PDH_NOT_IMPLEMENTED;
  1614. break;
  1615. case PDH_LOG_TYPE_RETIRED_BIN:
  1616. pdhStatus = PdhiUpdateBinaryLogFileCatalog (pLog);
  1617. break;
  1618. case PDH_LOG_TYPE_PERFMON:
  1619. default:
  1620. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  1621. break;
  1622. }
  1623. } else {
  1624. pdhStatus = PDH_INVALID_HANDLE;
  1625. }
  1626. RELEASE_MUTEX (pLog->hLogMutex);
  1627. }
  1628. } else {
  1629. pdhStatus = PDH_INVALID_HANDLE;
  1630. }
  1631. return pdhStatus;
  1632. }
  1633. PDH_FUNCTION
  1634. PdhCloseLog(
  1635. IN HLOG hLog,
  1636. IN DWORD dwFlags
  1637. )
  1638. {
  1639. PDH_STATUS pdhStatus;
  1640. PPDHI_LOG pLog;
  1641. if (hLog == H_REALTIME_DATASOURCE || hLog == H_WBEM_DATASOURCE) {
  1642. // return immediately if datasource is realtime or wbem
  1643. //
  1644. return ERROR_SUCCESS;
  1645. }
  1646. if (IsValidLogHandle (hLog)) {
  1647. pLog = (PPDHI_LOG)hLog;
  1648. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
  1649. if (pdhStatus == ERROR_SUCCESS) {
  1650. // make sure it's still valid as it could have
  1651. // been deleted while we were waiting
  1652. if (IsValidLogHandle (hLog)) {
  1653. // this will release and delete the mutex
  1654. pdhStatus = CloseAndDeleteLogEntry (pLog, dwFlags, FALSE);
  1655. } else {
  1656. pdhStatus = PDH_INVALID_HANDLE;
  1657. }
  1658. }
  1659. } else {
  1660. pdhStatus = PDH_INVALID_HANDLE;
  1661. }
  1662. return pdhStatus;
  1663. }
  1664. BOOL
  1665. PdhiBrowseDataSource (
  1666. IN HWND hWndParent,
  1667. IN LPVOID szFileName,
  1668. IN LPDWORD pcchFileNameSize,
  1669. IN BOOL bUnicodeString
  1670. )
  1671. {
  1672. OPENFILENAMEW ofn;
  1673. LPWSTR szTempString = NULL;
  1674. LPWSTR szDirString = NULL;
  1675. LPWSTR szTempFileName = NULL;
  1676. BOOL bReturn;
  1677. LPWSTR szMsg;
  1678. WCHAR szLogFilterString[512];
  1679. LPWSTR szLogFilter;
  1680. if (szFileName == NULL) {
  1681. SetLastError(PDH_INVALID_ARGUMENT);
  1682. return FALSE;
  1683. }
  1684. // clear last error
  1685. SetLastError (ERROR_SUCCESS);
  1686. szTempString = G_ALLOC (* pcchFileNameSize * sizeof(WCHAR) * 2);
  1687. if (szTempString == NULL) {
  1688. SetLastError (PDH_MEMORY_ALLOCATION_FAILURE);
  1689. bReturn = FALSE;
  1690. } else {
  1691. ZeroMemory(szTempString, * pcchFileNameSize * sizeof(WCHAR) * 2);
  1692. szDirString = (LPWSTR)((LPBYTE)szTempString + (*pcchFileNameSize * sizeof(WCHAR)));
  1693. // continue
  1694. // get the current filename
  1695. if (bUnicodeString) {
  1696. lstrcpyW (szTempString, (LPWSTR)szFileName);
  1697. } else {
  1698. MultiByteToWideChar(_getmbcp(),
  1699. 0,
  1700. (LPSTR) szFileName,
  1701. lstrlenA((LPSTR) szFileName),
  1702. (LPWSTR) szTempString,
  1703. lstrlenA((LPSTR) szFileName) + 1);
  1704. }
  1705. // set the path up for the initial dir display
  1706. if (szTempString[0] != L'\0') {
  1707. if (SearchPathW(NULL, szTempString, NULL,
  1708. *pcchFileNameSize, szDirString, &szTempFileName) > 0) {
  1709. // then update the buffers to show file and dir path
  1710. if (szTempFileName > szDirString) {
  1711. // then we have a path with a file name so
  1712. // truncate the path at the last backslash and
  1713. // then copy the filename to the original buffer
  1714. *(szTempFileName-1) = 0;
  1715. lstrcpyW (szTempString, szTempFileName);
  1716. } else {
  1717. // no file name found so leave things as is
  1718. }
  1719. } else {
  1720. // unable to search path so leave things alone
  1721. }
  1722. }
  1723. // get the log filter string
  1724. if (MakeLogFilterInfoString (
  1725. szLogFilterString,
  1726. (sizeof(szLogFilterString)/sizeof(szLogFilterString[0]))) == ERROR_SUCCESS) {
  1727. szLogFilter = szLogFilterString;
  1728. } else {
  1729. // then use default filter string
  1730. szLogFilter = NULL;
  1731. }
  1732. // display file open dialog to browse for log files.
  1733. szMsg = GetStringResource (IDS_DSRC_SELECT);
  1734. ofn.lStructSize = sizeof (ofn);
  1735. ofn.hwndOwner = hWndParent;
  1736. ofn.hInstance = ThisDLLHandle;
  1737. ofn.lpstrFilter = szLogFilter;
  1738. ofn.lpstrCustomFilter = NULL;
  1739. ofn.nMaxCustFilter = 0;
  1740. ofn.nFilterIndex = 1;
  1741. ofn.lpstrFile = szTempString;
  1742. ofn.nMaxFile = SMALL_BUFFER_SIZE -1;
  1743. ofn.lpstrFileTitle = NULL;
  1744. ofn.nMaxFileTitle = 0;
  1745. ofn.lpstrInitialDir = szDirString;
  1746. ofn.lpstrTitle = szMsg;
  1747. ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY |
  1748. OFN_PATHMUSTEXIST;
  1749. ofn.nFileOffset = 0;
  1750. ofn.nFileExtension = 0;
  1751. ofn.lpstrDefExt = cszBlg;
  1752. ofn.lCustData = 0;
  1753. ofn.lpfnHook = NULL;
  1754. ofn.lpTemplateName = NULL;
  1755. if (GetOpenFileNameW (&ofn)) {
  1756. // then update the return string
  1757. if (bUnicodeString) {
  1758. lstrcpyW ((LPWSTR)szFileName, szTempString);
  1759. * pcchFileNameSize = lstrlenW(szTempString) + 1;
  1760. } else {
  1761. PdhiConvertUnicodeToAnsi(_getmbcp(),
  1762. szTempString, (LPSTR) szFileName, pcchFileNameSize);
  1763. }
  1764. bReturn = TRUE;
  1765. } else {
  1766. bReturn = FALSE;
  1767. }
  1768. if (szMsg) G_FREE (szMsg);
  1769. }
  1770. if (szTempString != NULL) G_FREE (szTempString);
  1771. return bReturn;
  1772. }
  1773. PDH_FUNCTION
  1774. PdhGetDataSourceTimeRangeH (
  1775. IN HLOG hDataSource,
  1776. IN LPDWORD pdwNumEntries,
  1777. IN PPDH_TIME_INFO pInfo,
  1778. IN LPDWORD pdwBufferSize
  1779. )
  1780. {
  1781. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1782. DWORD dwLocalBufferSize = 0;
  1783. DWORD dwLocalNumEntries = 0;
  1784. PDH_TIME_INFO LocalInfo;
  1785. PPDHI_LOG pLog;
  1786. // TODO postW2k1: Capture pInfo. Most routines should be in try
  1787. if (hDataSource == H_REALTIME_DATASOURCE) {
  1788. pdhStatus = PDH_DATA_SOURCE_IS_REAL_TIME;
  1789. }
  1790. else if ((pdwNumEntries == NULL) || (pInfo == NULL)
  1791. || (pdwBufferSize == NULL)) {
  1792. pdhStatus = PDH_INVALID_ARGUMENT;
  1793. }
  1794. else {
  1795. // test caller's buffers before trying to use them
  1796. __try {
  1797. dwLocalNumEntries = * pdwNumEntries;
  1798. dwLocalBufferSize = * pdwBufferSize;
  1799. LocalInfo.StartTime = pInfo->StartTime;
  1800. }
  1801. __except (EXCEPTION_EXECUTE_HANDLER) {
  1802. pdhStatus = PDH_INVALID_ARGUMENT;
  1803. }
  1804. }
  1805. if (pdhStatus == ERROR_SUCCESS) {
  1806. if (IsValidLogHandle(hDataSource)) {
  1807. pLog = (PPDHI_LOG) hDataSource;
  1808. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX(pLog->hLogMutex);
  1809. if (pdhStatus == ERROR_SUCCESS) {
  1810. if (IsValidLogHandle(hDataSource)) {
  1811. // enum machines based on log type
  1812. //
  1813. switch (LOWORD(pLog->dwLogFormat)) {
  1814. case PDH_LOG_TYPE_CSV:
  1815. case PDH_LOG_TYPE_TSV:
  1816. pdhStatus = PdhiGetTimeRangeFromTextLog(
  1817. pLog,
  1818. & dwLocalNumEntries,
  1819. & LocalInfo,
  1820. & dwLocalBufferSize);
  1821. break;
  1822. case PDH_LOG_TYPE_BINARY:
  1823. pdhStatus = PdhiGetTimeRangeFromWmiLog(
  1824. pLog,
  1825. & dwLocalNumEntries,
  1826. & LocalInfo,
  1827. & dwLocalBufferSize);
  1828. break;
  1829. case PDH_LOG_TYPE_RETIRED_BIN:
  1830. pdhStatus = PdhiGetTimeRangeFromBinaryLog(
  1831. pLog,
  1832. & dwLocalNumEntries,
  1833. & LocalInfo,
  1834. & dwLocalBufferSize);
  1835. break;
  1836. case PDH_LOG_TYPE_SQL:
  1837. pdhStatus = PdhiGetTimeRangeFromSQLLog(
  1838. pLog,
  1839. & dwLocalNumEntries,
  1840. & LocalInfo,
  1841. & dwLocalBufferSize);
  1842. break;
  1843. case PDH_LOG_TYPE_PERFMON:
  1844. pdhStatus = PdhiGetTimeRangeFromPerfmonLog(
  1845. pLog,
  1846. & dwLocalNumEntries,
  1847. & LocalInfo,
  1848. & dwLocalBufferSize);
  1849. break;
  1850. default:
  1851. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  1852. break;
  1853. }
  1854. __try {
  1855. * pdwBufferSize = dwLocalBufferSize;
  1856. * pdwNumEntries = dwLocalNumEntries;
  1857. pInfo->StartTime = LocalInfo.StartTime;
  1858. pInfo->EndTime = LocalInfo.EndTime;
  1859. pInfo->SampleCount = LocalInfo.SampleCount;
  1860. }
  1861. __except (EXCEPTION_EXECUTE_HANDLER) {
  1862. pdhStatus = PDH_INVALID_ARGUMENT;
  1863. }
  1864. }
  1865. else {
  1866. pdhStatus = PDH_INVALID_HANDLE;
  1867. }
  1868. RELEASE_MUTEX (pLog->hLogMutex);
  1869. }
  1870. }
  1871. else {
  1872. pdhStatus = PDH_INVALID_HANDLE;
  1873. }
  1874. }
  1875. return pdhStatus;
  1876. }
  1877. PDH_FUNCTION
  1878. PdhGetDataSourceTimeRangeW (
  1879. IN LPCWSTR szDataSource,
  1880. IN LPDWORD pdwNumEntries,
  1881. IN PPDH_TIME_INFO pInfo,
  1882. IN LPDWORD pdwBufferSize
  1883. )
  1884. {
  1885. PDH_STATUS PdhStatus = PDH_DATA_SOURCE_IS_REAL_TIME;
  1886. HLOG hDataSource = NULL;
  1887. DWORD dwLogType = -1;
  1888. if (szDataSource != NULL) {
  1889. // open log file
  1890. //
  1891. PdhStatus = PdhOpenLogW (
  1892. szDataSource,
  1893. PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
  1894. & dwLogType,
  1895. NULL,
  1896. 0,
  1897. NULL,
  1898. & hDataSource);
  1899. if (PdhStatus == ERROR_SUCCESS) {
  1900. PdhStatus = PdhGetDataSourceTimeRangeH(
  1901. hDataSource,
  1902. pdwNumEntries,
  1903. pInfo,
  1904. pdwBufferSize);
  1905. PdhCloseLog(hDataSource, 0);
  1906. }
  1907. }
  1908. return PdhStatus;
  1909. }
  1910. PDH_FUNCTION
  1911. PdhGetDataSourceTimeRangeA (
  1912. IN LPCSTR szDataSource,
  1913. IN LPDWORD pdwNumEntries,
  1914. IN PPDH_TIME_INFO pInfo,
  1915. IN LPDWORD pdwBufferSize
  1916. )
  1917. {
  1918. LPWSTR wszDataSource = NULL;
  1919. DWORD dwSize;
  1920. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1921. DWORD dwLocalBufferSize = 0;
  1922. DWORD dwLocalNumEntries = 0;
  1923. // TODO postW2k1: Capture pInfo. Most routines should be in try
  1924. if (szDataSource == NULL) {
  1925. // null data source == the current activity so return
  1926. pdhStatus = PDH_DATA_SOURCE_IS_REAL_TIME;
  1927. } else if ((pdwNumEntries == NULL) ||
  1928. (pInfo == NULL) ||
  1929. (pdwBufferSize == NULL)) {
  1930. pdhStatus = PDH_INVALID_ARGUMENT;
  1931. } else {
  1932. __try {
  1933. dwLocalBufferSize = *pdwBufferSize;
  1934. dwLocalNumEntries = *pdwNumEntries;
  1935. dwSize = lstrlenA(szDataSource);
  1936. wszDataSource = G_ALLOC ((dwSize + 1) * sizeof(WCHAR));
  1937. if (wszDataSource == NULL) {
  1938. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  1939. } else {
  1940. MultiByteToWideChar(_getmbcp(),
  1941. 0,
  1942. szDataSource,
  1943. dwSize,
  1944. (LPWSTR) wszDataSource,
  1945. dwSize + 1);
  1946. }
  1947. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1948. // assume a bad parameter caused the exception
  1949. pdhStatus = PDH_INVALID_ARGUMENT;
  1950. }
  1951. }
  1952. if (pdhStatus == ERROR_SUCCESS) {
  1953. pdhStatus = PdhGetDataSourceTimeRangeW (
  1954. wszDataSource,
  1955. &dwLocalNumEntries,
  1956. pInfo,
  1957. &dwLocalBufferSize);
  1958. // copy returned values regardless of status
  1959. __try {
  1960. *pdwBufferSize = dwLocalBufferSize;
  1961. *pdwNumEntries = dwLocalNumEntries;
  1962. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1963. pdhStatus = PDH_INVALID_ARGUMENT;
  1964. }
  1965. }
  1966. if (wszDataSource != NULL) {
  1967. G_FREE (wszDataSource);
  1968. }
  1969. return pdhStatus;
  1970. }
  1971. PDH_FUNCTION
  1972. PdhGetLogFileSize (
  1973. IN HLOG hLog,
  1974. IN LONGLONG *llSize
  1975. )
  1976. {
  1977. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1978. PPDHI_LOG pLog;
  1979. UINT nErrorMode;
  1980. DWORD dwFileSizeLow = 0;
  1981. DWORD dwFileSizeHigh = 0;
  1982. LONGLONG llFileLength;
  1983. DWORD dwError;
  1984. if (llSize == NULL) {
  1985. pdhStatus = PDH_INVALID_ARGUMENT;
  1986. } else {
  1987. if (IsValidLogHandle (hLog)) {
  1988. pLog = (PPDHI_LOG)hLog;
  1989. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
  1990. if (pdhStatus == ERROR_SUCCESS) {
  1991. if (IsValidLogHandle (hLog)) {
  1992. if (LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_SQL) {
  1993. __try {
  1994. * llSize = 0;
  1995. }
  1996. __except (EXCEPTION_EXECUTE_HANDLER) {
  1997. pdhStatus = PDH_INVALID_ARGUMENT;
  1998. }
  1999. }
  2000. else if (LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_BINARY) {
  2001. pdhStatus = PdhiGetWmiLogFileSize(pLog, llSize);
  2002. }
  2003. else {
  2004. // disable windows error message popup
  2005. nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  2006. if (pLog->hLogFileHandle != INVALID_HANDLE_VALUE) {
  2007. dwFileSizeLow = GetFileSize (pLog->hLogFileHandle, &dwFileSizeHigh);
  2008. // test for error
  2009. if ((dwFileSizeLow == 0xFFFFFFFF) &&
  2010. ((dwError = GetLastError()) != NO_ERROR)) {
  2011. // then we couldn't get the file size
  2012. pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
  2013. } else {
  2014. if (dwFileSizeHigh > 0) {
  2015. llFileLength = dwFileSizeHigh << (sizeof(DWORD) * 8);
  2016. } else {
  2017. llFileLength = 0;
  2018. }
  2019. llFileLength += dwFileSizeLow;
  2020. // write to the caller' buffer
  2021. __try {
  2022. *llSize = llFileLength;
  2023. }
  2024. __except (EXCEPTION_EXECUTE_HANDLER) {
  2025. pdhStatus = PDH_INVALID_ARGUMENT;
  2026. }
  2027. }
  2028. } else {
  2029. pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
  2030. }
  2031. SetErrorMode (nErrorMode); // restore old error mode
  2032. }
  2033. } else {
  2034. pdhStatus = PDH_INVALID_HANDLE;
  2035. }
  2036. RELEASE_MUTEX (pLog->hLogMutex);
  2037. }
  2038. } else {
  2039. pdhStatus = PDH_INVALID_HANDLE;
  2040. }
  2041. }
  2042. return pdhStatus;
  2043. }
  2044. PDH_FUNCTION
  2045. PdhReadRawLogRecord (
  2046. IN HLOG hLog,
  2047. IN FILETIME ftRecord,
  2048. IN PPDH_RAW_LOG_RECORD pBuffer,
  2049. IN LPDWORD pdwBufferLength
  2050. )
  2051. {
  2052. PPDHI_LOG pLog;
  2053. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  2054. DWORD dwLocalBufferLength = 0;
  2055. if (pdwBufferLength == NULL) {
  2056. pdhStatus = PDH_INVALID_ARGUMENT;
  2057. } else {
  2058. __try {
  2059. CHAR TestChar;
  2060. // test read & write access to the user's buffer.
  2061. dwLocalBufferLength = *pdwBufferLength;
  2062. if (dwLocalBufferLength > 0) {
  2063. // test beginnging and end of the buffer passed in
  2064. TestChar = ((CHAR *)pBuffer)[0];
  2065. ((CHAR *)pBuffer)[0] = 0;
  2066. ((CHAR *)pBuffer)[0] = TestChar;
  2067. TestChar = ((CHAR *)pBuffer)[dwLocalBufferLength -1];
  2068. ((CHAR *)pBuffer)[dwLocalBufferLength -1] = 0;
  2069. ((CHAR *)pBuffer)[dwLocalBufferLength -1] = TestChar;
  2070. } else {
  2071. // 0 length buffer is OK
  2072. }
  2073. } __except (EXCEPTION_EXECUTE_HANDLER) {
  2074. pdhStatus = PDH_INVALID_ARGUMENT;
  2075. }
  2076. }
  2077. if (!IsValidLogHandle (hLog)) {
  2078. pdhStatus = PDH_INVALID_HANDLE;
  2079. } else if (pdhStatus == ERROR_SUCCESS) {
  2080. pLog = (PPDHI_LOG)hLog;
  2081. // see if the log is open, first?
  2082. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
  2083. if (pdhStatus == ERROR_SUCCESS) {
  2084. // make sure it's still valid
  2085. if (IsValidLogHandle (hLog)) {
  2086. switch (LOWORD(pLog->dwLogFormat)) {
  2087. case PDH_LOG_TYPE_CSV:
  2088. case PDH_LOG_TYPE_TSV:
  2089. pdhStatus = PdhiReadRawTextLogRecord (
  2090. hLog,
  2091. &ftRecord,
  2092. pBuffer,
  2093. &dwLocalBufferLength);
  2094. break;
  2095. case PDH_LOG_TYPE_BINARY:
  2096. case PDH_LOG_TYPE_RETIRED_BIN:
  2097. pdhStatus = PdhiReadRawBinaryLogRecord (
  2098. hLog,
  2099. &ftRecord,
  2100. pBuffer,
  2101. &dwLocalBufferLength);
  2102. break;
  2103. case PDH_LOG_TYPE_SQL:
  2104. //note this is only supported with a null buffer
  2105. // as we don't actually read the record, and
  2106. // positioning the file at the record doesn't
  2107. // mean anything for SQL
  2108. pdhStatus = PdhiReadRawSQLLogRecord (
  2109. hLog,
  2110. &ftRecord,
  2111. pBuffer,
  2112. pdwBufferLength);
  2113. break;
  2114. case PDH_LOG_TYPE_PERFMON:
  2115. pdhStatus = PdhiReadRawPerfmonLogRecord (
  2116. hLog,
  2117. &ftRecord,
  2118. pBuffer,
  2119. &dwLocalBufferLength);
  2120. break;
  2121. default:
  2122. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  2123. break;
  2124. }
  2125. __try {
  2126. *pdwBufferLength = dwLocalBufferLength;
  2127. } __except (EXCEPTION_EXECUTE_HANDLER) {
  2128. pdhStatus = PDH_INVALID_ARGUMENT;
  2129. }
  2130. } else {
  2131. pdhStatus = PDH_INVALID_HANDLE;
  2132. }
  2133. RELEASE_MUTEX (pLog->hLogMutex);
  2134. }
  2135. } else {
  2136. // return pdhStatus
  2137. }
  2138. return pdhStatus;
  2139. }
  2140. PDH_FUNCTION
  2141. PdhiEnumLoggedMachines (
  2142. IN HLOG hDataSource,
  2143. IN LPVOID mszMachineList,
  2144. IN LPDWORD pcchBufferSize,
  2145. IN BOOL bUnicode
  2146. )
  2147. {
  2148. PDH_STATUS pdhStatus = PDH_INVALID_HANDLE;
  2149. PPDHI_LOG pDataSource;
  2150. DWORD dwLogType;
  2151. // enum machines based on log type
  2152. //
  2153. if (IsValidLogHandle(hDataSource)) {
  2154. pDataSource = (PPDHI_LOG) hDataSource;
  2155. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pDataSource->hLogMutex);
  2156. if (pdhStatus == ERROR_SUCCESS) {
  2157. if (IsValidLogHandle (hDataSource)) {
  2158. dwLogType = pDataSource->dwLogFormat;
  2159. switch (LOWORD(dwLogType)) {
  2160. case PDH_LOG_TYPE_CSV:
  2161. case PDH_LOG_TYPE_TSV:
  2162. pdhStatus = PdhiEnumMachinesFromTextLog (
  2163. (PPDHI_LOG) hDataSource,
  2164. mszMachineList,
  2165. pcchBufferSize,
  2166. bUnicode);
  2167. break;
  2168. case PDH_LOG_TYPE_BINARY:
  2169. case PDH_LOG_TYPE_RETIRED_BIN:
  2170. pdhStatus = PdhiEnumMachinesFromBinaryLog (
  2171. (PPDHI_LOG) hDataSource,
  2172. mszMachineList,
  2173. pcchBufferSize,
  2174. bUnicode);
  2175. break;
  2176. case PDH_LOG_TYPE_SQL:
  2177. pdhStatus = PdhiEnumMachinesFromSQLLog (
  2178. (PPDHI_LOG)hDataSource,
  2179. mszMachineList,
  2180. pcchBufferSize,
  2181. bUnicode);
  2182. break;
  2183. case PDH_LOG_TYPE_PERFMON:
  2184. pdhStatus = PdhiEnumMachinesFromPerfmonLog (
  2185. (PPDHI_LOG) hDataSource,
  2186. mszMachineList,
  2187. pcchBufferSize,
  2188. bUnicode);
  2189. break;
  2190. default:
  2191. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  2192. break;
  2193. }
  2194. }
  2195. else {
  2196. pdhStatus = PDH_INVALID_HANDLE;
  2197. }
  2198. RELEASE_MUTEX (pDataSource->hLogMutex);
  2199. }
  2200. }
  2201. return pdhStatus;
  2202. }
  2203. PDH_FUNCTION
  2204. PdhiEnumLoggedObjects (
  2205. IN HLOG hDataSource,
  2206. IN LPCWSTR szMachineName,
  2207. IN LPVOID mszObjectList,
  2208. IN LPDWORD pcchBufferSize,
  2209. IN DWORD dwDetailLevel,
  2210. IN BOOL bRefresh, // ignored by log files
  2211. IN BOOL bUnicode
  2212. )
  2213. {
  2214. PDH_STATUS pdhStatus = PDH_INVALID_HANDLE;
  2215. PPDHI_LOG pDataSource;
  2216. DWORD dwLogType;
  2217. UNREFERENCED_PARAMETER (bRefresh);
  2218. if (IsValidLogHandle(hDataSource)) {
  2219. pDataSource = (PPDHI_LOG)hDataSource;
  2220. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pDataSource->hLogMutex);
  2221. if (pdhStatus == ERROR_SUCCESS) {
  2222. if (IsValidLogHandle (hDataSource)) {
  2223. dwLogType = pDataSource->dwLogFormat;
  2224. // enum objects based on log type & machine name
  2225. switch (LOWORD(dwLogType)) {
  2226. case PDH_LOG_TYPE_CSV:
  2227. case PDH_LOG_TYPE_TSV:
  2228. pdhStatus = PdhiEnumObjectsFromTextLog (
  2229. (PPDHI_LOG)hDataSource,
  2230. szMachineName,
  2231. mszObjectList,
  2232. pcchBufferSize,
  2233. dwDetailLevel,
  2234. bUnicode);
  2235. break;
  2236. case PDH_LOG_TYPE_BINARY:
  2237. case PDH_LOG_TYPE_RETIRED_BIN:
  2238. pdhStatus = PdhiEnumObjectsFromBinaryLog (
  2239. (PPDHI_LOG)hDataSource,
  2240. szMachineName,
  2241. mszObjectList,
  2242. pcchBufferSize,
  2243. dwDetailLevel,
  2244. bUnicode);
  2245. break;
  2246. case PDH_LOG_TYPE_SQL:
  2247. pdhStatus = PdhiEnumObjectsFromSQLLog (
  2248. (PPDHI_LOG)hDataSource,
  2249. szMachineName,
  2250. mszObjectList,
  2251. pcchBufferSize,
  2252. dwDetailLevel,
  2253. bUnicode);
  2254. break;
  2255. case PDH_LOG_TYPE_PERFMON:
  2256. pdhStatus = PdhiEnumObjectsFromPerfmonLog (
  2257. (PPDHI_LOG)hDataSource,
  2258. szMachineName,
  2259. mszObjectList,
  2260. pcchBufferSize,
  2261. dwDetailLevel,
  2262. bUnicode);
  2263. break;
  2264. default:
  2265. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  2266. break;
  2267. }
  2268. }
  2269. else {
  2270. pdhStatus = PDH_INVALID_HANDLE;
  2271. }
  2272. RELEASE_MUTEX (pDataSource->hLogMutex);
  2273. }
  2274. }
  2275. else {
  2276. }
  2277. return pdhStatus;
  2278. }
  2279. PDH_FUNCTION
  2280. PdhiEnumLoggedObjectItems (
  2281. IN HLOG hDataSource,
  2282. IN LPCWSTR szMachineName,
  2283. IN LPCWSTR szObjectName,
  2284. IN LPVOID mszCounterList,
  2285. IN LPDWORD pdwCounterListLength,
  2286. IN LPVOID mszInstanceList,
  2287. IN LPDWORD pdwInstanceListLength,
  2288. IN DWORD dwDetailLevel,
  2289. IN DWORD dwFlags,
  2290. IN BOOL bUnicode
  2291. )
  2292. {
  2293. PDH_STATUS pdhStatus = PDH_INVALID_HANDLE;
  2294. PPDHI_LOG pDataSource;
  2295. DWORD dwLogType;
  2296. PDHI_COUNTER_TABLE CounterTable;
  2297. DWORD dwIndex;
  2298. LIST_ENTRY InstanceList;
  2299. PLIST_ENTRY pHeadInst;
  2300. PLIST_ENTRY pNextInst;
  2301. PPDHI_INSTANCE pInstance;
  2302. PPDHI_INST_LIST pInstList;
  2303. LPVOID TempBuffer = NULL;
  2304. DWORD dwNewBuffer = 0;
  2305. LPVOID LocalCounter = NULL;
  2306. DWORD LocalCounterSize = 0;
  2307. LPVOID LocalInstance = NULL;
  2308. DWORD LocalInstanceSize = 0;
  2309. DWORD dwCntrBufferUsed = 0;
  2310. DWORD dwInstBufferUsed = 0;
  2311. PdhiInitCounterHashTable(CounterTable);
  2312. InitializeListHead(& InstanceList);
  2313. LocalCounter = G_ALLOC(MEDIUM_BUFFER_SIZE);
  2314. LocalInstance = G_ALLOC(MEDIUM_BUFFER_SIZE);
  2315. if (LocalCounter == NULL || LocalInstance == NULL) {
  2316. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2317. goto Cleanup;
  2318. }
  2319. LocalCounterSize = LocalInstanceSize = MEDIUM_BUFFER_SIZE;
  2320. if (mszCounterList != NULL)
  2321. memset(mszCounterList, 0, * pdwCounterListLength);
  2322. if (mszInstanceList != NULL)
  2323. memset(mszInstanceList, 0, * pdwInstanceListLength);
  2324. if (IsValidLogHandle(hDataSource)) {
  2325. pDataSource = (PPDHI_LOG)hDataSource;
  2326. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pDataSource->hLogMutex);
  2327. if (pdhStatus == ERROR_SUCCESS) {
  2328. if (IsValidLogHandle (hDataSource)) {
  2329. dwLogType = pDataSource->dwLogFormat;
  2330. // enum objects based on log type & machine name
  2331. switch (LOWORD(dwLogType)) {
  2332. case PDH_LOG_TYPE_CSV:
  2333. case PDH_LOG_TYPE_TSV:
  2334. pdhStatus = PdhiEnumObjectItemsFromTextLog (
  2335. (PPDHI_LOG) hDataSource,
  2336. szMachineName,
  2337. szObjectName,
  2338. CounterTable,
  2339. dwDetailLevel,
  2340. dwFlags);
  2341. break;
  2342. case PDH_LOG_TYPE_BINARY:
  2343. pdhStatus = PdhiEnumObjectItemsFromWmiLog (
  2344. (PPDHI_LOG) hDataSource,
  2345. szMachineName,
  2346. szObjectName,
  2347. CounterTable,
  2348. dwDetailLevel,
  2349. dwFlags);
  2350. break;
  2351. case PDH_LOG_TYPE_RETIRED_BIN:
  2352. pdhStatus = PdhiEnumObjectItemsFromBinaryLog (
  2353. (PPDHI_LOG) hDataSource,
  2354. szMachineName,
  2355. szObjectName,
  2356. CounterTable,
  2357. dwDetailLevel,
  2358. dwFlags);
  2359. break;
  2360. case PDH_LOG_TYPE_SQL:
  2361. pdhStatus = PdhiEnumObjectItemsFromSQLLog (
  2362. (PPDHI_LOG) hDataSource,
  2363. szMachineName,
  2364. szObjectName,
  2365. CounterTable,
  2366. dwDetailLevel,
  2367. dwFlags);
  2368. break;
  2369. case PDH_LOG_TYPE_PERFMON:
  2370. pdhStatus = PdhiEnumObjectItemsFromPerfmonLog (
  2371. (PPDHI_LOG)hDataSource,
  2372. szMachineName,
  2373. szObjectName,
  2374. CounterTable,
  2375. dwDetailLevel,
  2376. dwFlags);
  2377. break;
  2378. default:
  2379. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  2380. break;
  2381. }
  2382. }
  2383. else {
  2384. pdhStatus = PDH_INVALID_HANDLE;
  2385. }
  2386. RELEASE_MUTEX (pDataSource->hLogMutex);
  2387. }
  2388. }
  2389. if (pdhStatus == ERROR_SUCCESS) {
  2390. dwCntrBufferUsed = 0;
  2391. for (dwIndex = 0; dwIndex < HASH_TABLE_SIZE; dwIndex ++) {
  2392. PPDHI_INSTANCE pNewInst;
  2393. pInstList = CounterTable[dwIndex];
  2394. while (pInstList != NULL) {
  2395. if (! IsListEmpty(& pInstList->InstList)) {
  2396. pHeadInst = & pInstList->InstList;
  2397. pNextInst = pHeadInst->Flink;
  2398. while (pNextInst != pHeadInst) {
  2399. pInstance = CONTAINING_RECORD(
  2400. pNextInst, PDHI_INSTANCE, Entry);
  2401. pdhStatus = PdhiFindInstance(
  2402. & InstanceList,
  2403. pInstance->szInstance,
  2404. FALSE,
  2405. & pNewInst);
  2406. if (pNewInst->dwTotal < pInstance->dwTotal) {
  2407. pNewInst->dwTotal = pInstance->dwTotal;
  2408. }
  2409. pNextInst = pNextInst->Flink;
  2410. }
  2411. }
  2412. dwNewBuffer = (lstrlenW(pInstList->szCounter) + 1)
  2413. * sizeof(WCHAR);
  2414. while ( LocalCounterSize
  2415. < (dwCntrBufferUsed + dwNewBuffer)) {
  2416. TempBuffer = LocalCounter;
  2417. LocalCounter = G_REALLOC(TempBuffer,
  2418. LocalCounterSize + MEDIUM_BUFFER_SIZE);
  2419. if (LocalCounter == NULL) {
  2420. G_FREE(TempBuffer);
  2421. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2422. goto Cleanup;
  2423. }
  2424. LocalCounterSize += MEDIUM_BUFFER_SIZE;
  2425. }
  2426. dwNewBuffer = AddStringToMultiSz(
  2427. (LPVOID) LocalCounter,
  2428. pInstList->szCounter,
  2429. bUnicode);
  2430. if (dwNewBuffer > 0) {
  2431. dwCntrBufferUsed = dwNewBuffer *
  2432. (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
  2433. }
  2434. pInstList = pInstList->pNext;
  2435. }
  2436. }
  2437. dwInstBufferUsed = 0;
  2438. if (! IsListEmpty(& InstanceList)) {
  2439. pHeadInst = & InstanceList;
  2440. pNextInst = pHeadInst->Flink;
  2441. while (pNextInst != pHeadInst) {
  2442. pInstance = CONTAINING_RECORD(
  2443. pNextInst, PDHI_INSTANCE, Entry);
  2444. dwNewBuffer = (lstrlenW(pInstance->szInstance) + 1)
  2445. * sizeof(WCHAR) * pInstance->dwTotal;
  2446. while ( LocalInstanceSize
  2447. < (dwInstBufferUsed + dwNewBuffer)) {
  2448. TempBuffer = LocalInstance;
  2449. LocalInstance = G_REALLOC(TempBuffer,
  2450. LocalInstanceSize + MEDIUM_BUFFER_SIZE);
  2451. if (LocalInstance == NULL) {
  2452. G_FREE(TempBuffer);
  2453. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2454. goto Cleanup;
  2455. }
  2456. LocalInstanceSize += MEDIUM_BUFFER_SIZE;
  2457. }
  2458. for (dwIndex = 0; dwIndex < pInstance->dwTotal; dwIndex ++) {
  2459. dwNewBuffer = AddStringToMultiSz(
  2460. (LPVOID) LocalInstance,
  2461. pInstance->szInstance,
  2462. bUnicode);
  2463. }
  2464. if (dwNewBuffer > 0) {
  2465. dwInstBufferUsed = dwNewBuffer *
  2466. (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
  2467. }
  2468. pNextInst = pNextInst->Flink;
  2469. }
  2470. }
  2471. if (mszCounterList && dwCntrBufferUsed <= * pdwCounterListLength) {
  2472. RtlCopyMemory(mszCounterList, LocalCounter, dwCntrBufferUsed);
  2473. }
  2474. else {
  2475. if (mszCounterList)
  2476. RtlCopyMemory(mszCounterList,
  2477. LocalCounter,
  2478. * pdwCounterListLength);
  2479. dwCntrBufferUsed += (bUnicode) ? sizeof(WCHAR)
  2480. : sizeof(CHAR);
  2481. pdhStatus = PDH_MORE_DATA;
  2482. }
  2483. *pdwCounterListLength = dwCntrBufferUsed;
  2484. if (dwInstBufferUsed > 0) {
  2485. if ( mszInstanceList
  2486. && dwInstBufferUsed <= * pdwInstanceListLength) {
  2487. RtlCopyMemory(mszInstanceList, LocalInstance, dwInstBufferUsed);
  2488. }
  2489. else {
  2490. if (mszInstanceList)
  2491. RtlCopyMemory(mszInstanceList,
  2492. LocalInstance,
  2493. * pdwInstanceListLength);
  2494. dwInstBufferUsed += (bUnicode) ? sizeof(WCHAR)
  2495. : sizeof(CHAR);
  2496. pdhStatus = PDH_MORE_DATA;
  2497. }
  2498. }
  2499. *pdwInstanceListLength = dwInstBufferUsed;
  2500. }
  2501. Cleanup:
  2502. if (! IsListEmpty(& InstanceList)) {
  2503. pHeadInst = & InstanceList;
  2504. pNextInst = pHeadInst->Flink;
  2505. while (pNextInst != pHeadInst) {
  2506. pInstance = CONTAINING_RECORD(pNextInst, PDHI_INSTANCE, Entry);
  2507. pNextInst = pNextInst->Flink;
  2508. RemoveEntryList(& pInstance->Entry);
  2509. G_FREE(pInstance);
  2510. }
  2511. }
  2512. for (dwIndex = 0; dwIndex < HASH_TABLE_SIZE; dwIndex ++) {
  2513. PPDHI_INST_LIST pCurrent;
  2514. pInstList = CounterTable[dwIndex];
  2515. while (pInstList != NULL) {
  2516. if (! IsListEmpty(& pInstList->InstList)) {
  2517. pHeadInst = & pInstList->InstList;
  2518. pNextInst = pHeadInst->Flink;
  2519. while (pNextInst != pHeadInst) {
  2520. pInstance = CONTAINING_RECORD(
  2521. pNextInst, PDHI_INSTANCE, Entry);
  2522. pNextInst = pNextInst->Flink;
  2523. RemoveEntryList(& pInstance->Entry);
  2524. G_FREE(pInstance);
  2525. }
  2526. }
  2527. pCurrent = pInstList;
  2528. pInstList = pInstList->pNext;
  2529. G_FREE(pCurrent);
  2530. }
  2531. }
  2532. if (LocalCounter != NULL) {
  2533. G_FREE(LocalCounter);
  2534. }
  2535. if (LocalInstance != NULL) {
  2536. G_FREE(LocalInstance);
  2537. }
  2538. return pdhStatus;
  2539. }
  2540. BOOL
  2541. PdhiDataSourceHasDetailLevels (
  2542. IN LPWSTR szDataSource
  2543. )
  2544. {
  2545. if (szDataSource == NULL) {
  2546. // real-time supports them
  2547. return TRUE;
  2548. } else {
  2549. // logs don't (for now)
  2550. return FALSE;
  2551. }
  2552. }
  2553. BOOL
  2554. PdhiDataSourceHasDetailLevelsH(
  2555. IN HLOG hDataSource
  2556. )
  2557. {
  2558. return (hDataSource == H_REALTIME_DATASOURCE);
  2559. }
  2560. PDH_FUNCTION
  2561. PdhiGetMatchingLogRecord (
  2562. IN HLOG hLog,
  2563. IN LONGLONG *pStartTime,
  2564. IN LPDWORD pdwIndex
  2565. )
  2566. {
  2567. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  2568. PPDHI_LOG pLog;
  2569. DWORD dwTempIndex;
  2570. __try {
  2571. dwTempIndex = *pdwIndex;
  2572. *pdwIndex = 0;
  2573. *pdwIndex = dwTempIndex;
  2574. } __except (EXCEPTION_EXECUTE_HANDLER) {
  2575. pdhStatus = PDH_INVALID_ARGUMENT;
  2576. }
  2577. if (pdhStatus == ERROR_SUCCESS) {
  2578. if (IsValidLogHandle (hLog)) {
  2579. pLog = (PPDHI_LOG)hLog;
  2580. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
  2581. if (pdhStatus == ERROR_SUCCESS) {
  2582. if (IsValidLogHandle (hLog)) {
  2583. // call any type-specific open functions
  2584. switch (LOWORD(pLog->dwLogFormat)) {
  2585. case PDH_LOG_TYPE_CSV:
  2586. case PDH_LOG_TYPE_TSV:
  2587. pdhStatus = PdhiGetMatchingTextLogRecord (
  2588. pLog,
  2589. pStartTime,
  2590. pdwIndex);
  2591. break;
  2592. case PDH_LOG_TYPE_BINARY:
  2593. case PDH_LOG_TYPE_RETIRED_BIN:
  2594. pdhStatus = PdhiGetMatchingBinaryLogRecord (
  2595. pLog,
  2596. pStartTime,
  2597. pdwIndex);
  2598. break;
  2599. case PDH_LOG_TYPE_SQL:
  2600. pdhStatus = PdhiGetMatchingSQLLogRecord (
  2601. pLog,
  2602. pStartTime,
  2603. pdwIndex);
  2604. break;
  2605. case PDH_LOG_TYPE_PERFMON:
  2606. pdhStatus = PdhiGetMatchingPerfmonLogRecord (
  2607. pLog,
  2608. pStartTime,
  2609. pdwIndex);
  2610. break;
  2611. default:
  2612. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  2613. break;
  2614. }
  2615. } else {
  2616. pdhStatus = PDH_INVALID_HANDLE;
  2617. }
  2618. RELEASE_MUTEX (pLog->hLogMutex);
  2619. }
  2620. } else {
  2621. pdhStatus = PDH_INVALID_HANDLE;
  2622. }
  2623. }
  2624. return pdhStatus;
  2625. }
  2626. PDH_FUNCTION
  2627. PdhiGetCounterValueFromLogFile (
  2628. IN HLOG hLog,
  2629. IN DWORD dwIndex,
  2630. IN PPDHI_COUNTER pCounter
  2631. )
  2632. {
  2633. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  2634. PPDHI_LOG pLog = NULL;
  2635. PDH_RAW_COUNTER pValue;
  2636. memset (&pValue, 0, sizeof (pValue));
  2637. pCounter->LastValue = pCounter->ThisValue;
  2638. if (pdhStatus == ERROR_SUCCESS) {
  2639. if (IsValidLogHandle (hLog)) {
  2640. pLog = (PPDHI_LOG)hLog;
  2641. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
  2642. if (pdhStatus == ERROR_SUCCESS) {
  2643. if (IsValidLogHandle (hLog)) {
  2644. // call any type-specific open functions
  2645. switch (LOWORD(pLog->dwLogFormat)) {
  2646. case PDH_LOG_TYPE_CSV:
  2647. case PDH_LOG_TYPE_TSV:
  2648. pdhStatus = PdhiGetCounterValueFromTextLog (
  2649. pLog,
  2650. dwIndex,
  2651. & pCounter->plCounterInfo,
  2652. & pValue);
  2653. break;
  2654. case PDH_LOG_TYPE_RETIRED_BIN:
  2655. pdhStatus = PdhiGetCounterValueFromBinaryLog (
  2656. pLog,
  2657. dwIndex,
  2658. pCounter);
  2659. break;
  2660. case PDH_LOG_TYPE_SQL:
  2661. pdhStatus = PdhiGetCounterValueFromSQLLog (
  2662. pLog,
  2663. dwIndex,
  2664. pCounter,
  2665. &pValue);
  2666. break;
  2667. case PDH_LOG_TYPE_PERFMON:
  2668. pdhStatus = PdhiGetCounterValueFromPerfmonLog (
  2669. pLog,
  2670. dwIndex,
  2671. pCounter,
  2672. & pValue);
  2673. break;
  2674. case PDH_LOG_TYPE_BINARY:
  2675. default:
  2676. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  2677. break;
  2678. }
  2679. } else {
  2680. pdhStatus = PDH_INVALID_HANDLE;
  2681. }
  2682. RELEASE_MUTEX (pLog->hLogMutex);
  2683. }
  2684. } else {
  2685. pdhStatus = PDH_INVALID_HANDLE;
  2686. }
  2687. }
  2688. if ( pdhStatus == ERROR_SUCCESS
  2689. && LOWORD(pLog->dwLogFormat) != PDH_LOG_TYPE_RETIRED_BIN
  2690. && LOWORD(pLog->dwLogFormat) != PDH_LOG_TYPE_BINARY) {
  2691. if (pdhStatus != ERROR_SUCCESS) {
  2692. // See if this is because there's no more entries.
  2693. // If not, clear the counter value & return error
  2694. //
  2695. if (pdhStatus != PDH_NO_MORE_DATA) {
  2696. memset (& pCounter->ThisValue, 0, sizeof (PDH_RAW_COUNTER));
  2697. pCounter->ThisValue.CStatus = pdhStatus;
  2698. }
  2699. }
  2700. else {
  2701. pCounter->ThisValue = pValue;
  2702. }
  2703. }
  2704. return pdhStatus;
  2705. }
  2706. PDH_FUNCTION
  2707. PdhiResetLogBuffers (
  2708. IN HLOG hLog
  2709. )
  2710. {
  2711. PDH_STATUS pdhStatus;
  2712. PPDHI_LOG pLog;
  2713. if (IsValidLogHandle(hLog)) {
  2714. pLog = (PPDHI_LOG)hLog;
  2715. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
  2716. if (pdhStatus == ERROR_SUCCESS) {
  2717. if (IsValidLogHandle (hLog)) {
  2718. if (LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_BINARY) {
  2719. pdhStatus = PdhiRewindWmiLog(pLog);
  2720. }
  2721. else {
  2722. pLog->dwLastRecordRead = 0;
  2723. if (pLog->lpMappedFileBase != NULL) {
  2724. // for mapped files we use a pointer into the buffer
  2725. // so reset it
  2726. pLog->pLastRecordRead = pLog->lpMappedFileBase;
  2727. } else {
  2728. // for other files we have a separate buffer
  2729. if (pLog->pLastRecordRead != NULL) {
  2730. G_FREE (pLog->pLastRecordRead);
  2731. pLog->pLastRecordRead = NULL;
  2732. }
  2733. }
  2734. pdhStatus = ERROR_SUCCESS;
  2735. }
  2736. } else {
  2737. pdhStatus = PDH_INVALID_HANDLE;
  2738. }
  2739. RELEASE_MUTEX (pLog->hLogMutex);
  2740. }
  2741. } else {
  2742. pdhStatus = PDH_INVALID_HANDLE;
  2743. }
  2744. return pdhStatus;
  2745. }
  2746. PDH_FUNCTION
  2747. PdhListLogFileHeaderW (
  2748. IN LPCWSTR szFileName,
  2749. IN LPWSTR mszHeaderList,
  2750. IN LPDWORD pcchHeaderListSize
  2751. )
  2752. {
  2753. HLOG hDataSource = NULL;
  2754. PDH_STATUS pdhStatus;
  2755. DWORD dwLogType = -1;
  2756. PPDHI_LOG pDataSource;
  2757. BOOL bUnicode = TRUE;
  2758. // open log file
  2759. pdhStatus = PdhOpenLogW (
  2760. szFileName,
  2761. PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
  2762. &dwLogType,
  2763. NULL,
  2764. 0,
  2765. NULL,
  2766. &hDataSource);
  2767. if (pdhStatus == ERROR_SUCCESS) {
  2768. pDataSource = (PPDHI_LOG)hDataSource;
  2769. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pDataSource->hLogMutex);
  2770. if (pdhStatus == ERROR_SUCCESS) {
  2771. if (IsValidLogHandle (hDataSource)) {
  2772. // enum objects based on log type & machine name
  2773. switch (LOWORD(dwLogType)) {
  2774. case PDH_LOG_TYPE_CSV:
  2775. case PDH_LOG_TYPE_TSV:
  2776. pdhStatus = PdhiListHeaderFromTextLog (
  2777. (PPDHI_LOG)hDataSource,
  2778. (LPVOID)mszHeaderList,
  2779. pcchHeaderListSize,
  2780. bUnicode);
  2781. break;
  2782. case PDH_LOG_TYPE_BINARY:
  2783. case PDH_LOG_TYPE_RETIRED_BIN:
  2784. pdhStatus = PdhiListHeaderFromBinaryLog (
  2785. (PPDHI_LOG)hDataSource,
  2786. (LPVOID)mszHeaderList,
  2787. pcchHeaderListSize,
  2788. bUnicode);
  2789. break;
  2790. case PDH_LOG_TYPE_SQL:
  2791. pdhStatus = PdhiListHeaderFromSQLLog (
  2792. (PPDHI_LOG)hDataSource,
  2793. (LPVOID)mszHeaderList,
  2794. pcchHeaderListSize,
  2795. bUnicode);
  2796. break;
  2797. case PDH_LOG_TYPE_PERFMON:
  2798. pdhStatus = PDH_NOT_IMPLEMENTED;
  2799. break;
  2800. default:
  2801. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  2802. break;
  2803. }
  2804. PdhCloseLog (hDataSource, 0);
  2805. } else {
  2806. pdhStatus = PDH_INVALID_HANDLE;
  2807. }
  2808. RELEASE_MUTEX (pDataSource->hLogMutex);
  2809. }
  2810. }
  2811. return pdhStatus;
  2812. }
  2813. PDH_FUNCTION
  2814. PdhListLogFileHeaderA (
  2815. IN LPCSTR szFileName,
  2816. IN LPSTR mszHeaderList,
  2817. IN LPDWORD pcchHeaderListSize
  2818. )
  2819. {
  2820. HLOG hDataSource = NULL;
  2821. PDH_STATUS pdhStatus;
  2822. DWORD dwLogType = -1;
  2823. PPDHI_LOG pDataSource;
  2824. BOOL bUnicode = FALSE;
  2825. // open log file
  2826. pdhStatus = PdhOpenLogA (
  2827. szFileName,
  2828. PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
  2829. &dwLogType,
  2830. NULL,
  2831. 0,
  2832. NULL,
  2833. &hDataSource);
  2834. if (pdhStatus == ERROR_SUCCESS) {
  2835. pDataSource = (PPDHI_LOG)hDataSource;
  2836. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pDataSource->hLogMutex);
  2837. if (pdhStatus == ERROR_SUCCESS) {
  2838. if (IsValidLogHandle (hDataSource)) {
  2839. // enum objects based on log type & machine name
  2840. switch (LOWORD(dwLogType)) {
  2841. case PDH_LOG_TYPE_CSV:
  2842. case PDH_LOG_TYPE_TSV:
  2843. pdhStatus = PdhiListHeaderFromTextLog (
  2844. (PPDHI_LOG)hDataSource,
  2845. (LPVOID)mszHeaderList,
  2846. pcchHeaderListSize,
  2847. bUnicode);
  2848. break;
  2849. case PDH_LOG_TYPE_BINARY:
  2850. case PDH_LOG_TYPE_RETIRED_BIN:
  2851. pdhStatus = PdhiListHeaderFromBinaryLog (
  2852. (PPDHI_LOG)hDataSource,
  2853. (LPVOID)mszHeaderList,
  2854. pcchHeaderListSize,
  2855. bUnicode);
  2856. break;
  2857. case PDH_LOG_TYPE_SQL:
  2858. pdhStatus = PdhiListHeaderFromSQLLog (
  2859. (PPDHI_LOG)hDataSource,
  2860. (LPVOID)mszHeaderList,
  2861. pcchHeaderListSize,
  2862. bUnicode);
  2863. break;
  2864. case PDH_LOG_TYPE_PERFMON:
  2865. pdhStatus = PDH_NOT_IMPLEMENTED;
  2866. break;
  2867. default:
  2868. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  2869. break;
  2870. }
  2871. PdhCloseLog (hDataSource, 0);
  2872. } else {
  2873. pdhStatus = PDH_INVALID_HANDLE;
  2874. }
  2875. RELEASE_MUTEX (pDataSource->hLogMutex);
  2876. }
  2877. }
  2878. return pdhStatus;
  2879. }
  2880. PDH_FUNCTION
  2881. PdhiGetMultiInstanceValueFromLogFile (
  2882. IN HLOG hLog,
  2883. IN DWORD dwIndex,
  2884. IN PPDHI_COUNTER pCounter,
  2885. IN OUT PPDHI_RAW_COUNTER_ITEM_BLOCK *ppValue
  2886. )
  2887. {
  2888. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  2889. PPDHI_LOG pLog;
  2890. // allocates and updates the raw counter data array
  2891. // in the counter structure and returns a pointer to that
  2892. // structure in the ppvalue argument
  2893. if (pdhStatus == ERROR_SUCCESS) {
  2894. if (IsValidLogHandle (hLog)) {
  2895. pLog = (PPDHI_LOG)hLog;
  2896. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
  2897. if (pdhStatus == ERROR_SUCCESS) {
  2898. if (IsValidLogHandle (hLog)) {
  2899. // call any type-specific open functions
  2900. switch (LOWORD(pLog->dwLogFormat)) {
  2901. case PDH_LOG_TYPE_CSV:
  2902. case PDH_LOG_TYPE_TSV:
  2903. // Text files do not support this type of counter
  2904. pdhStatus = PDH_INVALID_ARGUMENT;
  2905. break;
  2906. case PDH_LOG_TYPE_BINARY:
  2907. case PDH_LOG_TYPE_RETIRED_BIN:
  2908. pdhStatus = PdhiGetCounterArrayFromBinaryLog (
  2909. pLog,
  2910. dwIndex,
  2911. pCounter,
  2912. ppValue);
  2913. break;
  2914. case PDH_LOG_TYPE_PERFMON:
  2915. // not currently implemented but it could be
  2916. pdhStatus = PDH_NOT_IMPLEMENTED;
  2917. break;
  2918. default:
  2919. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  2920. break;
  2921. }
  2922. } else {
  2923. pdhStatus = PDH_INVALID_HANDLE;
  2924. }
  2925. RELEASE_MUTEX (pLog->hLogMutex);
  2926. }
  2927. } else {
  2928. pdhStatus = PDH_INVALID_HANDLE;
  2929. }
  2930. }
  2931. return pdhStatus;
  2932. }
  2933. extern DWORD DataSourceTypeW(IN LPCWSTR szDataSource);
  2934. PDH_FUNCTION
  2935. PdhBindInputDataSourceW(
  2936. IN HLOG * phDataSource,
  2937. IN LPCWSTR LogFileNameList
  2938. )
  2939. {
  2940. PDH_STATUS PdhStatus = ERROR_SUCCESS;
  2941. DWORD dwDataSource = DataSourceTypeW(LogFileNameList);
  2942. LPWSTR NextLogFile = (LPWSTR) LogFileNameList;
  2943. ULONG LogFileCount = 0;
  2944. ULONG LogFileSize;
  2945. PPDHI_LOG pLogHead = NULL;
  2946. PPDHI_LOG pLogNew = NULL;
  2947. DWORD dwLogType;
  2948. HLOG hLogLocal = NULL;
  2949. WCHAR wcType[VALUE_BUFFER_SIZE];
  2950. switch (dwDataSource) {
  2951. case DATA_SOURCE_WBEM:
  2952. * phDataSource = H_WBEM_DATASOURCE;
  2953. break;
  2954. case DATA_SOURCE_REGISTRY:
  2955. * phDataSource = H_REALTIME_DATASOURCE;
  2956. break;
  2957. case DATA_SOURCE_LOGFILE:
  2958. ZeroMemory((LPWSTR) wcType, sizeof(WCHAR) * VALUE_BUFFER_SIZE);
  2959. lstrcpynW((LPWSTR) wcType,
  2960. (LPWSTR) LogFileNameList,
  2961. lstrlenW(cszSQL) + 1);
  2962. if (lstrcmpiW((LPWSTR) wcType, (LPWSTR) cszSQL) == 0) {
  2963. // special handling for SQL datasource
  2964. //
  2965. dwLogType = PDH_LOG_TYPE_SQL;
  2966. PdhStatus = PdhOpenLogW(LogFileNameList,
  2967. PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
  2968. & dwLogType,
  2969. NULL,
  2970. 0,
  2971. NULL,
  2972. & hLogLocal);
  2973. if (PdhStatus == ERROR_SUCCESS) {
  2974. * phDataSource = hLogLocal;
  2975. }
  2976. break;
  2977. }
  2978. __try {
  2979. while (* NextLogFile != L'\0') {
  2980. LogFileSize = sizeof(WCHAR) * (lstrlenW(NextLogFile) + 1);
  2981. LogFileSize = DWORD_MULTIPLE(LogFileSize);
  2982. //LogFileSize += sizeof(PDHI_LOG);
  2983. pLogNew = G_ALLOC(LogFileSize + sizeof(PDHI_LOG));
  2984. if (pLogNew == NULL) {
  2985. PdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2986. break;
  2987. }
  2988. RtlZeroMemory(pLogNew, LogFileSize + sizeof(PDHI_LOG));
  2989. * ((LPDWORD)(& pLogNew->signature[0])) = SigLog;
  2990. pLogNew->dwLength = sizeof(PDHI_LOG);
  2991. pLogNew->szLogFileName = (LPWSTR) ( ((PUCHAR) pLogNew)
  2992. + sizeof(PDHI_LOG));
  2993. lstrcpyW(pLogNew->szLogFileName, NextLogFile);
  2994. pLogNew->NextLog = pLogHead;
  2995. pLogHead = pLogNew;
  2996. LogFileCount ++;
  2997. NextLogFile += (lstrlenW(NextLogFile) + 1);
  2998. }
  2999. if (pLogHead == NULL) {
  3000. PdhStatus = PDH_INVALID_ARGUMENT;
  3001. }
  3002. }
  3003. __except (EXCEPTION_EXECUTE_HANDLER) {
  3004. PdhStatus = PDH_INVALID_ARGUMENT;
  3005. }
  3006. if (PdhStatus == ERROR_SUCCESS) {
  3007. pLogHead->hLogMutex = CreateMutexW(NULL, TRUE, NULL);
  3008. pLogHead->hLogFileHandle = INVALID_HANDLE_VALUE;
  3009. pLogHead->hCatFileHandle = INVALID_HANDLE_VALUE;
  3010. if (PdhiFirstLogEntry == NULL) {
  3011. PdhiFirstLogEntry = pLogHead;
  3012. pLogHead->next.flink =
  3013. pLogHead->next.blink = pLogHead;
  3014. }
  3015. else {
  3016. PPDHI_LOG pFirstLog = PdhiFirstLogEntry;
  3017. PPDHI_LOG pLastLog = pFirstLog->next.blink;
  3018. pLogHead->next.flink = pLastLog->next.flink;
  3019. pLastLog->next.flink = pLogHead;
  3020. pLogHead->next.blink = pFirstLog->next.blink;
  3021. pFirstLog->next.blink = pLogHead;
  3022. }
  3023. PdhStatus = OpenInputLogFile(
  3024. pLogHead,
  3025. PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
  3026. & dwDataSource);
  3027. if ( PdhStatus == ERROR_SUCCESS
  3028. && (dwDataSource == PDH_LOG_TYPE_BINARY || LogFileCount == 1)) {
  3029. * phDataSource = (HLOG) pLogHead;
  3030. }
  3031. else {
  3032. if (PdhStatus == ERROR_SUCCESS) {
  3033. PdhStatus = PDH_INVALID_ARGUMENT;
  3034. PdhCloseLog(pLogHead, 0);
  3035. }
  3036. DeleteLogEntry(pLogHead);
  3037. }
  3038. }
  3039. else {
  3040. while (pLogHead != NULL) {
  3041. pLogNew = pLogHead;
  3042. pLogHead = pLogNew->NextLog;
  3043. G_FREE(pLogNew);
  3044. }
  3045. }
  3046. break;
  3047. default:
  3048. PdhStatus = PDH_INVALID_ARGUMENT;
  3049. break;
  3050. }
  3051. return PdhStatus;
  3052. }
  3053. PDH_FUNCTION
  3054. PdhBindInputDataSourceA(
  3055. IN HLOG * phDataSource,
  3056. IN LPCSTR LogFileNameList
  3057. )
  3058. {
  3059. LPWSTR wLogFileNameList = NULL;
  3060. LPWSTR wNextFileName;
  3061. LPSTR aNextFileName;
  3062. ULONG LogFileListSize = 1;
  3063. PDH_STATUS PdhStatus = ERROR_SUCCESS;
  3064. if (LogFileNameList == NULL) {
  3065. wLogFileNameList = NULL;
  3066. }
  3067. else {
  3068. __try {
  3069. while ( LogFileNameList[LogFileListSize - 1] != '\0'
  3070. || LogFileNameList[LogFileListSize] != '\0') {
  3071. LogFileListSize ++;
  3072. }
  3073. LogFileListSize = (LogFileListSize + 1) * sizeof(WCHAR);
  3074. wLogFileNameList = (LPWSTR) G_ALLOC(LogFileListSize);
  3075. if (wLogFileNameList == NULL) {
  3076. PdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  3077. }
  3078. else {
  3079. aNextFileName = (LPSTR) LogFileNameList;
  3080. wNextFileName = wLogFileNameList;
  3081. while (* aNextFileName != '\0') {
  3082. LogFileListSize = lstrlenA(aNextFileName);
  3083. MultiByteToWideChar(_getmbcp(),
  3084. 0,
  3085. aNextFileName,
  3086. LogFileListSize,
  3087. (LPWSTR) wNextFileName,
  3088. LogFileListSize + 1);
  3089. aNextFileName += LogFileListSize;
  3090. wNextFileName += LogFileListSize;
  3091. }
  3092. * wNextFileName = L'\0';
  3093. }
  3094. }
  3095. __except (EXCEPTION_EXECUTE_HANDLER) {
  3096. PdhStatus = PDH_INVALID_ARGUMENT;
  3097. }
  3098. }
  3099. if (PdhStatus == ERROR_SUCCESS) {
  3100. PdhStatus = PdhBindInputDataSourceW(phDataSource, wLogFileNameList);
  3101. }
  3102. return PdhStatus;
  3103. }
  3104. BOOL
  3105. PdhiCloseAllLoggers()
  3106. {
  3107. while (PdhiFirstLogEntry != NULL) {
  3108. PPDHI_LOG pLog = PdhiFirstLogEntry;
  3109. CloseAndDeleteLogEntry(pLog, 0, TRUE);
  3110. }
  3111. return TRUE;
  3112. }
  3113. PDH_FUNCTION PdhiCheckWmiLogFileType(IN LPCWSTR LogFileName,
  3114. IN LPDWORD LogFileType);
  3115. PDH_FUNCTION
  3116. PdhGetLogFileTypeW(
  3117. IN LPCWSTR LogFileName,
  3118. IN LPDWORD LogFileType)
  3119. {
  3120. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  3121. HANDLE hFile;
  3122. DWORD dwLogFormat;
  3123. if (LogFileName == NULL) {
  3124. pdhStatus = PDH_INVALID_ARGUMENT;
  3125. }
  3126. else {
  3127. __try {
  3128. dwLogFormat = * LogFileType;
  3129. * LogFileType = dwLogFormat;
  3130. if (* LogFileName == L'\0') {
  3131. pdhStatus = PDH_INVALID_ARGUMENT;
  3132. }
  3133. } __except (EXCEPTION_EXECUTE_HANDLER) {
  3134. pdhStatus = PDH_INVALID_ARGUMENT;
  3135. }
  3136. }
  3137. if (pdhStatus == ERROR_SUCCESS) {
  3138. hFile = CreateFileW(LogFileName,
  3139. GENERIC_READ,
  3140. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3141. NULL,
  3142. OPEN_EXISTING,
  3143. FILE_ATTRIBUTE_NORMAL,
  3144. NULL);
  3145. if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) {
  3146. pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
  3147. }
  3148. }
  3149. if (pdhStatus == ERROR_SUCCESS) {
  3150. dwLogFormat = GetLogFileType(hFile);
  3151. CloseHandle(hFile);
  3152. if (dwLogFormat == PDH_LOG_TYPE_UNDEFINED) {
  3153. pdhStatus = PdhiCheckWmiLogFileType(LogFileName, & dwLogFormat);
  3154. }
  3155. }
  3156. if (pdhStatus == ERROR_SUCCESS) {
  3157. * LogFileType = dwLogFormat;
  3158. }
  3159. return pdhStatus;
  3160. }
  3161. PDH_FUNCTION
  3162. PdhGetLogFileTypeA(
  3163. IN LPCSTR LogFileName,
  3164. IN LPDWORD LogFileType)
  3165. {
  3166. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  3167. LPWSTR wszLogFileName = NULL;
  3168. DWORD dwLogFileName = 0;
  3169. if (LogFileName == NULL) {
  3170. pdhStatus = PDH_INVALID_ARGUMENT;
  3171. }
  3172. else {
  3173. __try {
  3174. if (* LogFileName == '\0') {
  3175. pdhStatus = PDH_INVALID_ARGUMENT;
  3176. }
  3177. else {
  3178. dwLogFileName = lstrlenA(LogFileName);
  3179. wszLogFileName = (LPWSTR)
  3180. G_ALLOC((dwLogFileName + 1) * sizeof(WCHAR));
  3181. if (wszLogFileName == NULL) {
  3182. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  3183. }
  3184. else {
  3185. MultiByteToWideChar(_getmbcp(),
  3186. 0,
  3187. LogFileName,
  3188. dwLogFileName,
  3189. (LPWSTR) wszLogFileName,
  3190. dwLogFileName + 1);
  3191. }
  3192. }
  3193. } __except (EXCEPTION_EXECUTE_HANDLER) {
  3194. pdhStatus = PDH_INVALID_ARGUMENT;
  3195. }
  3196. }
  3197. if (pdhStatus == ERROR_SUCCESS) {
  3198. pdhStatus = PdhGetLogFileTypeW(wszLogFileName, LogFileType);
  3199. }
  3200. if (wszLogFileName != NULL) {
  3201. G_FREE(wszLogFileName);
  3202. }
  3203. return pdhStatus;
  3204. }