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.

2229 lines
77 KiB

  1. /*++
  2. Copyright (C) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. log_text.c
  5. Abstract:
  6. <abstract>
  7. --*/
  8. #include <windows.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <assert.h>
  12. #include <mbctype.h>
  13. #include <pdh.h>
  14. #include "pdhidef.h"
  15. #include "log_text.h"
  16. #include "pdhmsg.h"
  17. #include "strings.h"
  18. #pragma warning ( disable : 4213)
  19. #define TAB_DELIMITER '\t'
  20. #define COMMA_DELIMITER ','
  21. #define DOUBLE_QUOTE '\"'
  22. #define VALUE_BUFFER_SIZE 32
  23. LPCSTR PdhiszFmtTimeStamp = "\"%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d.%3.3d\"";
  24. LPCSTR PdhiszFmtStringValue = "%c\"%s\"";
  25. LPCSTR PdhiszFmtRealValue = "%c\"%.20g\"";
  26. TIME_ZONE_INFORMATION TimeZone;
  27. // LPCSTR PdhiszTimeStampLabel = " Sample Time\"";
  28. // DWORD PdhidwTimeStampLabelLength = 13;
  29. extern LPCSTR PdhiszRecordTerminator;
  30. extern DWORD PdhidwRecordTerminatorLength;
  31. #define TEXTLOG_TYPE_ID_RECORD 1
  32. #define TEXTLOG_HEADER_RECORD 1
  33. #define TEXTLOG_FIRST_DATA_RECORD 2
  34. #define TIME_FIELD_COUNT 7
  35. #define TIME_FIELD_BUFF_SIZE 24
  36. DWORD dwTimeFieldOffsetList[TIME_FIELD_COUNT] = {2, 5, 10, 13, 16, 19, 23};
  37. #define MAX_TEXT_FILE_SIZE ((LONGLONG)0x0000000077FFFFFF)
  38. PDH_FUNCTION
  39. PdhiBuildFullCounterPath(
  40. IN BOOL bMachine,
  41. IN PPDHI_COUNTER_PATH pCounterPath,
  42. IN LPWSTR szObjectName,
  43. IN LPWSTR szCounterName,
  44. IN LPWSTR szFullPath
  45. );
  46. STATIC_BOOL
  47. PdhiDateStringToFileTimeA (
  48. IN LPSTR szDateTimeString,
  49. IN LPFILETIME pFileTime
  50. );
  51. STATIC_DWORD
  52. PdhiGetStringFromDelimitedListA (
  53. IN LPSTR szInputString,
  54. IN DWORD dwItemIndex,
  55. IN CHAR cDelimiter,
  56. IN DWORD dwFlags,
  57. IN LPSTR szOutputString,
  58. IN DWORD cchBufferLength
  59. );
  60. STATIC_PDH_FUNCTION
  61. PdhiReadOneTextLogRecord (
  62. IN PPDHI_LOG pLog,
  63. IN DWORD dwRecordId,
  64. IN LPSTR szRecord,
  65. IN DWORD dwMaxSize
  66. );
  67. STATIC_BOOL
  68. PdhiDateStringToFileTimeA (
  69. IN LPSTR szDateTimeString,
  70. IN LPFILETIME pFileTime
  71. )
  72. {
  73. CHAR mszTimeFields[TIME_FIELD_BUFF_SIZE];
  74. DWORD dwThisField;
  75. LONG lValue;
  76. SYSTEMTIME st;
  77. // make string into msz
  78. lstrcpynA (mszTimeFields, szDateTimeString, TIME_FIELD_BUFF_SIZE);
  79. for (dwThisField = 0; dwThisField < TIME_FIELD_COUNT; dwThisField++) {
  80. mszTimeFields[dwTimeFieldOffsetList[dwThisField]] = 0;
  81. }
  82. // read string into system time structure
  83. dwThisField = 0;
  84. st.wDayOfWeek = 0;
  85. lValue = atol(&mszTimeFields[0]);
  86. st.wMonth = LOWORD(lValue);
  87. lValue = atol(&mszTimeFields[dwTimeFieldOffsetList[dwThisField++]+1]);
  88. st.wDay = LOWORD(lValue);
  89. lValue = atol(&mszTimeFields[dwTimeFieldOffsetList[dwThisField++]+1]);
  90. st.wYear = LOWORD(lValue);
  91. lValue = atol(&mszTimeFields[dwTimeFieldOffsetList[dwThisField++]+1]);
  92. st.wHour = LOWORD(lValue);
  93. lValue = atol(&mszTimeFields[dwTimeFieldOffsetList[dwThisField++]+1]);
  94. st.wMinute = LOWORD(lValue);
  95. lValue = atol(&mszTimeFields[dwTimeFieldOffsetList[dwThisField++]+1]);
  96. st.wSecond = LOWORD(lValue);
  97. lValue = atol(&mszTimeFields[dwTimeFieldOffsetList[dwThisField++]+1]);
  98. st.wMilliseconds = LOWORD(lValue);
  99. return SystemTimeToFileTime (&st, pFileTime);
  100. }
  101. #define PDHI_GSFDL_REMOVE_QUOTES 0x00000001
  102. #define PDHI_GSFDL_REMOVE_NONPRINT 0x00000002
  103. STATIC_DWORD
  104. PdhiGetStringFromDelimitedListA (
  105. IN LPSTR szInputString,
  106. IN DWORD dwItemIndex,
  107. IN CHAR cDelimiter,
  108. IN DWORD dwFlags,
  109. IN LPSTR szOutputString,
  110. IN DWORD cchBufferLength
  111. )
  112. {
  113. DWORD dwCurrentIndex = 0;
  114. LPSTR szCurrentItem;
  115. LPSTR szSrcPtr, szDestPtr;
  116. DWORD dwReturn = 0;
  117. BOOL bInsideQuote = FALSE;
  118. // go to desired entry in string, 0 = first entry
  119. szCurrentItem = szInputString;
  120. while (dwCurrentIndex < dwItemIndex) {
  121. // goto next delimiter or terminator
  122. while (* szCurrentItem != cDelimiter || bInsideQuote) {
  123. if (* szCurrentItem == 0) break;
  124. else if (* szCurrentItem == DOUBLEQUOTE_A) {
  125. bInsideQuote = ! bInsideQuote;
  126. }
  127. szCurrentItem ++;
  128. }
  129. if (* szCurrentItem != 0) szCurrentItem ++;
  130. dwCurrentIndex++;
  131. }
  132. if (*szCurrentItem != 0) {
  133. // then copy to the user's buffer, as long as it fits
  134. szSrcPtr = szCurrentItem;
  135. szDestPtr = szOutputString;
  136. dwReturn = 0;
  137. bInsideQuote = FALSE;
  138. while ( (dwReturn < cchBufferLength)
  139. && (* szSrcPtr != 0)
  140. && (* szSrcPtr != cDelimiter || bInsideQuote)) {
  141. if (* szSrcPtr == DOUBLEQUOTE_A) {
  142. bInsideQuote = ! bInsideQuote;
  143. if (dwFlags & PDHI_GSFDL_REMOVE_QUOTES) {
  144. // skip the quote
  145. szSrcPtr ++;
  146. continue;
  147. }
  148. }
  149. if (dwFlags & PDHI_GSFDL_REMOVE_NONPRINT) {
  150. if ((UCHAR) * szSrcPtr < (UCHAR) ' ') {
  151. // skip the control char
  152. szSrcPtr ++;
  153. continue;
  154. }
  155. }
  156. // copy character
  157. * szDestPtr ++ = * szSrcPtr ++;
  158. dwReturn ++; // increment length
  159. }
  160. if (dwReturn > 0) {
  161. * szDestPtr = 0; // add terminator char
  162. }
  163. }
  164. return dwReturn;
  165. }
  166. STATIC_PDH_FUNCTION
  167. PdhiReadOneTextLogRecord (
  168. IN PPDHI_LOG pLog,
  169. IN DWORD dwRecordId,
  170. IN LPSTR szRecord,
  171. IN DWORD dwMaxSize
  172. )
  173. // reads the specified record from the log file and returns it as an ANSI
  174. // character string
  175. {
  176. LPSTR szTempBuffer;
  177. LPSTR szOldBuffer;
  178. LPSTR szTempBufferPtr;
  179. LPSTR szReturn;
  180. PDH_STATUS pdhStatus;
  181. int nFileError = 0;
  182. DWORD dwRecordLength;
  183. DWORD dwBytesRead = 0;
  184. if (pLog->dwMaxRecordSize == 0) {
  185. // initialize with a default value
  186. dwRecordLength = SMALL_BUFFER_SIZE;
  187. } else {
  188. // use current maz record size max.
  189. dwRecordLength = pLog->dwMaxRecordSize;
  190. }
  191. szTempBuffer = G_ALLOC (dwRecordLength);
  192. if (szTempBuffer == NULL) {
  193. return PDH_MEMORY_ALLOCATION_FAILURE;
  194. }
  195. // position file pointer to desired record;
  196. if (dwRecordId == pLog->dwLastRecordRead) {
  197. // then return the current record from the cached buffer
  198. if ((DWORD)lstrlenA((LPSTR)pLog->pLastRecordRead) < dwMaxSize) {
  199. lstrcpyA(szRecord, (LPSTR)pLog->pLastRecordRead);
  200. pdhStatus = ERROR_SUCCESS;
  201. } else {
  202. pdhStatus = PDH_MORE_DATA;
  203. }
  204. // free temp buffer
  205. if (szTempBuffer != NULL) {
  206. G_FREE (szTempBuffer);
  207. }
  208. } else {
  209. if ((dwRecordId < pLog->dwLastRecordRead) || (pLog->dwLastRecordRead == 0)){
  210. // the desired record is before the current position
  211. // or the counter has been reset so we have to
  212. // go to the beginning of the file and read up to the specified
  213. // record.
  214. pLog->dwLastRecordRead = 0;
  215. rewind (pLog->StreamFile);
  216. }
  217. // free old buffer
  218. if (pLog->pLastRecordRead != NULL) {
  219. G_FREE (pLog->pLastRecordRead);
  220. pLog->pLastRecordRead = NULL;
  221. }
  222. // now seek to the desired entry
  223. do {
  224. szReturn = fgets (szTempBuffer, dwRecordLength, pLog->StreamFile);
  225. if (szReturn == NULL) {
  226. if (!feof(pLog->StreamFile)) {
  227. nFileError = ferror (pLog->StreamFile);
  228. }
  229. break; // end of file
  230. } else {
  231. // see if an entire record was read
  232. dwBytesRead = lstrlenA(szTempBuffer);
  233. // see if the last char is a new line
  234. if ((dwBytesRead > 0) &&
  235. (szTempBuffer[dwBytesRead-1] != '\r') &&
  236. (szTempBuffer[dwBytesRead-1] != '\n')) {
  237. // then if the record size is the same as the buffer
  238. // or there's more text in this record...
  239. // just to be safe, we'll realloc the buffer and try
  240. // reading some more
  241. while (dwBytesRead == dwRecordLength-1) {
  242. dwRecordLength += SMALL_BUFFER_SIZE;
  243. szOldBuffer = szTempBuffer;
  244. szTempBuffer = G_REALLOC (szOldBuffer, dwRecordLength);
  245. if (szTempBuffer == NULL) {
  246. G_FREE(szOldBuffer);
  247. pLog->dwLastRecordRead = 0;
  248. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  249. goto Cleanup;
  250. }
  251. // position read pointer at end of bytes already read
  252. szTempBufferPtr = szTempBuffer + dwBytesRead;
  253. szReturn = fgets (szTempBufferPtr,
  254. dwRecordLength - dwBytesRead,
  255. pLog->StreamFile);
  256. if (szReturn == NULL) {
  257. if (!feof(pLog->StreamFile)) {
  258. nFileError = ferror (pLog->StreamFile);
  259. }
  260. break; // end of file
  261. } else {
  262. // the BytesRead value already includes the NULL
  263. dwBytesRead += lstrlenA(szTempBufferPtr);
  264. }
  265. } // end while finding the end of the record
  266. // update the record length
  267. // add one byte to the length read to prevent entering the
  268. // recalc loop on records of the same size
  269. dwRecordLength = dwBytesRead + 1;
  270. szOldBuffer = szTempBuffer;
  271. szTempBuffer = G_REALLOC (szOldBuffer, dwRecordLength);
  272. if (szTempBuffer == NULL) {
  273. G_FREE(szOldBuffer);
  274. pLog->dwLastRecordRead = 0;
  275. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  276. goto Cleanup;
  277. }
  278. assert (szTempBuffer != NULL);
  279. } // else the whole record fit
  280. }
  281. } while (++pLog->dwLastRecordRead < dwRecordId);
  282. // update the max record length for the log file.
  283. if (dwRecordLength> pLog->dwMaxRecordSize) {
  284. pLog->dwMaxRecordSize = dwRecordLength;
  285. }
  286. // if the desired one was found then return it
  287. if (szReturn != NULL) {
  288. // then a record was read so update the cached values and return
  289. // the data
  290. pLog->pLastRecordRead = (LPVOID)szTempBuffer;
  291. // copy to the caller's buffer
  292. if (dwBytesRead < dwMaxSize) {
  293. lstrcpyA(szRecord, (LPSTR)pLog->pLastRecordRead);
  294. pdhStatus = ERROR_SUCCESS;
  295. } else {
  296. pdhStatus = PDH_MORE_DATA;
  297. }
  298. } else {
  299. // reset the pointers and buffers
  300. pLog->dwLastRecordRead = 0;
  301. G_FREE (szTempBuffer);
  302. pdhStatus = PDH_END_OF_LOG_FILE;
  303. }
  304. }
  305. Cleanup:
  306. return pdhStatus;
  307. }
  308. PDH_FUNCTION
  309. PdhiGetTextLogCounterInfo (
  310. IN PPDHI_LOG pLog,
  311. IN PPDHI_COUNTER pCounter
  312. )
  313. {
  314. PDH_STATUS pdhStatus;
  315. LPSTR szReturn;
  316. CHAR cDelim;
  317. CHAR szTemp[4];
  318. LPSTR szAnsiCounterPath = NULL;
  319. LPSTR szAnsiCounter = NULL;
  320. LPWSTR szUnicodeCounter = NULL;
  321. DWORD dwIndex;
  322. LPSTR szThisItem;
  323. DWORD dwPathLength;
  324. DWORD dwBufferLength;
  325. DWORD dwItemLength;
  326. DWORD dwInstanceId = 0;
  327. BOOL bNoMachine = FALSE;
  328. if (lstrcmpiW(pCounter->pCounterPath->szMachineName, L"\\\\.") == 0) {
  329. bNoMachine = TRUE;
  330. }
  331. // allocate extra space for DBCS characters
  332. //
  333. dwPathLength = lstrlenW(pCounter->pCounterPath->szMachineName) + 1
  334. + lstrlenW(pCounter->pCounterPath->szObjectName) + 1
  335. + lstrlenW(pCounter->pCounterPath->szParentName) + 4
  336. + lstrlenW(pCounter->pCounterPath->szInstanceName) + 2
  337. + lstrlenW(pCounter->pCounterPath->szCounterName) + 1;
  338. if ((lstrlenW(pCounter->szFullName) + 1) > (LONG) dwPathLength) {
  339. dwPathLength = lstrlenW(pCounter->szFullName) + 1;
  340. }
  341. szAnsiCounterPath = G_ALLOC(dwPathLength * 3 * sizeof(CHAR));
  342. szAnsiCounter = G_ALLOC(dwPathLength * 3 * sizeof(CHAR));
  343. szUnicodeCounter = G_ALLOC(dwPathLength * sizeof(WCHAR));
  344. if (szAnsiCounterPath == NULL || szUnicodeCounter == NULL
  345. || szAnsiCounter == NULL) {
  346. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  347. goto Cleanup;
  348. } else {
  349. PdhiBuildFullCounterPath((bNoMachine ? FALSE : TRUE),
  350. pCounter->pCounterPath,
  351. pCounter->pCounterPath->szObjectName,
  352. pCounter->pCounterPath->szCounterName,
  353. szUnicodeCounter);
  354. WideCharToMultiByte(_getmbcp(),
  355. 0,
  356. pCounter->szFullName,
  357. lstrlenW(pCounter->szFullName),
  358. szAnsiCounterPath,
  359. dwPathLength,
  360. NULL,
  361. NULL);
  362. WideCharToMultiByte(_getmbcp(),
  363. 0,
  364. szUnicodeCounter,
  365. lstrlenW(szUnicodeCounter),
  366. szAnsiCounter,
  367. dwPathLength,
  368. NULL,
  369. NULL);
  370. }
  371. szReturn = &szTemp[0]; // for starters
  372. // read the log file's header record
  373. pdhStatus = PdhiReadOneTextLogRecord (
  374. pLog,
  375. TEXTLOG_HEADER_RECORD,
  376. szReturn,
  377. 1); // we're lying to prevent copying the record.
  378. // what's in szReturn is not important since we'll be reading the
  379. // data from the "last Record read" buffer
  380. if (pLog->dwLastRecordRead == TEXTLOG_HEADER_RECORD) {
  381. cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ?
  382. COMMA_DELIMITER : TAB_DELIMITER);
  383. // then the seek worked and we can use the buffer
  384. dwBufferLength =
  385. lstrlenA((LPSTR)pLog->pLastRecordRead) + 1;
  386. szReturn = G_ALLOC (dwBufferLength * sizeof(CHAR));
  387. if (szReturn != NULL) {
  388. lstrcpyA (szReturn, (LPSTR)pLog->pLastRecordRead);
  389. dwIndex = 0;
  390. szThisItem = NULL;
  391. while ((dwItemLength = PdhiGetStringFromDelimitedListA(
  392. (LPSTR)pLog->pLastRecordRead,
  393. ++dwIndex,
  394. cDelim,
  395. PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT,
  396. szReturn,
  397. dwBufferLength)) != 0) {
  398. if (lstrcmpiA(szReturn, szAnsiCounterPath) == 0) {
  399. szThisItem = szReturn;
  400. break;
  401. }
  402. else if (lstrcmpiA(szReturn, szAnsiCounter) == 0) {
  403. // then this is the desired counter
  404. if (dwInstanceId < pCounter->pCounterPath->dwIndex) {
  405. dwInstanceId ++;
  406. }
  407. else {
  408. szThisItem = szReturn;
  409. break;
  410. }
  411. }
  412. }
  413. if (szThisItem != NULL) {
  414. if (bNoMachine) {
  415. pCounter->pCounterPath->szMachineName = NULL;
  416. }
  417. // this is a valid counter so update the fields
  418. // for Text logs, none of this info is used
  419. pCounter->plCounterInfo.dwObjectId = 0;
  420. pCounter->plCounterInfo.lInstanceId = dwInstanceId;
  421. pCounter->plCounterInfo.szInstanceName = NULL;
  422. pCounter->plCounterInfo.dwParentObjectId = 0;
  423. pCounter->plCounterInfo.szParentInstanceName = NULL;
  424. // this data is used by the log file readers
  425. pCounter->plCounterInfo.dwCounterId = dwIndex;
  426. pCounter->plCounterInfo.dwCounterType = PERF_DOUBLE_RAW;
  427. pCounter->plCounterInfo.dwCounterSize = 8;
  428. pdhStatus = ERROR_SUCCESS;
  429. } else {
  430. // counter not found
  431. pdhStatus = PDH_CSTATUS_NO_COUNTER;
  432. }
  433. G_FREE (szReturn);
  434. } else {
  435. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  436. }
  437. } else {
  438. // unable to read header from log file
  439. pdhStatus = PDH_UNABLE_READ_LOG_HEADER;
  440. }
  441. Cleanup:
  442. if (szAnsiCounterPath) G_FREE(szAnsiCounterPath);
  443. if (szAnsiCounter) G_FREE(szAnsiCounter);
  444. if (szUnicodeCounter) G_FREE(szUnicodeCounter);
  445. return pdhStatus;
  446. }
  447. PDH_FUNCTION
  448. PdhiOpenInputTextLog (
  449. IN PPDHI_LOG pLog
  450. )
  451. {
  452. PDH_STATUS pdhStatus;
  453. // open a stream handle for easy C RTL I/O
  454. pLog->StreamFile = _wfopen (pLog->szLogFileName, (LPCWSTR)L"rt");
  455. if (pLog->StreamFile == NULL ||
  456. pLog->StreamFile == (FILE *)((DWORD_PTR)(-1))) {
  457. pLog->StreamFile = (FILE *)((DWORD_PTR) (-1));
  458. pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
  459. } else {
  460. pdhStatus = ERROR_SUCCESS;
  461. }
  462. return pdhStatus;
  463. }
  464. PDH_FUNCTION
  465. PdhiOpenOutputTextLog (
  466. IN PPDHI_LOG pLog
  467. )
  468. {
  469. PDH_STATUS pdhStatus;
  470. pLog->StreamFile = (FILE *)((DWORD_PTR)(-1));
  471. pLog->dwRecord1Size = 0;
  472. pdhStatus = ERROR_SUCCESS;
  473. return pdhStatus;
  474. }
  475. PDH_FUNCTION
  476. PdhiCloseTextLog (
  477. IN PPDHI_LOG pLog,
  478. IN DWORD dwFlags
  479. )
  480. {
  481. PDH_STATUS pdhStatus;
  482. UNREFERENCED_PARAMETER (dwFlags);
  483. if (pLog->StreamFile != NULL &&
  484. pLog->StreamFile != (FILE *)((DWORD_PTR)(-1))) {
  485. fclose (pLog->StreamFile);
  486. pLog->StreamFile = (FILE *)((DWORD_PTR)(-1));
  487. }
  488. pdhStatus = ERROR_SUCCESS;
  489. return pdhStatus;
  490. }
  491. PDH_FUNCTION
  492. PdhiWriteTextLogHeader (
  493. IN PPDHI_LOG pLog,
  494. IN LPCWSTR szUserCaption
  495. )
  496. {
  497. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  498. PPDHI_COUNTER pThisCounter;
  499. CHAR cDelim;
  500. CHAR szLeadDelim[4];
  501. DWORD dwLeadSize;
  502. CHAR szTrailDelim[4];
  503. DWORD dwTrailSize;
  504. DWORD dwBytesWritten;
  505. LPSTR szCounterPath = NULL;
  506. LPWSTR wszCounterPath = NULL;
  507. LPSTR szLocalCaption = NULL;
  508. DWORD dwCaptionSize = 0;
  509. BOOL bDefaultCaption;
  510. LPSTR szOutputString = NULL;
  511. LPSTR szTmpString;
  512. DWORD dwStringBufferSize = 0;
  513. DWORD dwStringBufferUsed = 0;
  514. DWORD dwNewStringLen;
  515. szCounterPath = G_ALLOC(MEDIUM_BUFFER_SIZE * sizeof(CHAR));
  516. wszCounterPath = G_ALLOC(MEDIUM_BUFFER_SIZE * sizeof(WCHAR));
  517. szOutputString = G_ALLOC(MEDIUM_BUFFER_SIZE * sizeof(CHAR));
  518. if (szCounterPath == NULL || wszCounterPath == NULL
  519. || szOutputString == NULL) {
  520. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  521. goto Cleanup;
  522. }
  523. dwStringBufferSize = MEDIUM_BUFFER_SIZE;
  524. cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ? COMMA_DELIMITER :
  525. TAB_DELIMITER);
  526. szLeadDelim[0] = cDelim;
  527. szLeadDelim[1] = DOUBLE_QUOTE;
  528. szLeadDelim[2] = 0;
  529. szLeadDelim[3] = 0;
  530. dwLeadSize = 2 * sizeof(szLeadDelim[0]);
  531. szTrailDelim[0] = DOUBLE_QUOTE;
  532. szTrailDelim[1] = 0;
  533. szTrailDelim[2] = 0;
  534. szTrailDelim[3] = 0;
  535. dwTrailSize = 1 * sizeof(szTrailDelim[0]);
  536. // we'll assume the buffer allocated is large enough to hold the timestamp
  537. // and 1st counter name. After that we'll test the size first.
  538. lstrcpyA(szOutputString, szTrailDelim);
  539. lstrcatA(szOutputString,
  540. (LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV ?
  541. szCsvLogFileHeader : szTsvLogFileHeader));
  542. {
  543. // Add TimeZone information
  544. //
  545. DWORD dwReturn = GetTimeZoneInformation(&TimeZone);
  546. CHAR strTimeZone[MAX_PATH];
  547. if (dwReturn != TIME_ZONE_ID_INVALID) {
  548. if (dwReturn == TIME_ZONE_ID_DAYLIGHT) {
  549. sprintf(strTimeZone, " (%ws)(%d)",
  550. TimeZone.DaylightName,
  551. TimeZone.Bias + TimeZone.DaylightBias);
  552. }
  553. else {
  554. sprintf(strTimeZone, " (%ws)(%d)",
  555. TimeZone.StandardName,
  556. TimeZone.Bias + TimeZone.StandardBias);
  557. }
  558. lstrcatA(szOutputString, strTimeZone);
  559. pLog->dwRecord1Size = 1;
  560. }
  561. }
  562. lstrcatA(szOutputString, szTrailDelim);
  563. lstrlenA(szOutputString);
  564. // get buffer size here
  565. dwStringBufferUsed = lstrlenA(szOutputString);
  566. // check each counter in the list of counters for this query and
  567. // write them to the file
  568. // output the path names
  569. pThisCounter = pLog->pQuery ? pLog->pQuery->pCounterListHead : NULL;
  570. if (pThisCounter != NULL) {
  571. do {
  572. // get the counter path information from the counter
  573. ZeroMemory(wszCounterPath, sizeof(WCHAR) * MEDIUM_BUFFER_SIZE);
  574. ZeroMemory(szCounterPath, sizeof(CHAR) * MEDIUM_BUFFER_SIZE);
  575. PdhiBuildFullCounterPath(TRUE,
  576. pThisCounter->pCounterPath,
  577. pThisCounter->pCounterPath->szObjectName,
  578. pThisCounter->pCounterPath->szCounterName,
  579. wszCounterPath);
  580. WideCharToMultiByte(_getmbcp(),
  581. 0,
  582. wszCounterPath,
  583. lstrlenW(wszCounterPath),
  584. (LPSTR) szCounterPath,
  585. MEDIUM_BUFFER_SIZE,
  586. NULL,
  587. NULL);
  588. dwNewStringLen = lstrlenA(szCounterPath);
  589. dwNewStringLen += dwLeadSize;
  590. dwNewStringLen += dwTrailSize;
  591. if ((dwNewStringLen + dwStringBufferUsed) >= dwStringBufferSize) {
  592. dwStringBufferSize += SMALL_BUFFER_SIZE;
  593. szTmpString = szOutputString;
  594. szOutputString = G_REALLOC (szTmpString, dwStringBufferSize);
  595. if (szOutputString == NULL) {
  596. G_FREE(szTmpString);
  597. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  598. break; // out of DO loop
  599. }
  600. } else {
  601. // mem alloc ok, so continue
  602. }
  603. lstrcatA (szOutputString, szLeadDelim);
  604. if (pdhStatus == ERROR_SUCCESS) {
  605. lstrcatA (szOutputString, szCounterPath);
  606. } else {
  607. // just write the delimiters and no string inbetween
  608. }
  609. lstrcatA (szOutputString, szTrailDelim);
  610. dwStringBufferUsed += dwNewStringLen;
  611. pThisCounter = pThisCounter->next.flink; // go to next in list
  612. } while (pThisCounter != pLog->pQuery->pCounterListHead);
  613. }
  614. // test to see if the caller wants to append user strings to the log
  615. if (((pLog->dwLogFormat & PDH_LOG_OPT_MASK) == PDH_LOG_OPT_USER_STRING) &&
  616. (pdhStatus == ERROR_SUCCESS)) {
  617. // they want to write user data so see if they've passed in a
  618. // caption string
  619. if (szUserCaption != NULL) {
  620. dwCaptionSize = lstrlenW (szUserCaption) + 1;
  621. // allocate larger buffer to accomodate DBCS characters
  622. dwCaptionSize = dwCaptionSize * 3 * sizeof (CHAR);
  623. szLocalCaption = (LPSTR) G_ALLOC (dwCaptionSize);
  624. if (szLocalCaption != NULL) {
  625. memset(szLocalCaption, 0, dwCaptionSize);
  626. dwCaptionSize = WideCharToMultiByte(
  627. _getmbcp(),
  628. 0,
  629. szUserCaption,
  630. lstrlenW(szUserCaption),
  631. szLocalCaption,
  632. dwCaptionSize,
  633. NULL,
  634. NULL);
  635. bDefaultCaption = FALSE;
  636. } else {
  637. bDefaultCaption = TRUE;
  638. }
  639. } else {
  640. bDefaultCaption = TRUE;
  641. }
  642. if (bDefaultCaption) {
  643. szLocalCaption = (LPSTR)caszDefaultLogCaption;
  644. dwCaptionSize = lstrlenA (szLocalCaption);
  645. }
  646. dwNewStringLen = (DWORD)dwCaptionSize;
  647. dwNewStringLen += dwLeadSize;
  648. dwNewStringLen += dwTrailSize;
  649. if ((dwNewStringLen + dwStringBufferUsed) >= dwStringBufferSize) {
  650. dwStringBufferSize += SMALL_BUFFER_SIZE;
  651. szTmpString = szOutputString;
  652. szOutputString = G_REALLOC (szTmpString, dwStringBufferSize);
  653. if (szOutputString == NULL) {
  654. G_FREE(szTmpString);
  655. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  656. }
  657. } else {
  658. // mem alloc ok, so continue
  659. }
  660. if (pdhStatus == ERROR_SUCCESS) {
  661. lstrcatA (szOutputString, szLeadDelim);
  662. #pragma warning (disable : 4701 ) // szLocalCaption is initialized above
  663. lstrcatA (szOutputString, szLocalCaption);
  664. #pragma warning (default : 4701)
  665. lstrcatA (szOutputString, szTrailDelim);
  666. }
  667. dwStringBufferUsed += dwNewStringLen;
  668. if (!bDefaultCaption) {
  669. G_FREE (szLocalCaption);
  670. }
  671. }
  672. if (pdhStatus == ERROR_SUCCESS) {
  673. if ((PdhidwRecordTerminatorLength + dwStringBufferUsed) >= dwStringBufferSize) {
  674. dwStringBufferSize += PdhidwRecordTerminatorLength;
  675. szTmpString = szOutputString;
  676. szOutputString = G_REALLOC (szTmpString, dwStringBufferSize);
  677. if (szOutputString == NULL) {
  678. G_FREE(szTmpString);
  679. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  680. }
  681. } else {
  682. // mem alloc ok, so continue
  683. }
  684. if (pdhStatus == ERROR_SUCCESS) {
  685. lstrcatA (szOutputString, PdhiszRecordTerminator);
  686. dwStringBufferUsed += PdhidwRecordTerminatorLength;
  687. // write the record
  688. if (!WriteFile (pLog->hLogFileHandle,
  689. (LPCVOID)szOutputString,
  690. dwStringBufferUsed,
  691. &dwBytesWritten,
  692. NULL)) {
  693. pdhStatus = GetLastError();
  694. } else if (pLog->pQuery->hLog == H_REALTIME_DATASOURCE || pLog->pQuery->hLog == H_WBEM_DATASOURCE) {
  695. FlushFileBuffers(pLog->hLogFileHandle);
  696. }
  697. if (dwStringBufferUsed > pLog->dwMaxRecordSize) {
  698. // then update the buffer size
  699. pLog->dwMaxRecordSize = dwStringBufferUsed;
  700. }
  701. }
  702. }
  703. Cleanup:
  704. if (szCounterPath != NULL) G_FREE(szCounterPath);
  705. if (wszCounterPath != NULL) G_FREE(wszCounterPath);
  706. if (szOutputString != NULL) G_FREE(szOutputString);
  707. return pdhStatus;
  708. }
  709. PDH_FUNCTION
  710. PdhiWriteTextLogRecord (
  711. IN PPDHI_LOG pLog,
  712. IN SYSTEMTIME *stTimeStamp,
  713. IN LPCWSTR szUserString
  714. )
  715. {
  716. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  717. PPDHI_COUNTER pThisCounter;
  718. CHAR cDelim;
  719. DWORD dwBytesWritten;
  720. DWORD dwBufferSize;
  721. CHAR szValueBuffer[VALUE_BUFFER_SIZE];
  722. PDH_FMT_COUNTERVALUE pdhValue;
  723. DWORD dwUserStringSize;
  724. LPSTR szLocalUserString = NULL;
  725. BOOL bDefaultUserString;
  726. LPSTR szOutputString = NULL;
  727. DWORD dwStringBufferSize = 0;
  728. DWORD dwStringBufferUsed = 0;
  729. DWORD dwNewStringLen;
  730. SYSTEMTIME lstTimeStamp;
  731. LARGE_INTEGER liFileSize;
  732. dwStringBufferSize = (MEDIUM_BUFFER_SIZE > pLog->dwMaxRecordSize ?
  733. MEDIUM_BUFFER_SIZE : pLog->dwMaxRecordSize);
  734. szOutputString = G_ALLOC (dwStringBufferSize);
  735. if (szOutputString == NULL) {
  736. return PDH_MEMORY_ALLOCATION_FAILURE;
  737. }
  738. cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ? COMMA_DELIMITER :
  739. TAB_DELIMITER);
  740. // format and write the time stamp title
  741. lstTimeStamp = * stTimeStamp;
  742. dwStringBufferUsed = sprintf (szOutputString, PdhiszFmtTimeStamp,
  743. lstTimeStamp.wMonth, lstTimeStamp.wDay, lstTimeStamp.wYear,
  744. lstTimeStamp.wHour, lstTimeStamp.wMinute, lstTimeStamp.wSecond,
  745. lstTimeStamp.wMilliseconds);
  746. // check each counter in the list of counters for this query and
  747. // write them to the file
  748. pThisCounter = pLog->pQuery ? pLog->pQuery->pCounterListHead : NULL;
  749. if (pThisCounter != NULL) {
  750. // lock the query while we read the data so the values
  751. // written to the log will all be from the same sample
  752. pdhStatus = WAIT_FOR_AND_LOCK_MUTEX(pThisCounter->pOwner->hMutex);
  753. if (pdhStatus == ERROR_SUCCESS) {
  754. do {
  755. // get the formatted value from the counter
  756. // compute and format current value
  757. pdhStatus = PdhiComputeFormattedValue (
  758. pThisCounter->CalcFunc,
  759. pThisCounter->plCounterInfo.dwCounterType,
  760. pThisCounter->lScale,
  761. PDH_FMT_DOUBLE | PDH_FMT_NOCAP100,
  762. &pThisCounter->ThisValue,
  763. &pThisCounter->LastValue,
  764. &pThisCounter->TimeBase,
  765. 0L,
  766. &pdhValue);
  767. if ((pdhStatus == ERROR_SUCCESS) &&
  768. ((pdhValue.CStatus == PDH_CSTATUS_VALID_DATA) ||
  769. (pdhValue.CStatus == PDH_CSTATUS_NEW_DATA))) {
  770. // then this is a valid data value so print it
  771. dwBufferSize = sprintf (szValueBuffer,
  772. PdhiszFmtRealValue, cDelim, pdhValue.doubleValue);
  773. } else {
  774. // invalid data so show a blank data value
  775. dwBufferSize = sprintf (szValueBuffer, PdhiszFmtStringValue, cDelim, caszSpace);
  776. // reset error
  777. pdhStatus = ERROR_SUCCESS;
  778. }
  779. dwNewStringLen = dwBufferSize;
  780. if ((dwNewStringLen+dwStringBufferUsed) >= dwStringBufferSize) {
  781. LPTSTR szNewString;
  782. dwStringBufferSize += SMALL_BUFFER_SIZE;
  783. szNewString = G_REALLOC (szOutputString, dwStringBufferSize);
  784. if (szNewString == NULL) {
  785. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  786. break; // out of DO loop
  787. }
  788. else {
  789. szOutputString = szNewString;
  790. }
  791. }
  792. if (pdhStatus != PDH_MEMORY_ALLOCATION_FAILURE) {
  793. lstrcatA (szOutputString, szValueBuffer);
  794. dwStringBufferUsed += dwNewStringLen;
  795. }
  796. // goto the next counter in the list
  797. pThisCounter = pThisCounter->next.flink; // go to next in list
  798. } while (pThisCounter != pLog->pQuery->pCounterListHead);
  799. // free (i.e. unlock) the query
  800. RELEASE_MUTEX(pThisCounter->pOwner->hMutex);
  801. }
  802. }
  803. if (pdhStatus == PDH_MEMORY_ALLOCATION_FAILURE) // cannot go further
  804. goto endLogText;
  805. // test to see if the caller wants to append user strings to the log
  806. if ((pLog->dwLogFormat & PDH_LOG_OPT_MASK) == PDH_LOG_OPT_USER_STRING) {
  807. // they want to write user data so see if they've passed in a
  808. // display string
  809. if (szUserString != NULL) {
  810. // get size in chars
  811. dwUserStringSize = lstrlenW (szUserString) + 1;
  812. // allocate larger buffer to accomodate DBCS characters
  813. dwUserStringSize = dwUserStringSize * 3 * sizeof(CHAR);
  814. szLocalUserString = (LPSTR) G_ALLOC (dwUserStringSize);
  815. if (szLocalUserString != NULL) {
  816. memset(szLocalUserString, 0, dwUserStringSize);
  817. dwUserStringSize = WideCharToMultiByte(
  818. _getmbcp(),
  819. 0,
  820. szUserString,
  821. lstrlenW(szUserString),
  822. szLocalUserString,
  823. dwUserStringSize,
  824. NULL,
  825. NULL);
  826. bDefaultUserString = FALSE;
  827. } else {
  828. bDefaultUserString = TRUE;
  829. }
  830. } else {
  831. bDefaultUserString = TRUE;
  832. }
  833. if (bDefaultUserString) {
  834. szLocalUserString = (LPSTR)caszSpace;
  835. dwUserStringSize = lstrlenA (szLocalUserString);
  836. }
  837. #pragma warning (disable : 4701) // szLocalUserString is init'd above
  838. dwBufferSize = sprintf (szValueBuffer,
  839. PdhiszFmtStringValue, cDelim, szLocalUserString);
  840. #pragma warning (default : 4701)
  841. dwNewStringLen = dwBufferSize;
  842. if ((dwNewStringLen + dwStringBufferUsed) >= dwStringBufferSize) {
  843. LPTSTR szNewString;
  844. dwStringBufferSize += SMALL_BUFFER_SIZE;
  845. szNewString = G_REALLOC (szOutputString, dwStringBufferSize);
  846. if (szNewString == NULL) {
  847. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  848. }
  849. else {
  850. szOutputString = szNewString;
  851. }
  852. }
  853. if (pdhStatus != PDH_MEMORY_ALLOCATION_FAILURE) {
  854. lstrcatA (szOutputString, szValueBuffer);
  855. dwStringBufferUsed += dwNewStringLen;
  856. }
  857. if (!bDefaultUserString) {
  858. G_FREE (szLocalUserString);
  859. }
  860. }
  861. if (pdhStatus == PDH_MEMORY_ALLOCATION_FAILURE)
  862. goto endLogText;
  863. if ((PdhidwRecordTerminatorLength + dwStringBufferUsed) >= dwStringBufferSize) {
  864. LPTSTR szNewString;
  865. dwStringBufferSize += PdhidwRecordTerminatorLength;
  866. szNewString = G_REALLOC (szOutputString, dwStringBufferSize);
  867. if (szNewString == NULL) {
  868. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  869. }
  870. else {
  871. szOutputString = szNewString;
  872. }
  873. }
  874. if (pdhStatus == ERROR_SUCCESS) {
  875. lstrcatA (szOutputString, PdhiszRecordTerminator);
  876. dwStringBufferUsed += PdhidwRecordTerminatorLength;
  877. liFileSize.LowPart = GetFileSize (
  878. pLog->hLogFileHandle,
  879. (LPDWORD)&liFileSize.HighPart);
  880. // add in new record to see if it will fit.
  881. liFileSize.QuadPart += dwStringBufferUsed;
  882. // test for maximum allowable filesize
  883. if (liFileSize.QuadPart <= MAX_TEXT_FILE_SIZE) {
  884. // write the record terminator
  885. if (!WriteFile (pLog->hLogFileHandle,
  886. (LPCVOID)szOutputString,
  887. dwStringBufferUsed,
  888. &dwBytesWritten,
  889. NULL)) {
  890. pdhStatus = GetLastError ();
  891. } else if (pLog->pQuery->hLog == H_REALTIME_DATASOURCE || pLog->pQuery->hLog == H_WBEM_DATASOURCE) {
  892. FlushFileBuffers(pLog->hLogFileHandle);
  893. }
  894. } else {
  895. pdhStatus = ERROR_LOG_FILE_FULL;
  896. }
  897. if (dwStringBufferUsed> pLog->dwMaxRecordSize) {
  898. // then update the buffer size
  899. pLog->dwMaxRecordSize = dwStringBufferUsed;
  900. }
  901. }
  902. endLogText:
  903. G_FREE (szOutputString);
  904. return pdhStatus;
  905. }
  906. PDH_FUNCTION
  907. PdhiEnumMachinesFromTextLog (
  908. PPDHI_LOG pLog,
  909. LPVOID pBuffer,
  910. LPDWORD lpdwBufferSize,
  911. BOOL bUnicodeDest
  912. )
  913. {
  914. PDH_STATUS pdhStatus;
  915. PDH_STATUS pdhBuffStatus = ERROR_SUCCESS;
  916. LPSTR szBuffer;
  917. CHAR szTemp[4];
  918. CHAR cDelim;
  919. PPDH_COUNTER_PATH_ELEMENTS_A pInfo;
  920. DWORD dwInfoBufferSize;
  921. DWORD dwBufferUsed;
  922. DWORD dwNewBuffer;
  923. DWORD dwIndex;
  924. DWORD dwItemLength;
  925. DWORD dwBufferLength;
  926. DWORD dwItemCount = 0;
  927. LPVOID LocalBuffer = NULL;
  928. LPVOID TempBuffer;
  929. DWORD LocalBufferSize = 0;
  930. LocalBuffer = G_ALLOC(MEDIUM_BUFFER_SIZE);
  931. if (LocalBuffer == NULL) {
  932. return PDH_MEMORY_ALLOCATION_FAILURE;
  933. }
  934. LocalBufferSize = MEDIUM_BUFFER_SIZE;
  935. memset(LocalBuffer, 0, MEDIUM_BUFFER_SIZE);
  936. if (pBuffer) {
  937. memset(pBuffer, 0, * lpdwBufferSize);
  938. }
  939. pInfo = (PPDH_COUNTER_PATH_ELEMENTS_A) G_ALLOC (MEDIUM_BUFFER_SIZE);
  940. if (pInfo == NULL) {
  941. G_FREE(LocalBuffer);
  942. return PDH_MEMORY_ALLOCATION_FAILURE;
  943. }
  944. szBuffer = &szTemp[0];
  945. // what's in szReturn is not important since we'll be reading the
  946. // data from the "last Record read" buffer
  947. pdhStatus = PdhiReadOneTextLogRecord (
  948. pLog,
  949. TEXTLOG_HEADER_RECORD,
  950. szBuffer,
  951. 1); // we're lying to prevent copying the record.
  952. if (pLog->dwLastRecordRead == TEXTLOG_HEADER_RECORD) {
  953. // then the seek worked and we can use the buffer
  954. cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ?
  955. COMMA_DELIMITER : TAB_DELIMITER);
  956. dwBufferLength = lstrlenA((LPSTR)pLog->pLastRecordRead)+1;
  957. szBuffer = G_ALLOC (dwBufferLength);
  958. if (szBuffer != NULL) {
  959. dwBufferUsed = 0;
  960. dwIndex = 0;
  961. while ((dwItemLength = PdhiGetStringFromDelimitedListA(
  962. (LPSTR)pLog->pLastRecordRead,
  963. ++dwIndex,
  964. cDelim,
  965. PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT,
  966. szBuffer,
  967. dwBufferLength)) != 0) {
  968. if (dwItemLength > 0) {
  969. dwInfoBufferSize = MEDIUM_BUFFER_SIZE;
  970. // parse the path, pull the machine name out and
  971. memset(pInfo, 0, MEDIUM_BUFFER_SIZE);
  972. pdhStatus = PdhParseCounterPathA (
  973. szBuffer,
  974. pInfo,
  975. &dwInfoBufferSize,
  976. 0);
  977. if (pdhStatus == ERROR_SUCCESS) {
  978. if (szBuffer[1] != '\\') {
  979. pInfo->szMachineName[0] = '.';
  980. pInfo->szMachineName[1] = '\0';
  981. }
  982. // add it to the list if it will fit
  983. if (pInfo->szMachineName != NULL) {
  984. // include sizeof delimiter char
  985. dwNewBuffer = (lstrlenA (pInfo->szMachineName) + 1) *
  986. (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR));
  987. while ( LocalBufferSize
  988. < (dwBufferUsed + dwNewBuffer)) {
  989. TempBuffer = LocalBuffer;
  990. LocalBuffer = G_REALLOC(TempBuffer,
  991. LocalBufferSize + MEDIUM_BUFFER_SIZE);
  992. if (LocalBuffer == NULL) {
  993. G_FREE(szBuffer);
  994. G_FREE(TempBuffer);
  995. G_FREE(pInfo);
  996. return PDH_MEMORY_ALLOCATION_FAILURE;
  997. }
  998. LocalBufferSize += MEDIUM_BUFFER_SIZE;
  999. }
  1000. dwNewBuffer = AddUniqueStringToMultiSz (
  1001. (LPVOID) LocalBuffer,
  1002. pInfo->szMachineName,
  1003. bUnicodeDest);
  1004. } else {
  1005. dwNewBuffer = 0;
  1006. }
  1007. if (dwNewBuffer > 0) {
  1008. // string was added so update size used.
  1009. dwBufferUsed = dwNewBuffer
  1010. * (bUnicodeDest ? sizeof(WCHAR)
  1011. : sizeof(CHAR));
  1012. dwItemCount++;
  1013. }
  1014. }
  1015. }
  1016. }
  1017. if (dwItemCount > 0) {
  1018. // then the routine was successful. Errors that occurred
  1019. // while scanning will be ignored as long as at least
  1020. // one entry was successfully read
  1021. pdhStatus = pdhBuffStatus;
  1022. }
  1023. // update the buffer used or required.
  1024. if (pBuffer && dwBufferUsed <= * lpdwBufferSize) {
  1025. RtlCopyMemory(pBuffer, LocalBuffer, dwBufferUsed);
  1026. }
  1027. else {
  1028. if (pBuffer)
  1029. RtlCopyMemory(pBuffer, LocalBuffer, * lpdwBufferSize);
  1030. dwBufferUsed += (bUnicodeDest) ? sizeof(WCHAR) : sizeof(CHAR);
  1031. pdhStatus = PDH_MORE_DATA;
  1032. }
  1033. *lpdwBufferSize = dwBufferUsed;
  1034. G_FREE (szBuffer);
  1035. } else {
  1036. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  1037. }
  1038. } else {
  1039. // unable to read header record
  1040. pdhStatus = PDH_UNABLE_READ_LOG_HEADER;
  1041. }
  1042. G_FREE (pInfo);
  1043. G_FREE(LocalBuffer);
  1044. return pdhStatus;
  1045. }
  1046. PDH_FUNCTION
  1047. PdhiEnumObjectsFromTextLog (
  1048. IN PPDHI_LOG pLog,
  1049. IN LPCWSTR szMachineName,
  1050. IN LPVOID pBuffer,
  1051. IN LPDWORD pcchBufferSize,
  1052. IN DWORD dwDetailLevel,
  1053. IN BOOL bUnicodeDest
  1054. )
  1055. {
  1056. PDH_STATUS pdhStatus;
  1057. PDH_STATUS pdhBuffStatus = ERROR_SUCCESS;
  1058. LPSTR szBuffer;
  1059. CHAR szTemp[4];
  1060. CHAR cDelim;
  1061. PPDH_COUNTER_PATH_ELEMENTS_A pInfo;
  1062. DWORD dwInfoBufferSize;
  1063. DWORD dwBufferUsed;
  1064. DWORD dwNewBuffer;
  1065. DWORD dwIndex;
  1066. DWORD dwItemLength;
  1067. DWORD dwBufferLength;
  1068. WCHAR wszMachineName[MAX_PATH];
  1069. DWORD dwMachineNameLength;
  1070. DWORD dwItemCount = 0;
  1071. LPVOID LocalBuffer = NULL;
  1072. LPVOID TempBuffer;
  1073. DWORD LocalBufferSize = 0;
  1074. UNREFERENCED_PARAMETER (dwDetailLevel);
  1075. pInfo = (PPDH_COUNTER_PATH_ELEMENTS_A) G_ALLOC (MEDIUM_BUFFER_SIZE);
  1076. if (pInfo == NULL) {
  1077. return PDH_MEMORY_ALLOCATION_FAILURE;
  1078. }
  1079. szBuffer = &szTemp[0];
  1080. LocalBuffer = G_ALLOC(MEDIUM_BUFFER_SIZE);
  1081. if (LocalBuffer == NULL) {
  1082. G_FREE(pInfo);
  1083. return PDH_MEMORY_ALLOCATION_FAILURE;
  1084. }
  1085. memset(LocalBuffer, 0, MEDIUM_BUFFER_SIZE);
  1086. LocalBufferSize = MEDIUM_BUFFER_SIZE;
  1087. if (pBuffer) {
  1088. memset(pBuffer, 0, * pcchBufferSize);
  1089. }
  1090. // what's in szReturn is not important since we'll be reading the
  1091. // data from the "last Record read" buffer
  1092. pdhStatus = PdhiReadOneTextLogRecord (
  1093. pLog,
  1094. TEXTLOG_HEADER_RECORD,
  1095. szBuffer,
  1096. 1); // we're lying to prevent copying the record.
  1097. if (pLog->dwLastRecordRead == TEXTLOG_HEADER_RECORD) {
  1098. // then the seek worked and we can use the buffer
  1099. cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ?
  1100. COMMA_DELIMITER : TAB_DELIMITER);
  1101. dwBufferLength = lstrlenA((LPSTR)pLog->pLastRecordRead)+1;
  1102. szBuffer = G_ALLOC (dwBufferLength);
  1103. if (szBuffer != NULL) {
  1104. dwBufferUsed = 0;
  1105. dwIndex = 0;
  1106. while ((dwItemLength = PdhiGetStringFromDelimitedListA(
  1107. (LPSTR)pLog->pLastRecordRead,
  1108. ++dwIndex,
  1109. cDelim,
  1110. PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT,
  1111. szBuffer,
  1112. dwBufferLength)) != 0) {
  1113. if (dwItemLength > 0) {
  1114. dwInfoBufferSize = MEDIUM_BUFFER_SIZE;
  1115. // parse the path, pull the machine name out and
  1116. memset(pInfo, 0, MEDIUM_BUFFER_SIZE);
  1117. pdhStatus = PdhParseCounterPathA (
  1118. szBuffer,
  1119. pInfo,
  1120. &dwInfoBufferSize,
  1121. 0);
  1122. if (pdhStatus == ERROR_SUCCESS) {
  1123. if (szBuffer[1] != '\\') {
  1124. pInfo->szMachineName[0] = '.';
  1125. pInfo->szMachineName[1] = '\0';
  1126. }
  1127. // add it to the list if it will fit and it's from
  1128. // the desired machine
  1129. memset(wszMachineName, 0, sizeof(WCHAR) * MAX_PATH);
  1130. dwMachineNameLength = MAX_PATH;
  1131. MultiByteToWideChar(_getmbcp(),
  1132. 0,
  1133. pInfo->szMachineName,
  1134. lstrlenA(pInfo->szMachineName),
  1135. (LPWSTR) wszMachineName,
  1136. dwMachineNameLength);
  1137. if (lstrcmpiW(szMachineName, wszMachineName) == 0) {
  1138. dwNewBuffer = (lstrlenA (pInfo->szObjectName) + 1) *
  1139. (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR));
  1140. while ( LocalBufferSize
  1141. < (dwBufferUsed + dwNewBuffer)) {
  1142. TempBuffer = LocalBuffer;
  1143. LocalBuffer = G_REALLOC(TempBuffer,
  1144. LocalBufferSize + MEDIUM_BUFFER_SIZE);
  1145. if (LocalBuffer == NULL) {
  1146. G_FREE(szBuffer);
  1147. G_FREE(TempBuffer);
  1148. G_FREE(pInfo);
  1149. return PDH_MEMORY_ALLOCATION_FAILURE;
  1150. }
  1151. LocalBufferSize += MEDIUM_BUFFER_SIZE;
  1152. }
  1153. dwNewBuffer = AddUniqueStringToMultiSz (
  1154. (LPVOID) LocalBuffer,
  1155. pInfo->szObjectName,
  1156. bUnicodeDest);
  1157. if (dwNewBuffer > 0) {
  1158. // string was added so update size used.
  1159. dwBufferUsed = dwNewBuffer
  1160. * (bUnicodeDest ? sizeof(WCHAR)
  1161. : sizeof(CHAR));
  1162. dwItemCount++;
  1163. }
  1164. }
  1165. }
  1166. }
  1167. }
  1168. if (dwItemCount > 0) {
  1169. // then the routine was successful. Errors that occurred
  1170. // while scanning will be ignored as long as at least
  1171. // one entry was successfully read
  1172. pdhStatus = pdhBuffStatus;
  1173. }
  1174. // copy buffer size used or required
  1175. if (pBuffer && dwBufferUsed <= * pcchBufferSize) {
  1176. RtlCopyMemory(pBuffer, LocalBuffer, dwBufferUsed);
  1177. }
  1178. else {
  1179. if (pBuffer)
  1180. RtlCopyMemory(pBuffer, LocalBuffer, * pcchBufferSize);
  1181. dwBufferUsed += (bUnicodeDest) ? sizeof(WCHAR) : sizeof(CHAR);
  1182. pdhStatus = PDH_MORE_DATA;
  1183. }
  1184. * pcchBufferSize = dwBufferUsed;
  1185. G_FREE (szBuffer);
  1186. } else {
  1187. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  1188. }
  1189. }
  1190. G_FREE (pInfo);
  1191. G_FREE(LocalBuffer);
  1192. return pdhStatus;
  1193. }
  1194. ULONG HashCounter(
  1195. LPWSTR szCounterName
  1196. )
  1197. {
  1198. ULONG h = 0;
  1199. ULONG a = 31415; //a, b, k are primes
  1200. const ULONG k = 16381;
  1201. const ULONG b = 27183;
  1202. LPWSTR szThisChar;
  1203. if (szCounterName) {
  1204. for (szThisChar = szCounterName; * szThisChar; szThisChar ++) {
  1205. h = (a * h + ((ULONG) (* szThisChar))) % k;
  1206. a = a * b % (k - 1);
  1207. }
  1208. }
  1209. return (h % HASH_TABLE_SIZE);
  1210. }
  1211. void
  1212. PdhiInitCounterHashTable(
  1213. IN PDHI_COUNTER_TABLE pTable
  1214. )
  1215. {
  1216. ZeroMemory(pTable, sizeof(PDHI_COUNTER_TABLE));
  1217. }
  1218. void
  1219. PdhiResetInstanceCount(
  1220. IN PDHI_COUNTER_TABLE pTable
  1221. )
  1222. {
  1223. PLIST_ENTRY pHeadInst;
  1224. PLIST_ENTRY pNextInst;
  1225. PPDHI_INSTANCE pInstance;
  1226. PPDHI_INST_LIST pInstList;
  1227. DWORD i;
  1228. for (i = 0; i < HASH_TABLE_SIZE; i ++) {
  1229. pInstList = pTable[i];
  1230. while (pInstList != NULL) {
  1231. if (! IsListEmpty(& pInstList->InstList)) {
  1232. pHeadInst = & pInstList->InstList;
  1233. pNextInst = pHeadInst->Flink;
  1234. while (pNextInst != pHeadInst) {
  1235. pInstance = CONTAINING_RECORD(
  1236. pNextInst, PDHI_INSTANCE, Entry);
  1237. pInstance->dwCount = 0;
  1238. pNextInst = pNextInst->Flink;
  1239. }
  1240. }
  1241. pInstList = pInstList->pNext;
  1242. }
  1243. }
  1244. }
  1245. PDH_FUNCTION
  1246. PdhiFindCounterInstList(
  1247. IN PDHI_COUNTER_TABLE pHeadList,
  1248. IN LPWSTR szCounter,
  1249. OUT PPDHI_INST_LIST * pInstList
  1250. )
  1251. {
  1252. PDH_STATUS Status = ERROR_SUCCESS;
  1253. ULONG lIndex = HashCounter(szCounter);
  1254. PPDHI_INST_LIST pLocalList = pHeadList[lIndex];
  1255. PPDHI_INST_LIST pRtnList = NULL;
  1256. * pInstList = NULL;
  1257. while (pLocalList != NULL) {
  1258. if (lstrcmpiW(pLocalList->szCounter, szCounter) == 0) {
  1259. pRtnList = pLocalList;
  1260. break;
  1261. }
  1262. pLocalList = pLocalList->pNext;
  1263. }
  1264. if (pRtnList == NULL) {
  1265. pRtnList = G_ALLOC(sizeof(PDHI_INST_LIST) +
  1266. sizeof(WCHAR) * (lstrlenW(szCounter) + 1));
  1267. if (pRtnList == NULL) {
  1268. Status = PDH_MEMORY_ALLOCATION_FAILURE;
  1269. goto Cleanup;
  1270. }
  1271. pRtnList->szCounter = (LPWSTR)
  1272. (((LPBYTE) pRtnList) + sizeof(PDHI_INST_LIST));
  1273. lstrcpyW(pRtnList->szCounter, szCounter);
  1274. InitializeListHead(& pRtnList->InstList);
  1275. pRtnList->pNext = pHeadList[lIndex];
  1276. pHeadList[lIndex] = pRtnList;
  1277. }
  1278. Cleanup:
  1279. if (Status == ERROR_SUCCESS) {
  1280. * pInstList = pRtnList;
  1281. }
  1282. return Status;
  1283. }
  1284. PDH_FUNCTION
  1285. PdhiFindInstance(
  1286. IN PLIST_ENTRY pHeadInst,
  1287. IN LPWSTR szInstance,
  1288. IN BOOLEAN bUpdateCount,
  1289. OUT PPDHI_INSTANCE * pInstance
  1290. )
  1291. {
  1292. PDH_STATUS Status = ERROR_SUCCESS;
  1293. PLIST_ENTRY pNextInst;
  1294. PPDHI_INSTANCE pLocalInst;
  1295. PPDHI_INSTANCE pRtnInst = NULL;
  1296. * pInstance = NULL;
  1297. if (! IsListEmpty(pHeadInst)) {
  1298. pNextInst = pHeadInst->Flink;
  1299. while (pNextInst != pHeadInst) {
  1300. pLocalInst = CONTAINING_RECORD(pNextInst, PDHI_INSTANCE, Entry);
  1301. if (lstrcmpiW(pLocalInst->szInstance, szInstance) == 0) {
  1302. pRtnInst = pLocalInst;
  1303. break;
  1304. }
  1305. pNextInst = pNextInst->Flink;
  1306. }
  1307. }
  1308. if (pRtnInst == NULL) {
  1309. pRtnInst = G_ALLOC(sizeof(PDHI_INSTANCE) +
  1310. sizeof(WCHAR) * (lstrlenW(szInstance) + 1));
  1311. if (pRtnInst == NULL) {
  1312. Status = PDH_MEMORY_ALLOCATION_FAILURE;
  1313. goto Cleanup;
  1314. }
  1315. pRtnInst->szInstance = (LPWSTR)
  1316. (((LPBYTE) pRtnInst) + sizeof(PDHI_INSTANCE));
  1317. lstrcpyW(pRtnInst->szInstance, szInstance);
  1318. pRtnInst->dwCount = pRtnInst->dwTotal = 0;
  1319. InsertTailList(pHeadInst, & pRtnInst->Entry);
  1320. }
  1321. if (bUpdateCount) {
  1322. pRtnInst->dwCount ++;
  1323. if (pRtnInst->dwCount > pRtnInst->dwTotal) {
  1324. pRtnInst->dwTotal = pRtnInst->dwCount;
  1325. }
  1326. }
  1327. else if (pRtnInst->dwCount == 0) {
  1328. pRtnInst->dwCount = pRtnInst->dwTotal = 1;
  1329. }
  1330. Cleanup:
  1331. if (Status == ERROR_SUCCESS) {
  1332. * pInstance = pRtnInst;
  1333. }
  1334. return Status;
  1335. }
  1336. DWORD
  1337. AddStringToMultiSz(
  1338. IN LPVOID mszDest,
  1339. IN LPWSTR szSource,
  1340. IN BOOL bUnicodeDest
  1341. )
  1342. {
  1343. LPVOID szDestElem;
  1344. DWORD dwReturnLength;
  1345. LPSTR aszSource = NULL;
  1346. DWORD dwLength;
  1347. if ((mszDest == NULL) || (szSource == NULL)
  1348. || (* szSource == L'\0')) {
  1349. return 0;
  1350. }
  1351. if (!bUnicodeDest) {
  1352. dwLength = lstrlenW(szSource) + 1;
  1353. aszSource = G_ALLOC(dwLength * 3 * sizeof(CHAR));
  1354. if (aszSource != NULL) {
  1355. WideCharToMultiByte(_getmbcp(),
  1356. 0,
  1357. szSource,
  1358. lstrlenW(szSource),
  1359. aszSource,
  1360. dwLength,
  1361. NULL,
  1362. NULL);
  1363. dwReturnLength = 1;
  1364. }
  1365. else {
  1366. dwReturnLength = 0;
  1367. }
  1368. }
  1369. else {
  1370. dwReturnLength = 1;
  1371. }
  1372. if (dwReturnLength > 0) {
  1373. for (szDestElem = mszDest;
  1374. (bUnicodeDest ? (* (LPWSTR) szDestElem != L'\0')
  1375. : (* (LPSTR) szDestElem != '\0'));
  1376. ) {
  1377. if (bUnicodeDest) {
  1378. szDestElem = (LPVOID) ((LPWSTR) szDestElem
  1379. + (lstrlenW((LPCWSTR) szDestElem) + 1));
  1380. }
  1381. else {
  1382. szDestElem = (LPVOID) ((LPSTR) szDestElem
  1383. + (lstrlenA((LPCSTR) szDestElem) + 1));
  1384. }
  1385. }
  1386. if (bUnicodeDest) {
  1387. lstrcpyW ((LPWSTR)szDestElem, szSource);
  1388. szDestElem = (LPVOID)((LPWSTR)szDestElem + lstrlenW(szSource) + 1);
  1389. * ((LPWSTR)szDestElem) = L'\0';
  1390. dwReturnLength = (DWORD)((LPWSTR)szDestElem - (LPWSTR)mszDest);
  1391. }
  1392. else {
  1393. lstrcpyA ((LPSTR)szDestElem, aszSource);
  1394. szDestElem = (LPVOID)((LPSTR)szDestElem + lstrlenA(szDestElem) + 1);
  1395. * ((LPSTR)szDestElem) = '\0';
  1396. dwReturnLength = (DWORD)((LPSTR)szDestElem - (LPSTR)mszDest);
  1397. }
  1398. }
  1399. if (aszSource != NULL) {
  1400. G_FREE (aszSource);
  1401. }
  1402. return (DWORD) dwReturnLength;
  1403. }
  1404. PDH_FUNCTION
  1405. PdhiEnumObjectItemsFromTextLog (
  1406. IN PPDHI_LOG pLog,
  1407. IN LPCWSTR szMachineName,
  1408. IN LPCWSTR szObjectName,
  1409. IN PDHI_COUNTER_TABLE CounterTable,
  1410. IN DWORD dwDetailLevel,
  1411. IN DWORD dwFlags
  1412. )
  1413. {
  1414. PDH_STATUS pdhStatus;
  1415. PDH_STATUS pdhBuffStatus = ERROR_SUCCESS;
  1416. LPSTR szBuffer;
  1417. CHAR szTemp[4];
  1418. CHAR cDelim;
  1419. PPDH_COUNTER_PATH_ELEMENTS_A pInfo = NULL;
  1420. DWORD dwInfoBufferSize;
  1421. DWORD dwIndex;
  1422. DWORD dwItemLength;
  1423. DWORD dwBufferLength;
  1424. WCHAR wszMachineName[MAX_PATH];
  1425. WCHAR wszObjectName[MAX_PATH];
  1426. WCHAR wszCounterName[MAX_PATH];
  1427. WCHAR wszInstanceName[MAX_PATH];
  1428. CHAR szFullInstanceName[MAX_PATH];
  1429. DWORD dwMachineNameLength;
  1430. DWORD dwObjectNameLength;
  1431. DWORD dwCounterNameLength;
  1432. DWORD dwInstanceNameLength;
  1433. DWORD dwItemCount = 0;
  1434. CHAR szIndexNumber[20];
  1435. PPDHI_INSTANCE pInstance;
  1436. PPDHI_INST_LIST pInstList;
  1437. UNREFERENCED_PARAMETER (dwDetailLevel);
  1438. UNREFERENCED_PARAMETER (dwFlags);
  1439. pInfo = (PPDH_COUNTER_PATH_ELEMENTS_A) G_ALLOC (MEDIUM_BUFFER_SIZE);
  1440. if (pInfo == NULL) {
  1441. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  1442. goto Cleanup;
  1443. }
  1444. szBuffer = & szTemp[0];
  1445. // what's in szReturn is not important since we'll be reading the
  1446. // data from the "last Record read" buffer
  1447. pdhStatus = PdhiReadOneTextLogRecord (
  1448. pLog,
  1449. TEXTLOG_HEADER_RECORD,
  1450. szBuffer,
  1451. 1); // we're lying to prevent copying the record.
  1452. if (pLog->dwLastRecordRead == TEXTLOG_HEADER_RECORD) {
  1453. // then the seek worked and we can use the buffer
  1454. cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ?
  1455. COMMA_DELIMITER : TAB_DELIMITER);
  1456. dwBufferLength = pLog->dwMaxRecordSize+1;
  1457. szBuffer = G_ALLOC (dwBufferLength);
  1458. if (szBuffer != NULL) {
  1459. dwIndex = 0;
  1460. while ((dwItemLength = PdhiGetStringFromDelimitedListA(
  1461. (LPSTR)pLog->pLastRecordRead,
  1462. ++dwIndex,
  1463. cDelim,
  1464. PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT,
  1465. szBuffer,
  1466. dwBufferLength)) != 0) {
  1467. if (dwItemLength > 0) {
  1468. dwInfoBufferSize = MEDIUM_BUFFER_SIZE;
  1469. // parse the path, pull the machine name out and
  1470. memset(pInfo, 0, MEDIUM_BUFFER_SIZE);
  1471. pdhStatus = PdhParseCounterPathA (
  1472. szBuffer,
  1473. pInfo,
  1474. &dwInfoBufferSize,
  1475. 0);
  1476. if (pdhStatus == ERROR_SUCCESS) {
  1477. if (szBuffer[1] != '\\') {
  1478. pInfo->szMachineName[0] = '.';
  1479. pInfo->szMachineName[1] = '\0';
  1480. }
  1481. // add it to the list if it will fit and it's from
  1482. // the desired machine
  1483. memset(wszMachineName, 0, sizeof(WCHAR) * MAX_PATH);
  1484. dwMachineNameLength = MAX_PATH;
  1485. MultiByteToWideChar(_getmbcp(),
  1486. 0,
  1487. pInfo->szMachineName,
  1488. lstrlenA(pInfo->szMachineName),
  1489. (LPWSTR) wszMachineName,
  1490. dwMachineNameLength);
  1491. if (lstrcmpiW(wszMachineName, szMachineName) == 0) {
  1492. memset(wszObjectName, 0, sizeof(WCHAR) * MAX_PATH);
  1493. dwObjectNameLength = MAX_PATH;
  1494. MultiByteToWideChar(_getmbcp(),
  1495. 0,
  1496. pInfo->szObjectName,
  1497. lstrlenA(pInfo->szObjectName),
  1498. (LPWSTR) wszObjectName,
  1499. dwObjectNameLength);
  1500. if (lstrcmpiW(wszObjectName, szObjectName) == 0) {
  1501. memset(wszCounterName, 0, sizeof(WCHAR) * MAX_PATH);
  1502. dwCounterNameLength = MAX_PATH;
  1503. MultiByteToWideChar(_getmbcp(),
  1504. 0,
  1505. pInfo->szCounterName,
  1506. lstrlenA(pInfo->szCounterName),
  1507. (LPWSTR) wszCounterName,
  1508. dwCounterNameLength);
  1509. pdhBuffStatus = PdhiFindCounterInstList(
  1510. CounterTable,
  1511. wszCounterName,
  1512. & pInstList);
  1513. if (pdhBuffStatus != ERROR_SUCCESS) {
  1514. continue;
  1515. }
  1516. if ( pInfo->szInstanceName != NULL
  1517. && pInfo->szInstanceName[0] != '\0') {
  1518. if (pInfo->szParentInstance == NULL) {
  1519. // then the name is just the instance
  1520. szFullInstanceName[0] = 0;
  1521. } else {
  1522. // we need to build the instance string from
  1523. // the parent and the child
  1524. lstrcpyA (szFullInstanceName,
  1525. pInfo->szParentInstance);
  1526. lstrcatA (szFullInstanceName, caszSlash);
  1527. }
  1528. lstrcatA (szFullInstanceName,
  1529. pInfo->szInstanceName);
  1530. if ((LONG)pInfo->dwInstanceIndex > 0) {
  1531. // append instance index to instance name if it's > 0
  1532. szIndexNumber[0] = POUNDSIGN_A;
  1533. _ultoa (pInfo->dwInstanceIndex, &szIndexNumber[1], 10);
  1534. lstrcatA (szFullInstanceName, szIndexNumber);
  1535. }
  1536. memset(wszInstanceName, 0, sizeof(WCHAR) * MAX_PATH);
  1537. dwInstanceNameLength = MAX_PATH;
  1538. MultiByteToWideChar(_getmbcp(),
  1539. 0,
  1540. szFullInstanceName,
  1541. lstrlenA(szFullInstanceName),
  1542. (LPWSTR) wszInstanceName,
  1543. dwInstanceNameLength);
  1544. pdhBuffStatus = PdhiFindInstance(
  1545. & pInstList->InstList,
  1546. wszInstanceName,
  1547. TRUE,
  1548. & pInstance);
  1549. }
  1550. if (pdhBuffStatus == ERROR_SUCCESS) {
  1551. dwItemCount++;
  1552. }
  1553. } // else not this object
  1554. } // else not this machine
  1555. }
  1556. }
  1557. }
  1558. if (dwItemCount > 0) {
  1559. // then the routine was successful. Errors that occurred
  1560. // while scanning will be ignored as long as at least
  1561. // one entry was successfully read
  1562. pdhStatus = pdhBuffStatus;
  1563. }
  1564. G_FREE (szBuffer);
  1565. } else {
  1566. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  1567. }
  1568. }
  1569. Cleanup:
  1570. if (pInfo) {
  1571. G_FREE (pInfo);
  1572. }
  1573. return pdhStatus;
  1574. }
  1575. PDH_FUNCTION
  1576. PdhiGetMatchingTextLogRecord (
  1577. IN PPDHI_LOG pLog,
  1578. IN LONGLONG *pStartTime,
  1579. IN LPDWORD pdwIndex
  1580. )
  1581. {
  1582. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1583. CHAR szSmallBuffer[MAX_PATH];
  1584. DWORD dwRecordId = TEXTLOG_FIRST_DATA_RECORD;
  1585. CHAR cDelim;
  1586. FILETIME RecordTimeStamp;
  1587. LONGLONG RecordTimeValue;
  1588. LONGLONG LastTimeValue = 0;
  1589. // read the first data record in the log file
  1590. // note that the record read is not copied to the local buffer
  1591. // rather the internal buffer is used in "read-only" mode
  1592. cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ?
  1593. COMMA_DELIMITER : TAB_DELIMITER);
  1594. if ((*pStartTime & 0xFFFFFFFF00000000) == 0xFFFFFFFF00000000) {
  1595. dwRecordId = (DWORD)(*pStartTime & 0x00000000FFFFFFFF);
  1596. LastTimeValue = *pStartTime;
  1597. if (dwRecordId == 0) return PDH_ENTRY_NOT_IN_LOG_FILE;
  1598. } else {
  1599. dwRecordId = TEXTLOG_FIRST_DATA_RECORD;
  1600. }
  1601. pdhStatus = PdhiReadOneTextLogRecord (
  1602. pLog,
  1603. dwRecordId,
  1604. szSmallBuffer,
  1605. 1); // to prevent copying the record
  1606. while ( pdhStatus == ERROR_SUCCESS
  1607. || pdhStatus == PDH_MORE_DATA
  1608. || pdhStatus == PDH_INSUFFICIENT_BUFFER) {
  1609. if (PdhiGetStringFromDelimitedListA(
  1610. (LPSTR)pLog->pLastRecordRead,
  1611. 0, // timestamp is first entry
  1612. cDelim,
  1613. PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT,
  1614. szSmallBuffer,
  1615. MAX_PATH) > 0) {
  1616. // convert ASCII timestamp to LONGLONG value for comparison
  1617. PdhiDateStringToFileTimeA (szSmallBuffer, &RecordTimeStamp);
  1618. RecordTimeValue = MAKELONGLONG(RecordTimeStamp.dwLowDateTime,
  1619. RecordTimeStamp.dwHighDateTime);
  1620. if ((*pStartTime == RecordTimeValue) || (*pStartTime == 0)) {
  1621. // found the match so bail here
  1622. LastTimeValue = RecordTimeValue;
  1623. break;
  1624. } else if (RecordTimeValue > *pStartTime) {
  1625. // then this is the first record > than the desired time
  1626. // so the desired value is the one before this one
  1627. // unless it's the first data record of the log
  1628. if (dwRecordId > TEXTLOG_FIRST_DATA_RECORD) {
  1629. dwRecordId--;
  1630. } else {
  1631. // this hasnt' been initialized yet.
  1632. LastTimeValue = RecordTimeValue;
  1633. }
  1634. break;
  1635. } else {
  1636. // save value for next trip through loop
  1637. LastTimeValue = RecordTimeValue;
  1638. // advance record counter and try the next entry
  1639. dwRecordId++;
  1640. }
  1641. } else {
  1642. // no timestamp field so ignore this record.
  1643. }
  1644. // read the next record in the file
  1645. pdhStatus = PdhiReadOneTextLogRecord (
  1646. pLog,
  1647. dwRecordId,
  1648. szSmallBuffer,
  1649. 1); // to prevent copying the record
  1650. }
  1651. if ( pdhStatus == ERROR_SUCCESS
  1652. || pdhStatus == PDH_MORE_DATA
  1653. || pdhStatus == PDH_INSUFFICIENT_BUFFER) {
  1654. // then dwRecordId is the desired entry
  1655. *pdwIndex = dwRecordId;
  1656. *pStartTime = LastTimeValue;
  1657. pdhStatus = ERROR_SUCCESS;
  1658. } else {
  1659. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  1660. }
  1661. return pdhStatus;
  1662. }
  1663. PDH_FUNCTION
  1664. PdhiGetCounterValueFromTextLog (
  1665. IN PPDHI_LOG pLog,
  1666. IN DWORD dwIndex,
  1667. IN PERFLIB_COUNTER *pPath,
  1668. IN PPDH_RAW_COUNTER pValue
  1669. )
  1670. {
  1671. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1672. CHAR szSmallBuffer[MAX_PATH];
  1673. CHAR cDelim;
  1674. FILETIME RecordTimeStamp;
  1675. DOUBLE dValue;
  1676. memset (&RecordTimeStamp, 0, sizeof(RecordTimeStamp));
  1677. // read the first data record in the log file
  1678. // note that the record read is not copied to the local buffer
  1679. // rather the internal buffer is used in "read-only" mode
  1680. cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ?
  1681. COMMA_DELIMITER : TAB_DELIMITER);
  1682. pdhStatus = PdhiReadOneTextLogRecord (
  1683. pLog,
  1684. dwIndex,
  1685. szSmallBuffer,
  1686. 1); // to prevent copying the record
  1687. if ( pdhStatus == ERROR_SUCCESS
  1688. || pdhStatus == PDH_MORE_DATA
  1689. || pdhStatus == PDH_INSUFFICIENT_BUFFER) {
  1690. // the specified entry in the log is the dwCounterId value
  1691. // in the perflib buffer
  1692. if (PdhiGetStringFromDelimitedListA (
  1693. (LPSTR)pLog->pLastRecordRead,
  1694. 0, // timestamp is first entry
  1695. cDelim,
  1696. PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT,
  1697. szSmallBuffer,
  1698. MAX_PATH) > 0) {
  1699. // convert time stamp string to FileTime value
  1700. PdhiDateStringToFileTimeA (szSmallBuffer, &RecordTimeStamp);
  1701. } else {
  1702. RecordTimeStamp.dwLowDateTime = 0;
  1703. RecordTimeStamp.dwHighDateTime = 0;
  1704. }
  1705. if (PdhiGetStringFromDelimitedListA(
  1706. (LPSTR) pLog->pLastRecordRead,
  1707. pPath->dwCounterId,
  1708. cDelim,
  1709. PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT,
  1710. szSmallBuffer,
  1711. MAX_PATH) > 0) {
  1712. // convert ASCII value to Double Float
  1713. if (szSmallBuffer[0] >= '0' && szSmallBuffer[0] <= '9') {
  1714. dValue = atof(szSmallBuffer);
  1715. pValue->CStatus = PDH_CSTATUS_VALID_DATA;
  1716. }
  1717. else {
  1718. dValue = 0.0;
  1719. pValue->CStatus = PDH_CSTATUS_NO_INSTANCE;
  1720. }
  1721. pdhStatus = ERROR_SUCCESS;
  1722. pValue->TimeStamp = RecordTimeStamp;
  1723. (double)pValue->FirstValue = dValue;
  1724. pValue->SecondValue = 0;
  1725. pValue->MultiCount = 1;
  1726. } else {
  1727. pdhStatus = ERROR_SUCCESS;
  1728. // update counter buffer
  1729. pValue->CStatus = PDH_CSTATUS_INVALID_DATA;
  1730. pValue->TimeStamp = RecordTimeStamp;
  1731. (double)pValue->FirstValue = (double)0.0f;
  1732. pValue->SecondValue = 0;
  1733. pValue->MultiCount = 1;
  1734. }
  1735. } else {
  1736. if (pdhStatus == PDH_END_OF_LOG_FILE) {
  1737. pdhStatus = PDH_NO_MORE_DATA;
  1738. }
  1739. // unable to find entry in the log file
  1740. pValue->CStatus = PDH_CSTATUS_INVALID_DATA;
  1741. pValue->TimeStamp = RecordTimeStamp;
  1742. (double)pValue->FirstValue = (double)0.0f;
  1743. pValue->SecondValue = 0;
  1744. pValue->MultiCount = 1;
  1745. }
  1746. return pdhStatus;
  1747. }
  1748. PDH_FUNCTION
  1749. PdhiGetTimeRangeFromTextLog (
  1750. IN PPDHI_LOG pLog,
  1751. IN LPDWORD pdwNumEntries,
  1752. IN PPDH_TIME_INFO pInfo,
  1753. IN LPDWORD pdwBufferSize
  1754. )
  1755. /*++
  1756. the first entry in the buffer returned is the total time range covered
  1757. in the file, if there are multiple time blocks in the log file, then
  1758. subsequent entries will identify each segment in the file.
  1759. --*/
  1760. {
  1761. PDH_STATUS pdhStatus;
  1762. LONGLONG llStartTime = MAX_TIME_VALUE;
  1763. LONGLONG llEndTime = MIN_TIME_VALUE;
  1764. LONGLONG llThisTime = 0;
  1765. CHAR cDelim;
  1766. DWORD dwThisRecord = TEXTLOG_FIRST_DATA_RECORD;
  1767. DWORD dwValidEntries = 0;
  1768. CHAR szSmallBuffer[MAX_PATH];
  1769. // read the first data record in the log file
  1770. // note that the record read is not copied to the local buffer
  1771. // rather the internal buffer is used in "read-only" mode
  1772. cDelim = (CHAR)((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_CSV) ?
  1773. COMMA_DELIMITER : TAB_DELIMITER);
  1774. pdhStatus = PdhiReadOneTextLogRecord (
  1775. pLog,
  1776. dwThisRecord,
  1777. szSmallBuffer,
  1778. 1); // to prevent copying the record
  1779. while (pdhStatus == ERROR_SUCCESS
  1780. || pdhStatus == PDH_MORE_DATA
  1781. || pdhStatus == PDH_INSUFFICIENT_BUFFER) {
  1782. if (PdhiGetStringFromDelimitedListA (
  1783. (LPSTR)pLog->pLastRecordRead,
  1784. 0, // timestamp is first entry
  1785. cDelim,
  1786. PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT,
  1787. szSmallBuffer,
  1788. MAX_PATH) > 0) {
  1789. // convert ASCII timestamp to LONGLONG value for comparison
  1790. PdhiDateStringToFileTimeA (szSmallBuffer, (LPFILETIME)&llThisTime);
  1791. if (llThisTime < llStartTime) {
  1792. llStartTime = llThisTime;
  1793. }
  1794. if (llThisTime > llEndTime) {
  1795. llEndTime = llThisTime;
  1796. }
  1797. dwValidEntries++;
  1798. } else {
  1799. // no timestamp field so ignore this record.
  1800. }
  1801. // read the next record in the file
  1802. pdhStatus = PdhiReadOneTextLogRecord (
  1803. pLog,
  1804. ++dwThisRecord,
  1805. szSmallBuffer,
  1806. 1); // to prevent copying the record
  1807. }
  1808. if (pdhStatus == PDH_END_OF_LOG_FILE) {
  1809. // then the whole file was read so update the args.
  1810. if (*pdwBufferSize >= sizeof(PDH_TIME_INFO)) {
  1811. *(LONGLONG *)(&pInfo->StartTime) = llStartTime;
  1812. *(LONGLONG *)(&pInfo->EndTime) = llEndTime;
  1813. pInfo->SampleCount = dwValidEntries;
  1814. *pdwBufferSize = sizeof(PDH_TIME_INFO);
  1815. *pdwNumEntries = 1;
  1816. } else {
  1817. pdhStatus = PDH_MORE_DATA;
  1818. }
  1819. pdhStatus = ERROR_SUCCESS;
  1820. } else {
  1821. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  1822. }
  1823. return pdhStatus;
  1824. }
  1825. PDH_FUNCTION
  1826. PdhiReadRawTextLogRecord (
  1827. IN PPDHI_LOG pLog,
  1828. IN FILETIME *ftRecord,
  1829. IN PPDH_RAW_LOG_RECORD pBuffer,
  1830. IN LPDWORD pdwBufferLength
  1831. )
  1832. {
  1833. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1834. LONGLONG llStartTime;
  1835. DWORD dwIndex = 0;
  1836. DWORD dwSizeRequired;
  1837. DWORD dwLocalRecordLength; // including terminating NULL
  1838. llStartTime = *(LONGLONG *)ftRecord;
  1839. pdhStatus = PdhiGetMatchingTextLogRecord (
  1840. pLog,
  1841. &llStartTime,
  1842. &dwIndex);
  1843. // copy results from internal log buffer if it'll fit.
  1844. if (pdhStatus == ERROR_SUCCESS) {
  1845. dwLocalRecordLength =
  1846. (lstrlenA ((LPSTR)pLog->pLastRecordRead)) * sizeof (CHAR);
  1847. dwSizeRequired =
  1848. sizeof (PDH_RAW_LOG_RECORD) - sizeof (UCHAR)
  1849. + dwLocalRecordLength;
  1850. if (*pdwBufferLength >= dwSizeRequired) {
  1851. pBuffer->dwRecordType = (DWORD)(LOWORD(pLog->dwLogFormat));
  1852. pBuffer->dwItems = dwLocalRecordLength;
  1853. // copy it
  1854. memcpy (&pBuffer->RawBytes[0], pLog->pLastRecordRead,
  1855. dwLocalRecordLength);
  1856. pBuffer->dwStructureSize = dwSizeRequired;
  1857. } else {
  1858. pdhStatus = PDH_MORE_DATA;
  1859. }
  1860. *pdwBufferLength = dwSizeRequired;
  1861. }
  1862. return pdhStatus;
  1863. }
  1864. PDH_FUNCTION
  1865. PdhiListHeaderFromTextLog (
  1866. IN PPDHI_LOG pLogFile,
  1867. IN LPVOID pBufferArg,
  1868. IN LPDWORD pcchBufferSize,
  1869. IN BOOL bUnicode
  1870. )
  1871. {
  1872. LPVOID pTempBuffer = NULL;
  1873. LPVOID pOldBuffer;
  1874. DWORD dwTempBufferSize;
  1875. CHAR szLocalPathBuffer[MAX_PATH];
  1876. DWORD dwIndex;
  1877. DWORD dwBufferRemaining;
  1878. LPVOID pNextChar;
  1879. DWORD dwReturnSize;
  1880. CHAR cDelimiter;
  1881. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1882. // read the header record and enum the machine name from the entries
  1883. if (pLogFile->dwMaxRecordSize == 0) {
  1884. // no size is defined so start with 64K
  1885. pLogFile->dwMaxRecordSize = 0x010000;
  1886. }
  1887. dwTempBufferSize = pLogFile->dwMaxRecordSize;
  1888. pTempBuffer = G_ALLOC (dwTempBufferSize);
  1889. assert (pTempBuffer != NULL);
  1890. if (pTempBuffer == NULL) {
  1891. assert (GetLastError() == ERROR_SUCCESS);
  1892. return PDH_MEMORY_ALLOCATION_FAILURE;
  1893. }
  1894. cDelimiter = (CHAR)((LOWORD(pLogFile->dwLogFormat) == PDH_LOG_TYPE_CSV) ?
  1895. COMMA_DELIMITER : TAB_DELIMITER);
  1896. // read in the catalog record
  1897. while ((pdhStatus = PdhiReadOneTextLogRecord (pLogFile, TEXTLOG_HEADER_RECORD,
  1898. pTempBuffer, dwTempBufferSize)) != ERROR_SUCCESS) {
  1899. if ((pdhStatus == PDH_INSUFFICIENT_BUFFER) || (pdhStatus == PDH_MORE_DATA)){
  1900. // read the 1st WORD to see if this is a valid record
  1901. pLogFile->dwMaxRecordSize *= 2;
  1902. // realloc a new buffer
  1903. pOldBuffer = pTempBuffer;
  1904. pTempBuffer = G_REALLOC (pOldBuffer, dwTempBufferSize);
  1905. assert (pTempBuffer != NULL);
  1906. if (pTempBuffer == NULL) {
  1907. // return memory error
  1908. G_FREE(pOldBuffer);
  1909. assert (GetLastError() == ERROR_SUCCESS);
  1910. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  1911. break;
  1912. }
  1913. } else {
  1914. // some other error was returned so
  1915. // return error from read function
  1916. break;
  1917. }
  1918. }
  1919. if (pdhStatus == ERROR_SUCCESS) {
  1920. // parse header record into MSZ
  1921. dwIndex = 1;
  1922. dwBufferRemaining = *pcchBufferSize;
  1923. pNextChar = pBufferArg;
  1924. // initialize first character in buffer
  1925. if (bUnicode) {
  1926. *(PWCHAR)pNextChar = 0;
  1927. } else {
  1928. *(LPBYTE)pNextChar = 0;
  1929. }
  1930. do {
  1931. dwReturnSize = PdhiGetStringFromDelimitedListA (
  1932. (LPSTR)pTempBuffer,
  1933. dwIndex,
  1934. cDelimiter,
  1935. PDHI_GSFDL_REMOVE_QUOTES | PDHI_GSFDL_REMOVE_NONPRINT,
  1936. szLocalPathBuffer,
  1937. MAX_PATH);
  1938. if (dwReturnSize > 0) {
  1939. // copy to buffer
  1940. if (dwReturnSize < dwBufferRemaining) {
  1941. if (bUnicode) {
  1942. MultiByteToWideChar(_getmbcp(),
  1943. 0,
  1944. szLocalPathBuffer,
  1945. lstrlenA(szLocalPathBuffer),
  1946. (LPWSTR) pNextChar,
  1947. dwReturnSize);
  1948. pNextChar = (LPVOID)((PWCHAR)pNextChar + dwReturnSize);
  1949. *(PWCHAR)pNextChar = 0;
  1950. pNextChar = (LPVOID)((PWCHAR)pNextChar + 1);
  1951. } else {
  1952. lstrcpyA ((LPSTR)pNextChar, szLocalPathBuffer);
  1953. pNextChar = (LPVOID)((LPBYTE)pNextChar + dwReturnSize);
  1954. *(LPBYTE)pNextChar = 0;
  1955. pNextChar = (LPVOID)((PCHAR)pNextChar + 1);
  1956. }
  1957. dwBufferRemaining -= dwReturnSize;
  1958. } else {
  1959. pdhStatus = PDH_MORE_DATA;
  1960. }
  1961. dwIndex++;
  1962. }
  1963. } while (dwReturnSize > 0); // end loop
  1964. // add MSZ terminator
  1965. if (1 < dwBufferRemaining) {
  1966. if (bUnicode) {
  1967. *(PWCHAR)pNextChar = 0;
  1968. pNextChar = (LPVOID)((PWCHAR)pNextChar + 1);
  1969. } else {
  1970. *(LPBYTE)pNextChar = 0;
  1971. pNextChar = (LPVOID)((PCHAR)pNextChar + 1);
  1972. }
  1973. dwBufferRemaining -= dwReturnSize;
  1974. pdhStatus = ERROR_SUCCESS;
  1975. } else {
  1976. pdhStatus = PDH_MORE_DATA;
  1977. }
  1978. }
  1979. if (pTempBuffer) G_FREE(pTempBuffer);
  1980. return pdhStatus;
  1981. }