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

752 lines
21 KiB

  1. //---------------------------------------------------------------------------
  2. // log.cpp - theme logging routines (shared in "inc" directory)
  3. //---------------------------------------------------------------------------
  4. #include "stdafx.h"
  5. //---------------------------------------------------------------------------
  6. #include "log.h"
  7. #include <time.h>
  8. #include <psapi.h>
  9. #include "cfile.h"
  10. #include "tmreg.h"
  11. //---------------------------------------------------------------------------
  12. //---- undo the defines that turn these into _xxx ----
  13. #undef Log
  14. #undef LogStartUp
  15. #undef LogShutDown
  16. #undef LogControl
  17. #undef TimeToStr
  18. #undef StartTimer
  19. #undef StopTimer
  20. #undef OpenLogFile
  21. #undef CloseLogFile
  22. #undef LogOptionOn
  23. #undef GetMemUsage
  24. #undef GetUserCount
  25. #undef GetGdiCount
  26. //---------------------------------------------------------------------------
  27. #define DEFAULT_LOGNAME L"c:\\Themes.log"
  28. //---------------------------------------------------------------------------
  29. struct LOGNAMEINFO
  30. {
  31. LPCSTR pszOption;
  32. LPCSTR pszDescription;
  33. };
  34. //---------------------------------------------------------------------------
  35. #define MAKE_LOG_STRINGS
  36. #include "logopts.h" // log options as strings
  37. //-----------------------------------------------------------------
  38. static const WCHAR szDayOfWeekArray[7][4] = { L"Sun", L"Mon", L"Tue", L"Wed",
  39. L"Thu", L"Fri", L"Sat" } ;
  40. static const WCHAR szMonthOfYearArray[12][4] = { L"Jan", L"Feb", L"Mar",
  41. L"Apr", L"May", L"Jun", L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec" } ;
  42. //-----------------------------------------------------------------
  43. #define OPTIONCNT (ARRAYSIZE(LogNames))
  44. #define LOGPROMPT "enter log cmd here."
  45. //-----------------------------------------------------------------
  46. //---- unprotected vars (set on init) ----
  47. static WCHAR _szUtilProcessName[MAX_PATH] = {0};
  48. static WCHAR _szLogAppName[MAX_PATH] = {0};
  49. static CRITICAL_SECTION csLogFile = {0};
  50. static WCHAR szLogFileName[MAX_PATH+1];
  51. static BOOL fLogInitialized = FALSE;
  52. //---- protected vars (thread safe) ----
  53. static UCHAR uLogOptions[OPTIONCNT]; // protected by csLogFile
  54. static UCHAR uBreakOptions[OPTIONCNT]; // protected by csLogFile
  55. static DWORD dwLogStartTimer = 0; // protected by csLogFile
  56. static char szLastOptions[999] = {0}; // protected by csLogFile
  57. static char szLogCmd[999] = {0}; // protected by csLogFile
  58. static int iIndentCount = 0; // protected by csLogFile
  59. static WCHAR s_szWorkerBuffer[512]; // protected by csLogFile
  60. static WCHAR s_szLogBuffer[512]; // protected by csLogFile
  61. static CHAR s_szConBuffer[512]; // protected by csLogFile
  62. static CSimpleFile *pLogFile = NULL; // protected by csLogFile
  63. //-----------------------------------------------------------------
  64. void ParseLogOptions(UCHAR *uOptions, LPCSTR pszName, LPCSTR pszOptions, BOOL fEcho);
  65. //-----------------------------------------------------------------
  66. void RawCon(LPCSTR pszFormat, ...)
  67. {
  68. CAutoCS cs(&csLogFile);
  69. va_list args;
  70. va_start(args, pszFormat);
  71. //---- format caller's string ----
  72. StringCchVPrintfA(s_szConBuffer, ARRAYSIZE(s_szConBuffer), pszFormat, args);
  73. OutputDebugStringA(s_szConBuffer);
  74. va_end(args);
  75. }
  76. //-----------------------------------------------------------------
  77. void SetDefaultLoggingOptions()
  78. {
  79. RESOURCE HKEY hklm = NULL;
  80. HRESULT hr = S_OK;
  81. //---- open hklm ----
  82. int code32 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, THEMEMGR_REGKEY, 0,
  83. KEY_READ, &hklm);
  84. if (code32 != ERROR_SUCCESS)
  85. {
  86. hr = MakeErrorLast();
  87. goto exit;
  88. }
  89. //---- read the "LogCmd" value ----
  90. WCHAR szValBuff[MAX_PATH];
  91. hr = RegistryStrRead(hklm, THEMEPROP_LOGCMD, szValBuff, ARRAYSIZE(szValBuff));
  92. if (SUCCEEDED(hr))
  93. {
  94. USES_CONVERSION;
  95. ParseLogOptions(uLogOptions, "Log", W2A(szValBuff), FALSE);
  96. }
  97. //---- read the "BreakCmd" value ----
  98. hr = RegistryStrRead(hklm, THEMEPROP_BREAKCMD, szValBuff, ARRAYSIZE(szValBuff));
  99. if (SUCCEEDED(hr))
  100. {
  101. USES_CONVERSION;
  102. ParseLogOptions(uBreakOptions, "Break", W2A(szValBuff), FALSE);
  103. }
  104. //---- read the "LogAppName" value ----
  105. RegistryStrRead(hklm, THEMEPROP_LOGAPPNAME, _szLogAppName, ARRAYSIZE(_szLogAppName));
  106. exit:
  107. if (hklm)
  108. RegCloseKey(hklm);
  109. }
  110. //-----------------------------------------------------------------
  111. BOOL LogStartUp()
  112. {
  113. BOOL fInit = FALSE;
  114. dwLogStartTimer = StartTimer();
  115. pLogFile = new CSimpleFile;
  116. if (! pLogFile)
  117. goto exit;
  118. //---- reset all log options ----
  119. for (int i=0; i < OPTIONCNT; i++)
  120. {
  121. uLogOptions[i] = 0;
  122. uBreakOptions[i] = 0;
  123. }
  124. //---- turn on default OUTPUT options ----
  125. uLogOptions[LO_CONSOLE] = TRUE;
  126. uLogOptions[LO_APPID] = TRUE;
  127. uLogOptions[LO_THREADID] = TRUE;
  128. //---- turn on default FILTER options ----
  129. uLogOptions[LO_ERROR] = TRUE;
  130. uLogOptions[LO_ASSERT] = TRUE;
  131. uLogOptions[LO_BREAK] = TRUE;
  132. uLogOptions[LO_PARAMS] = TRUE;
  133. uLogOptions[LO_ALWAYS] = TRUE;
  134. //---- turn on default BREAK options ----
  135. uBreakOptions[LO_ERROR] = TRUE;
  136. uBreakOptions[LO_ASSERT] = TRUE;
  137. if( InitializeCriticalSectionAndSpinCount(&csLogFile, 0) )
  138. {
  139. //---- get process name (log has its own copy) ----
  140. WCHAR szPath[MAX_PATH];
  141. if (! GetModuleFileNameW( NULL, szPath, ARRAYSIZE(szPath) ))
  142. goto exit;
  143. WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szExt[_MAX_EXT];
  144. _wsplitpath(szPath, szDrive, szDir, _szUtilProcessName, szExt);
  145. StringCchCopyA(szLogCmd, ARRAYSIZE(szLogCmd), LOGPROMPT);
  146. StringCchCopyW(szLogFileName, ARRAYSIZE(szLogFileName), DEFAULT_LOGNAME);
  147. fLogInitialized = TRUE;
  148. SetDefaultLoggingOptions();
  149. fInit = TRUE;
  150. }
  151. exit:
  152. return fInit;
  153. }
  154. //---------------------------------------------------------------------------
  155. BOOL LogShutDown()
  156. {
  157. fLogInitialized = FALSE;
  158. SAFE_DELETE(pLogFile);
  159. SAFE_DELETECRITICALSECTION(&csLogFile);
  160. return TRUE;
  161. }
  162. //---------------------------------------------------------------------------
  163. void GetDateString(WCHAR *pszDateBuff, ULONG cchDateBuff)
  164. {
  165. // Sent Date
  166. SYSTEMTIME stNow;
  167. WCHAR szMonth[10], szWeekDay[12] ;
  168. GetLocalTime(&stNow);
  169. StringCchCopyW(szWeekDay, ARRAYSIZE(szWeekDay), szDayOfWeekArray[stNow.wDayOfWeek]) ;
  170. StringCchCopyW(szMonth, ARRAYSIZE(szMonth), szMonthOfYearArray[stNow.wMonth-1]) ;
  171. StringCchPrintfW(pszDateBuff, cchDateBuff, L"%s, %u %s %u %2d:%02d:%02d ", szWeekDay, stNow.wDay,
  172. szMonth, stNow.wYear, stNow.wHour,
  173. stNow.wMinute, stNow.wSecond) ;
  174. }
  175. //---------------------------------------------------------------------------
  176. void LogMsgToFile(LPCWSTR pszMsg)
  177. {
  178. CAutoCS autoCritSect(&csLogFile);
  179. HRESULT hr;
  180. BOOL fWasOpen = pLogFile->IsOpen();
  181. if (! fWasOpen)
  182. {
  183. BOOL fNewFile = !FileExists(szLogFileName);
  184. hr = pLogFile->Append(szLogFileName, TRUE);
  185. if (FAILED(hr))
  186. goto exit;
  187. //---- write hdr if new file ----
  188. if (fNewFile)
  189. {
  190. WCHAR pszBuff[100];
  191. GetDateString(pszBuff, ARRAYSIZE(pszBuff));
  192. pLogFile->Printf(L"Theme log - %s\r\n\r\n", pszBuff);
  193. }
  194. }
  195. pLogFile->Write((void*)pszMsg, lstrlen(pszMsg)*sizeof(WCHAR));
  196. exit:
  197. if (! fWasOpen)
  198. pLogFile->Close();
  199. }
  200. //---------------------------------------------------------------------------
  201. void SimpleFileName(LPCSTR pszNarrowFile, OUT LPWSTR pszSimpleBuff, ULONG cchSimpleBuff)
  202. {
  203. USES_CONVERSION;
  204. WCHAR *pszFile = A2W(pszNarrowFile);
  205. //---- remove current dir marker for VS error navigation ----
  206. if ((pszFile[0] == L'.') && (pszFile[1] == L'\\'))
  207. {
  208. StringCchPrintfW(pszSimpleBuff, cchSimpleBuff, L"f:\\nt\\shell\\Themes\\UxTheme\\%s", pszFile+2);
  209. if (! FileExists(pszSimpleBuff))
  210. StringCchPrintfW(pszSimpleBuff, cchSimpleBuff, L"f:\\nt\\shell\\Themes\\ThemeSel\\%s", pszFile+2);
  211. if (! FileExists(pszSimpleBuff))
  212. StringCchPrintfW(pszSimpleBuff, cchSimpleBuff, L"f:\\nt\\shell\\Themes\\packthem\\%s", pszFile+2);
  213. if (! FileExists(pszSimpleBuff))
  214. StringCchPrintfW(pszSimpleBuff, cchSimpleBuff, L"%s", pszFile+2);
  215. }
  216. else
  217. StringCchCopyW(pszSimpleBuff, cchSimpleBuff, pszFile);
  218. }
  219. //-----------------------------------------------------------------
  220. #ifdef DEBUG // pulls in psapi.dll
  221. int GetMemUsage()
  222. {
  223. ULONG ulReturnLength;
  224. VM_COUNTERS vmCounters;
  225. if (!NT_SUCCESS(NtQueryInformationProcess(GetCurrentProcess(),
  226. ProcessVmCounters,
  227. &vmCounters,
  228. sizeof(vmCounters),
  229. &ulReturnLength)))
  230. {
  231. ZeroMemory(&vmCounters, sizeof(vmCounters));
  232. }
  233. return static_cast<int>(vmCounters.WorkingSetSize);
  234. }
  235. #else
  236. int GetMemUsage()
  237. {
  238. return 0;
  239. }
  240. #endif
  241. //-----------------------------------------------------------------
  242. int GetUserCount()
  243. {
  244. HANDLE hp = GetCurrentProcess();
  245. return GetGuiResources(hp, GR_USEROBJECTS);
  246. }
  247. //-----------------------------------------------------------------
  248. int GetGdiCount()
  249. {
  250. HANDLE hp = GetCurrentProcess();
  251. return GetGuiResources(hp, GR_GDIOBJECTS);
  252. }
  253. //-----------------------------------------------------------------
  254. void LogWorker(UCHAR uLogOption, LPCSTR pszSrcFile, int iLineNum, int iEntryExitCode, LPCWSTR pszMsg)
  255. {
  256. CAutoCS cs(&csLogFile);
  257. BOOL fBreaking = (uBreakOptions[uLogOption]);
  258. if (fBreaking)
  259. {
  260. OutputDebugString(L"\r\n"); // blank line at beginning
  261. WCHAR fn[_MAX_PATH+1];
  262. SimpleFileName(pszSrcFile, fn, ARRAYSIZE(fn));
  263. StringCchPrintfW(s_szWorkerBuffer, ARRAYSIZE(s_szWorkerBuffer), L"%s [%d]: BREAK at %s(%d):\r\n",
  264. _szUtilProcessName, GetCurrentThreadId(), fn, iLineNum);
  265. OutputDebugString(s_szWorkerBuffer);
  266. }
  267. //---- PRE API entry/exit indent adjustment ----
  268. if (iEntryExitCode == -1)
  269. {
  270. if (iIndentCount >= 2)
  271. iIndentCount -= 2;
  272. }
  273. WCHAR *p = s_szWorkerBuffer;
  274. ULONG cch = ARRAYSIZE(s_szWorkerBuffer);
  275. ULONG len;
  276. //---- apply indenting ----
  277. for (int i=0; i < iIndentCount; i++)
  278. {
  279. *p++ = ' ';
  280. cch--;
  281. }
  282. //---- POST API entry/exit indent adjustment ----
  283. if (iEntryExitCode == 1)
  284. {
  285. iIndentCount += 2;
  286. }
  287. //---- apply app id ----
  288. if (uLogOptions[LO_APPID] && cch > 0)
  289. {
  290. StringCchPrintfW(p, cch, L"%s ", _szUtilProcessName);
  291. len = lstrlen(p);
  292. p += len;
  293. cch -= len;
  294. }
  295. //---- apply thread id ----
  296. if (uLogOptions[LO_THREADID] && cch > 0)
  297. {
  298. StringCchPrintfW(p, cch, L"[%d] ", GetCurrentThreadId());
  299. len = lstrlen(p);
  300. p += len;
  301. cch -= len;
  302. }
  303. //---- apply src id ----
  304. if (uLogOptions[LO_SRCID] && cch > 0)
  305. {
  306. WCHAR fn[_MAX_PATH+1];
  307. SimpleFileName(pszSrcFile, fn, ARRAYSIZE(fn));
  308. if (fBreaking)
  309. StringCchPrintfW(p, cch, L"BREAK at %s(%d) : ", fn, iLineNum);
  310. else
  311. StringCchPrintfW(p, cch, L"%s(%d) : ", fn, iLineNum);
  312. len = lstrlen(p);
  313. p += len;
  314. cch -= len;
  315. }
  316. //---- apply timer id ----
  317. if (uLogOptions[LO_TIMERID] && cch > 0)
  318. {
  319. DWORD dwTicks = StopTimer(dwLogStartTimer);
  320. WCHAR buff[100];
  321. TimeToStr(dwTicks, buff, ARRAYSIZE(buff));
  322. StringCchPrintfW(p, cch, L"Timer: %s ", buff);
  323. len = lstrlen(p);
  324. p += len;
  325. cch -= len;
  326. }
  327. //---- apply clock id ----
  328. if (uLogOptions[LO_CLOCKID] && cch > 0)
  329. {
  330. SYSTEMTIME stNow;
  331. GetLocalTime(&stNow);
  332. StringCchPrintfW(p, cch, L"Clock: %02d:%02d:%02d.%03d ", stNow.wHour,
  333. stNow.wMinute, stNow.wSecond, stNow.wMilliseconds);
  334. len = lstrlen(p);
  335. p += len;
  336. cch -= len;
  337. }
  338. //---- apply USER count ----
  339. if (uLogOptions[LO_USERCOUNT] && cch > 0)
  340. {
  341. StringCchPrintfW(p, cch, L"UserCount=%d ", GetUserCount());
  342. len = lstrlen(p);
  343. p += len;
  344. cch -= len;
  345. }
  346. //---- apply GDI count ----
  347. if (uLogOptions[LO_GDICOUNT] && cch > 0)
  348. {
  349. StringCchPrintfW(p, cch, L"GDICount=%d ", GetGdiCount());
  350. len = lstrlen(p);
  351. p += len;
  352. cch -= len;
  353. }
  354. //---- apply MEM usage ----
  355. if (uLogOptions[LO_MEMUSAGE] && cch > 0)
  356. {
  357. int iUsage = GetMemUsage();
  358. StringCchPrintfW(p, cch, L"MemUsage=%d ", iUsage);
  359. len = lstrlen(p);
  360. p += len;
  361. cch -= len;
  362. }
  363. //---- add "Assert:" or "Error:" strings as needed ----
  364. if (uLogOption == LO_ASSERT && cch > 0)
  365. {
  366. StringCchCopyW(p, cch, L"Assert: ");
  367. len = lstrlen(p);
  368. p += len;
  369. cch -= len;
  370. }
  371. else if (uLogOption == LO_ERROR && cch > 0)
  372. {
  373. StringCchCopyW(p, cch, L"Error: ");
  374. len = lstrlen(p);
  375. p += len;
  376. cch -= len;
  377. }
  378. //---- apply caller's msg ----
  379. if( cch > 0 )
  380. {
  381. StringCchCopyW(p, cch, pszMsg);
  382. len = lstrlen(p);
  383. p += len;
  384. cch -= len;
  385. }
  386. if( cch >= 3 )
  387. {
  388. *p++ = '\r'; // end with CR
  389. cch--;
  390. }
  391. if( cch >= 2 )
  392. {
  393. *p++ = '\n'; // end with newline
  394. cch--;
  395. }
  396. if( cch >= 1 )
  397. {
  398. *p = 0;
  399. cch--;
  400. }
  401. //---- log to CONSOLE and/or FILE ----
  402. if (uLogOptions[LO_CONSOLE])
  403. OutputDebugString(s_szWorkerBuffer);
  404. if (uLogOptions[LO_LOGFILE])
  405. LogMsgToFile(s_szWorkerBuffer);
  406. //---- process Heap Check ----
  407. if (uLogOptions[LO_HEAPCHECK])
  408. {
  409. HANDLE hh = GetProcessHeap();
  410. HeapValidate(hh, 0, NULL);
  411. }
  412. if (fBreaking)
  413. OutputDebugString(L"\r\n"); // blank line at end
  414. }
  415. //-----------------------------------------------------------------
  416. HRESULT OpenLogFile(LPCWSTR pszLogFileName)
  417. {
  418. CAutoCS cs(&csLogFile);
  419. HRESULT hr = pLogFile->Create(pszLogFileName, TRUE);
  420. return hr;
  421. }
  422. //-----------------------------------------------------------------
  423. void CloseLogFile()
  424. {
  425. CAutoCS cs(&csLogFile);
  426. if (pLogFile)
  427. pLogFile->Close();
  428. }
  429. //-----------------------------------------------------------------
  430. void Log(UCHAR uLogOption, LPCSTR pszSrcFile, int iLineNum, int iEntryExitCode, LPCWSTR pszFormat, ...)
  431. {
  432. if (fLogInitialized)
  433. {
  434. CAutoCS cs(&csLogFile);
  435. //---- only log for a specified process? ----
  436. if (* _szLogAppName)
  437. {
  438. if (lstrcmpi(_szLogAppName, _szUtilProcessName) != 0)
  439. return;
  440. }
  441. while (1)
  442. {
  443. if (strncmp(szLogCmd, LOGPROMPT, 6)!=0)
  444. {
  445. LogControl(szLogCmd, TRUE);
  446. StringCchCopyA(szLogCmd, ARRAYSIZE(szLogCmd), LOGPROMPT);
  447. DEBUG_BREAK;
  448. }
  449. else
  450. break;
  451. }
  452. if ((uLogOption >= 0) || (uLogOption < OPTIONCNT))
  453. {
  454. if (uLogOptions[uLogOption])
  455. {
  456. //---- apply caller's msg ----
  457. va_list args;
  458. va_start(args, pszFormat);
  459. StringCchVPrintfW(s_szLogBuffer, ARRAYSIZE(s_szLogBuffer), pszFormat, args);
  460. va_end(args);
  461. LogWorker(uLogOption, pszSrcFile, iLineNum, iEntryExitCode, s_szLogBuffer);
  462. }
  463. if ((uBreakOptions[uLogOption]) && (uLogOption != LO_ASSERT))
  464. DEBUG_BREAK;
  465. }
  466. }
  467. }
  468. //-----------------------------------------------------------------
  469. int MatchLogOption(LPCSTR lszOption)
  470. {
  471. for (int i=0; i < OPTIONCNT; i++)
  472. {
  473. if (lstrcmpiA(lszOption, LogNames[i].pszOption)==0)
  474. return i;
  475. }
  476. return -1; // not found
  477. }
  478. //-----------------------------------------------------------------
  479. void ParseLogOptions(UCHAR *uOptions, LPCSTR pszName, LPCSTR pszOptions, BOOL fEcho)
  480. {
  481. CAutoCS cs(&csLogFile);
  482. if (! fLogInitialized)
  483. return;
  484. //---- ignore debugger's multiple eval of same expression ----
  485. if (strcmp(pszOptions, szLastOptions)==0)
  486. return;
  487. //---- make a copy of options so we can put NULLs in it ----
  488. BOOL fErrors = FALSE;
  489. char szOptions[999];
  490. char *pszErrorText = NULL;
  491. StringCchCopyA(szOptions, ARRAYSIZE(szOptions), pszOptions);
  492. //---- process each option in szOption ----
  493. char *p = strchr(szOptions, '.');
  494. if (p) // easy termination for NTSD users
  495. *p = 0;
  496. p = szOptions;
  497. while (*p == ' ')
  498. p++;
  499. while ((p) && (*p))
  500. {
  501. //---- find end of current option "p" ----
  502. char *q = strchr(p, ' ');
  503. if (q)
  504. *q = 0;
  505. UCHAR fSet = TRUE;
  506. if (*p == '+')
  507. p++;
  508. else if (*p == '-')
  509. {
  510. fSet = FALSE;
  511. p++;
  512. }
  513. if (! fErrors) // point to first error in case one is found
  514. pszErrorText = p;
  515. int iLogOpt = MatchLogOption(p);
  516. if (iLogOpt != -1)
  517. {
  518. if (iLogOpt == LO_ALL)
  519. {
  520. for (int i=0; i < OPTIONCNT; i++)
  521. uOptions[i] = fSet;
  522. }
  523. else
  524. uOptions[iLogOpt] = fSet;
  525. }
  526. else
  527. fErrors = TRUE;
  528. //---- skip to next valid space ----
  529. if (! q)
  530. break;
  531. q++;
  532. while (*q == ' ')
  533. q++;
  534. p = q;
  535. }
  536. //---- fixup inconsistent option settings ----
  537. if (! uOptions[LO_LOGFILE])
  538. uOptions[LO_CONSOLE] = TRUE;
  539. if ((! fErrors) && (fEcho))
  540. {
  541. //---- display active log options ----
  542. BOOL fNoneSet = TRUE;
  543. RawCon("Active %s Options:\n", pszName);
  544. for (int i=0; i < LO_ALL; i++)
  545. {
  546. if (uOptions[i])
  547. {
  548. RawCon("+%s ", LogNames[i].pszOption);
  549. fNoneSet = FALSE;
  550. }
  551. }
  552. if (fNoneSet)
  553. RawCon("<none>\n");
  554. else
  555. RawCon("\n");
  556. //---- display active log filters (except "all") ----
  557. RawCon("Active Msg Filters:\n ");
  558. for (i=LO_ALL+1; i < OPTIONCNT; i++)
  559. {
  560. if (uOptions[i])
  561. {
  562. RawCon("+%s ", LogNames[i].pszOption);
  563. fNoneSet = FALSE;
  564. }
  565. }
  566. if (fNoneSet)
  567. RawCon("<none>\n");
  568. else
  569. RawCon("\n");
  570. }
  571. else if (fErrors)
  572. {
  573. //---- one or more bad options - display available options ----
  574. RawCon("Error - unrecognized %s option: %s\n", pszName, pszErrorText);
  575. if (fEcho)
  576. {
  577. RawCon("Available Log Options:\n");
  578. for (int i=0; i < LO_ALL; i++)
  579. {
  580. RawCon(" +%-12s %s\n",
  581. LogNames[i].pszOption, LogNames[i].pszDescription);
  582. }
  583. RawCon("Available Msg Filters:\n");
  584. for (i=LO_ALL; i < OPTIONCNT; i++)
  585. {
  586. RawCon(" +%-12s %s\n",
  587. LogNames[i].pszOption, LogNames[i].pszDescription);
  588. }
  589. }
  590. }
  591. StringCchCopyA(szLastOptions, ARRAYSIZE(szLastOptions), pszOptions);
  592. }
  593. //-----------------------------------------------------------------
  594. void LogControl(LPCSTR pszOptions, BOOL fEcho)
  595. {
  596. ParseLogOptions(uLogOptions, "Log", pszOptions, fEcho);
  597. }
  598. //---------------------------------------------------------------------------
  599. DWORD StartTimer()
  600. {
  601. LARGE_INTEGER now;
  602. QueryPerformanceCounter(&now);
  603. return DWORD(now.QuadPart);
  604. }
  605. //---------------------------------------------------------------------------
  606. DWORD StopTimer(DWORD dwStartTime)
  607. {
  608. LARGE_INTEGER now;
  609. QueryPerformanceCounter(&now);
  610. return DWORD(now.QuadPart) - dwStartTime;
  611. }
  612. //---------------------------------------------------------------------------
  613. void TimeToStr(UINT uRaw, WCHAR *pszBuff, ULONG cchBuff)
  614. {
  615. LARGE_INTEGER freq;
  616. QueryPerformanceFrequency(&freq);
  617. DWORD Freq = (UINT)freq.QuadPart;
  618. const _int64 factor6 = 1000000;
  619. _int64 secs = uRaw*factor6/Freq;
  620. StringCchPrintfW(pszBuff, cchBuff, L"%u.%04u secs", UINT(secs/factor6), UINT(secs%factor6)/100);
  621. }
  622. //---------------------------------------------------------------------------
  623. BOOL LogOptionOn(int iLogOption)
  624. {
  625. if ((iLogOption < 0) || (iLogOption >= OPTIONCNT))
  626. return FALSE;
  627. return (uLogOptions[iLogOption] != 0);
  628. }
  629. //---------------------------------------------------------------------------