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.

1579 lines
42 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: T R A C E . C P P
  7. //
  8. // Contents: The actual tracing code (loading from ini, calling the
  9. // trace routines, etc.
  10. //
  11. // Notes:
  12. //
  13. // Author: jeffspr 9 Apr 1997
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.h>
  17. #pragma hdrstop
  18. #ifdef ENABLETRACE
  19. #include <stdio.h>
  20. #include "ncdebug.h"
  21. #include "ncbase.h"
  22. #define DBG_BUFFER_SIZE_SMALL (256)
  23. #define DBG_BUFFER_SIZE_LARGE (1024)
  24. //---[ CTracing class ]-------------------------------------------------------
  25. //
  26. // Don't give this class a constructor or destructor. We declare a global
  27. // (static to this module) instance of this class and, by definition, static
  28. // variables are automatically initialized to zero.
  29. //
  30. class CTracing
  31. {
  32. public:
  33. CTracing();
  34. // Initialize/Deinitialize this class
  35. //
  36. HRESULT HrInit();
  37. HRESULT HrUnInit();
  38. VOID Trace( TraceTagId ttid,
  39. PCSTR pszaTrace );
  40. private:
  41. BOOL m_fInitialized; // Has the object been initialized
  42. BOOL m_fAttemptedLogFileOpen; // Already attempted to open log
  43. BOOL m_fDisableLogFile; // Disable use of file logging?
  44. HANDLE m_hLogFile; // Handle for debug output file
  45. HANDLE m_hMutex;
  46. CHAR m_szLogFilePath[MAX_PATH+1]; // File for debug output
  47. BOOL m_fDebugFlagsLoaded; // Have these been loaded yet.
  48. VOID CorruptionCheck(); // Validate the tracetag structure
  49. HRESULT HrLoadOptionsFromIniFile();
  50. HRESULT HrLoadSectionsFromIniFile();
  51. HRESULT HrLoadDebugFlagsFromIniFile();
  52. HRESULT HrWriteDebugFlagsToIniFile();
  53. HRESULT HrOpenLogFile();
  54. HRESULT HrProcessTagSection(TraceTagElement * ptte);
  55. HRESULT HrGetPrivateProfileString( PCSTR lpAppName,
  56. PCSTR lpKeyName,
  57. PCSTR lpDefault,
  58. PSTR lpReturnedString,
  59. DWORD nSize,
  60. PCSTR lpFileName,
  61. DWORD * pcchReturn );
  62. BOOL FIniFileExists();
  63. };
  64. //---[ Static Variables ]-----------------------------------------------------
  65. static CTracing g_Tracing; // Our global tracing object
  66. //---[ Constants ]------------------------------------------------------------
  67. static const CHAR c_szaDebugIniFileName[] = "upnpdbg.ini"; // .INI file
  68. static const CHAR c_szaTraceLogFileName[] = "nctrace.log"; // .LOG file
  69. // constants for the INI file labels
  70. static const CHAR c_szaOptions[] = "Options";
  71. static const CHAR c_szaLogFilePath[] = "LogFilePath";
  72. static const CHAR c_szaDisableLogFile[] = "DisableLogFile";
  73. static const CHAR c_szaLogFileMutex[] = "UPNP_LOG_FILE_MUTEX";
  74. const INT c_iDefaultDisableLogFile = 0;
  75. //+---------------------------------------------------------------------------
  76. //
  77. // Function: HrInitTracing
  78. //
  79. // Purpose: Initialize the Tracing object and other random data.
  80. //
  81. // Arguments:
  82. // (none)
  83. //
  84. // Returns: S_OK or valid Win32 HRESULT
  85. //
  86. // Author: jeffspr 9 Apr 1997
  87. //
  88. // Notes:
  89. //
  90. HRESULT HrInitTracing()
  91. {
  92. HRESULT hr = g_Tracing.HrInit();
  93. return hr;
  94. }
  95. //+---------------------------------------------------------------------------
  96. //
  97. // Function: HrUnInitTracing
  98. //
  99. // Purpose: Uninitialize the tracing object.
  100. //
  101. // Arguments:
  102. // (none)
  103. //
  104. // Returns: S_OK or a valid Win32 HRESULT
  105. //
  106. // Author: jeffspr 14 Apr 1997
  107. //
  108. // Notes:
  109. //
  110. HRESULT HrUnInitTracing()
  111. {
  112. HRESULT hr = g_Tracing.HrUnInit();
  113. return hr;
  114. }
  115. const DWORD TI_HRESULT = 0x00000001;
  116. const DWORD TI_WIN32 = 0x00000002;
  117. const DWORD TI_IGNORABLE = 0x00000004;
  118. //+---------------------------------------------------------------------------
  119. //
  120. // Function: TraceInternal
  121. //
  122. // Purpose: The one and only place that a string to be traced is formed
  123. // and traced.
  124. //
  125. // Arguments:
  126. //
  127. // Returns: nothing.
  128. //
  129. // Author: shaunco 13 Mar 1998
  130. //
  131. // Notes: Restructured from lots of other code that was added to this
  132. // module over the past year.
  133. //
  134. VOID
  135. TraceInternal (
  136. TRACETAGID ttid,
  137. PCSTR pszaFile,
  138. INT nLine,
  139. DWORD dwFlags,
  140. PCSTR pszaCallerText,
  141. DWORD dwErrorCode)
  142. {
  143. // If this tracetag is turned off, don't do anything.
  144. //
  145. if (!g_TraceTags[ttid].fOutputDebugString &&
  146. !g_TraceTags[ttid].fOutputToFile)
  147. {
  148. return;
  149. }
  150. BOOL fError = dwFlags & (TI_HRESULT | TI_WIN32);
  151. BOOL fIgnorable = dwFlags & TI_IGNORABLE;
  152. HRESULT hr = (dwFlags & TI_HRESULT) ? dwErrorCode : S_OK;
  153. DWORD dwWin32Error = (dwFlags & TI_WIN32) ? dwErrorCode : ERROR_SUCCESS;
  154. // Ignore if told and we're not set to trace ignored errors or warnings.
  155. //
  156. if (fError && fIgnorable &&
  157. !FIsDebugFlagSet (dfidShowIgnoredErrors) &&
  158. !FIsDebugFlagSet (dfidExtremeTracing))
  159. {
  160. return;
  161. }
  162. // Don't do anything if we're tracing for an error and we don't have one,
  163. // unless the "Extreme Tracing" flag is on, in which case we trace
  164. // everything in the world (for debugger use only, really)
  165. // This is the path taken by TraceError ("...", S_OK) or
  166. // TraceLastWin32Error when there is no last Win32 error.
  167. //
  168. if (fError && !dwErrorCode && !FIsDebugFlagSet(dfidExtremeTracing))
  169. {
  170. return;
  171. }
  172. CHAR szaBuf [DBG_BUFFER_SIZE_LARGE];
  173. PSTR pcha = szaBuf;
  174. // Form the prefix, process id and thread id.
  175. //
  176. static const CHAR c_szaFmtPrefix [] = "UPNPDBG";
  177. lstrcpyA (pcha, c_szaFmtPrefix);
  178. pcha += lstrlenA (c_szaFmtPrefix);
  179. // Add process and thread ids if the debug flags indicate to do so.
  180. //
  181. if (FIsDebugFlagSet (dfidShowProcessAndThreadIds))
  182. {
  183. static const CHAR c_szaFmtPidAndTidDecimal [] = " %03d.%03d";
  184. static const CHAR c_szaFmtPidAndTidHex [] = " 0x%04x.0x%04x";
  185. LPCSTR pszaFmtPidAndTid = NULL;
  186. if (FIsDebugFlagSet (dfidShowIdsInHex))
  187. {
  188. pszaFmtPidAndTid = c_szaFmtPidAndTidHex;
  189. }
  190. else
  191. {
  192. pszaFmtPidAndTid = c_szaFmtPidAndTidDecimal;
  193. }
  194. pcha += wsprintfA (pcha, pszaFmtPidAndTid,
  195. GetCurrentProcessId (),
  196. GetCurrentThreadId ());
  197. }
  198. // Add a time stamp if the debug flags indicate to do so.
  199. //
  200. if (FIsDebugFlagSet (dfidTracingTimeStamps))
  201. {
  202. static const CHAR c_szaFmtTime [] = " [%02d:%02d:%02d.%03d]";
  203. SYSTEMTIME stLocal;
  204. GetLocalTime (&stLocal);
  205. pcha += wsprintfA (pcha, c_szaFmtTime,
  206. stLocal.wHour,
  207. stLocal.wMinute,
  208. stLocal.wSecond,
  209. stLocal.wMilliseconds);
  210. }
  211. // Add a severity indicator if this trace is for an error or warning.
  212. //
  213. if (fError || (ttidError == ttid))
  214. {
  215. static const CHAR c_szaSevIgnored [] = " Ignored:";
  216. static const CHAR c_szaSevError [] = " *ERROR*:";
  217. static const CHAR c_szaSevWarning [] = " Warning:";
  218. PCSTR pszaSev = NULL;
  219. if (fError && SUCCEEDED(hr) && !dwWin32Error && !fIgnorable)
  220. {
  221. pszaSev = c_szaSevWarning;
  222. }
  223. else
  224. {
  225. if (fIgnorable && FIsDebugFlagSet (dfidShowIgnoredErrors))
  226. {
  227. pszaSev = c_szaSevIgnored;
  228. }
  229. else
  230. {
  231. pszaSev = c_szaSevError;
  232. }
  233. }
  234. Assert (pszaSev);
  235. lstrcatA (pcha, pszaSev);
  236. pcha += lstrlenA (pszaSev);
  237. }
  238. // Add the tracetag short name. Don't do this for ttidError if
  239. // we already have the severity indicator from above.
  240. //
  241. if (ttid && (ttid < g_nTraceTagCount) && (ttid != ttidError))
  242. {
  243. static const CHAR c_szaFmtTraceTag [] = " (%s)";
  244. pcha += wsprintfA (pcha, c_szaFmtTraceTag,
  245. g_TraceTags[ttid].szShortName);
  246. }
  247. int nBytesCopied;
  248. int nBytesRemaining;
  249. // monitor bytes remaining from here on out...
  250. nBytesRemaining = sizeof(szaBuf) - (pcha - szaBuf);
  251. // Add the caller's text.
  252. //
  253. if (pszaCallerText)
  254. {
  255. static const CHAR c_szaFmtCallerText [] = " %s";
  256. // copy as many bytes as possible
  257. nBytesCopied = _snprintf (pcha,
  258. nBytesRemaining,
  259. c_szaFmtCallerText,
  260. pszaCallerText);
  261. // check for overflow
  262. if (nBytesCopied >= 0)
  263. {
  264. // increment pointer
  265. pcha += nBytesCopied;
  266. Assert (pcha > szaBuf);
  267. if ('\n' == *(pcha-1))
  268. {
  269. pcha--;
  270. *pcha = 0;
  271. }
  272. // update the number of bytes remaining...
  273. nBytesRemaining = sizeof(szaBuf) - (pcha - szaBuf);
  274. }
  275. else
  276. {
  277. // modify count
  278. nBytesRemaining = 0;
  279. }
  280. }
  281. // Add descriptive error text if this is an error and we can get some.
  282. //
  283. if ((nBytesRemaining > 0) && (FAILED(hr) || dwWin32Error))
  284. {
  285. BOOL fFacilityWin32 = (FACILITY_WIN32 == HRESULT_FACILITY(hr));
  286. // dwError will be the error code we pass to FormatMessage. It may
  287. // come from hr or dwWin32Error. Give preference to hr.
  288. //
  289. DWORD dwError = 0;
  290. if (fFacilityWin32)
  291. {
  292. dwError = HRESULT_CODE(hr);
  293. }
  294. else if (FAILED(hr))
  295. {
  296. dwError = hr;
  297. }
  298. else
  299. {
  300. dwError = dwWin32Error;
  301. }
  302. Assert (dwError);
  303. if (!FIsDebugFlagSet (dfidNoErrorText))
  304. {
  305. PSTR pszaErrorText = NULL;
  306. FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  307. FORMAT_MESSAGE_FROM_SYSTEM,
  308. NULL, dwError,
  309. MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
  310. (PSTR)&pszaErrorText, 0, NULL);
  311. if (pszaErrorText)
  312. {
  313. // Strip off newline characters.
  314. //
  315. PSTR pchText = pszaErrorText;
  316. while (*pchText && (*pchText != '\r') && (*pchText != '\n'))
  317. {
  318. pchText++;
  319. }
  320. *pchText = 0;
  321. // Add the error text.
  322. //
  323. static const CHAR c_szaFmtErrorText [] = " [%s]";
  324. // copy as many bytes as possible
  325. nBytesCopied = _snprintf (pcha,
  326. nBytesRemaining,
  327. c_szaFmtErrorText,
  328. pszaErrorText);
  329. // check for overflow
  330. if (nBytesCopied >= 0)
  331. {
  332. // increment pointer
  333. pcha += nBytesCopied;
  334. // update the number of bytes remaining...
  335. nBytesRemaining = sizeof(szaBuf) - (pcha - szaBuf);
  336. }
  337. else
  338. {
  339. // modify count
  340. nBytesRemaining = 0;
  341. }
  342. LocalFree (pszaErrorText);
  343. }
  344. }
  345. // Add the Win32 error code.
  346. //
  347. if ((nBytesRemaining > 0) && (fFacilityWin32 || dwWin32Error))
  348. {
  349. static const CHAR c_szaFmtWin32Error [] = " Win32=%d,0x%08X";
  350. // copy as many bytes as possible
  351. nBytesCopied = _snprintf (pcha,
  352. nBytesRemaining,
  353. c_szaFmtWin32Error,
  354. dwError, dwError);
  355. // check for overflow
  356. if (nBytesCopied >= 0)
  357. {
  358. // increment pointer
  359. pcha += nBytesCopied;
  360. // update the number of bytes remaining...
  361. nBytesRemaining = sizeof(szaBuf) - (pcha - szaBuf);
  362. }
  363. else
  364. {
  365. // modify count
  366. nBytesRemaining = 0;
  367. }
  368. }
  369. }
  370. // Add the HRESULT.
  371. //
  372. if ((nBytesRemaining > 0) && (S_OK != hr))
  373. {
  374. static const CHAR c_szaFmtHresult [] = " hr=0x%08X";
  375. // copy as many bytes as possible
  376. nBytesCopied = _snprintf (pcha,
  377. nBytesRemaining,
  378. c_szaFmtHresult,
  379. hr);
  380. // check for overflow
  381. if (nBytesCopied >= 0)
  382. {
  383. // increment pointer
  384. pcha += nBytesCopied;
  385. // update the number of bytes remaining...
  386. nBytesRemaining = sizeof(szaBuf) - (pcha - szaBuf);
  387. }
  388. else
  389. {
  390. // modify count
  391. nBytesRemaining = 0;
  392. }
  393. }
  394. // Add the file and line.
  395. //
  396. if ((nBytesRemaining > 0) && (pszaFile))
  397. {
  398. static const CHAR c_szaFmtFileAndLine [] = " File:%s,%d";
  399. // copy as many bytes as possible
  400. nBytesCopied = _snprintf (pcha,
  401. nBytesRemaining,
  402. c_szaFmtFileAndLine,
  403. pszaFile, nLine);
  404. // check for overflow
  405. if (nBytesCopied >= 0)
  406. {
  407. // increment pointer
  408. pcha += nBytesCopied;
  409. // update the number of bytes remaining...
  410. nBytesRemaining = sizeof(szaBuf) - (pcha - szaBuf);
  411. }
  412. else
  413. {
  414. // modify count
  415. nBytesRemaining = 0;
  416. }
  417. }
  418. // check for full string
  419. if (nBytesRemaining > 2)
  420. {
  421. lstrcatA (pcha, "\n");
  422. }
  423. else
  424. {
  425. // add new line & terminate full string
  426. szaBuf[sizeof(szaBuf) - 2] = '\n';
  427. szaBuf[sizeof(szaBuf) - 1] = '\0';
  428. }
  429. g_Tracing.Trace (ttid, szaBuf);
  430. // Now that the message is on the debugger, break if we have an error
  431. // and the debug flag to break on error is set.
  432. //
  433. if ((FAILED(hr) || dwWin32Error || (ttidError == ttid)) &&
  434. !fIgnorable && FIsDebugFlagSet(dfidBreakOnError))
  435. {
  436. DebugBreak();
  437. }
  438. }
  439. //+---------------------------------------------------------------------------
  440. //
  441. // Function: TraceErrorFn
  442. //
  443. // Purpose: Output debug trace of an HRESULT, allowing an additional
  444. // caller-defined error string.
  445. //
  446. // Arguments:
  447. // sz [] Caller-defined additional error text
  448. // hr [] The error HRESULT.
  449. //
  450. // Returns:
  451. //
  452. // Author: jeffspr 14 Apr 1997
  453. //
  454. // Notes:
  455. //
  456. VOID
  457. WINAPI
  458. TraceErrorFn (
  459. PCSTR pszaFile,
  460. INT nLine,
  461. PCSTR psza,
  462. HRESULT hr)
  463. {
  464. TraceInternal (ttidError, pszaFile, nLine, TI_HRESULT, psza, hr);
  465. }
  466. VOID
  467. WINAPI
  468. TraceResultFn (
  469. PCSTR pszaFile,
  470. INT nLine,
  471. PCSTR psza,
  472. BOOL f)
  473. {
  474. if (!f)
  475. {
  476. TraceInternal (ttidError, pszaFile, nLine, TI_WIN32, psza,
  477. GetLastError());
  478. }
  479. }
  480. //+---------------------------------------------------------------------------
  481. //
  482. // Function: TraceErrorOptionalFn
  483. //
  484. // Purpose: Implements TraceErrorOptional macro
  485. //
  486. // Arguments:
  487. // pszaFile [in] __FILE__ value
  488. // nLine [in] __LINE__ value
  489. // psza [in] String to trace.
  490. // hr [in] HRESULT value to trace.
  491. // fOpt [in] TRUE if error should be treated as optional, FALSE if
  492. // ERROR is not optional and should be reported thru
  493. // TraceError().
  494. //
  495. // Returns: Nothing.
  496. //
  497. // Author: danielwe 12 May 1997
  498. //
  499. // Notes:
  500. //
  501. VOID
  502. WINAPI
  503. TraceErrorOptionalFn (
  504. PCSTR pszaFile,
  505. INT nLine,
  506. PCSTR psza,
  507. HRESULT hr,
  508. BOOL fIgnorable)
  509. {
  510. DWORD dwFlags = TI_HRESULT;
  511. if (fIgnorable)
  512. {
  513. dwFlags |= TI_IGNORABLE;
  514. }
  515. TraceInternal (ttidError, pszaFile, nLine, dwFlags, psza, hr);
  516. }
  517. //+---------------------------------------------------------------------------
  518. //
  519. // Function: TraceErrorSkipFn
  520. //
  521. // Purpose: Implements TraceErrorOptional macro
  522. //
  523. // Arguments:
  524. // pszaFile [in] __FILE__ value
  525. // nLine [in] __LINE__ value
  526. // psza [in] String to trace.
  527. // hr [in] HRESULT value to trace.
  528. // c [in] count of pass-through Hresults. if hr is any of these
  529. // the error is treated as optional.
  530. // ... [in] list of hresults.
  531. //
  532. // Returns: Nothing.
  533. //
  534. // Author: sumitc 08 Jan 1998
  535. //
  536. // Notes:
  537. //
  538. VOID WINAPI
  539. TraceErrorSkipFn (
  540. PCSTR pszaFile,
  541. INT nLine,
  542. PCSTR psza,
  543. HRESULT hr,
  544. UINT c, ...)
  545. {
  546. va_list valMarker;
  547. BOOL fIgnorable = FALSE;
  548. va_start(valMarker, c);
  549. for (UINT i = 0; i < c; ++i)
  550. {
  551. fIgnorable = (va_arg(valMarker, HRESULT) == hr);
  552. if (fIgnorable)
  553. {
  554. break;
  555. }
  556. }
  557. va_end(valMarker);
  558. DWORD dwFlags = TI_HRESULT;
  559. if (fIgnorable)
  560. {
  561. dwFlags |= TI_IGNORABLE;
  562. }
  563. TraceInternal (ttidError, pszaFile, nLine, dwFlags, psza, hr);
  564. }
  565. //+---------------------------------------------------------------------------
  566. //
  567. // Function: TraceLastWin32ErrorFn
  568. //
  569. // Purpose: Trace the last Win32 error, which we get with GetLastError().
  570. // Not a whole lot to it.
  571. //
  572. // Arguments:
  573. // sz [] Additional error text.
  574. //
  575. // Returns:
  576. //
  577. // Author: jeffspr 14 Apr 1997
  578. //
  579. // Notes:
  580. //
  581. VOID
  582. WINAPIV
  583. TraceLastWin32ErrorFn (
  584. PCSTR pszaFile,
  585. INT nLine,
  586. PCSTR psza)
  587. {
  588. TraceInternal (ttidError, pszaFile, nLine, TI_WIN32, psza, GetLastError());
  589. }
  590. //+---------------------------------------------------------------------------
  591. //
  592. // Function: TraceHr
  593. //
  594. // Purpose: Generic replacement for the TraceErrorOptional, TraceError,
  595. // and a couple other random functions.
  596. //
  597. // Arguments:
  598. // ttid [] TraceTag to use for the debug output
  599. // pszaFile [] Source file to log
  600. // nLine [] Line number to log
  601. // hr [] Error to log
  602. // fIgnorable [] Ignore this error? (The optional bit)
  603. // pszaFmt [] Format of the vargs
  604. //
  605. // Returns:
  606. //
  607. // Author: jeffspr 10 Oct 1997
  608. //
  609. // Notes:
  610. //
  611. VOID
  612. WINAPIV
  613. TraceHr (
  614. TRACETAGID ttid,
  615. PCSTR pszaFile,
  616. INT nLine,
  617. HRESULT hr,
  618. BOOL fIgnorable,
  619. PCSTR pszaFmt,
  620. ...)
  621. {
  622. // If this tracetag is turned off, don't do anything.
  623. //
  624. if (!g_TraceTags[ttid].fOutputDebugString &&
  625. !g_TraceTags[ttid].fOutputToFile)
  626. {
  627. return;
  628. }
  629. CHAR szaBuf [DBG_BUFFER_SIZE_SMALL];
  630. // Build the string from the varg list
  631. //
  632. va_list valMarker;
  633. va_start (valMarker, pszaFmt);
  634. // copy as many bytes as possible
  635. _vsnprintf (szaBuf, sizeof(szaBuf), pszaFmt, valMarker);
  636. // terminate full string
  637. szaBuf[sizeof(szaBuf) - 1] = '\0';
  638. va_end (valMarker);
  639. DWORD dwFlags = TI_HRESULT;
  640. if (fIgnorable)
  641. {
  642. dwFlags |= TI_IGNORABLE;
  643. }
  644. TraceInternal (ttid, pszaFile, nLine, dwFlags, szaBuf, hr);
  645. }
  646. //+---------------------------------------------------------------------------
  647. //
  648. // Function: TraceTag
  649. //
  650. // Purpose: Output a debug trace to one or more trace targets (ODS,
  651. // File, COM port, etc.). This function determines the targets
  652. // and performs the actual trace.
  653. //
  654. // Arguments:
  655. // ttid [] TraceTag to use for the debug output
  656. // pszaFmt [] Format of the vargs.
  657. //
  658. // Returns:
  659. //
  660. // Author: jeffspr 14 Apr 1997
  661. //
  662. // Notes:
  663. //
  664. VOID
  665. WINAPIV
  666. TraceTag (
  667. TRACETAGID ttid,
  668. PCSTR pszaFmt,
  669. ...)
  670. {
  671. // If this tracetag is turned off, don't do anything.
  672. //
  673. if (!g_TraceTags[ttid].fOutputDebugString &&
  674. !g_TraceTags[ttid].fOutputToFile)
  675. {
  676. return;
  677. }
  678. CHAR szaBuf [DBG_BUFFER_SIZE_SMALL];
  679. // Build the string from the varg list
  680. //
  681. va_list valMarker;
  682. va_start (valMarker, pszaFmt);
  683. // copy as many bytes as possible
  684. _vsnprintf (szaBuf, sizeof(szaBuf), pszaFmt, valMarker);
  685. // terminate full string
  686. szaBuf[sizeof(szaBuf) - 1] = '\0';
  687. va_end (valMarker);
  688. TraceInternal (ttid, NULL, 0, 0, szaBuf, 0);
  689. }
  690. //+---------------------------------------------------------------------------
  691. //
  692. // Member: CTracing::CTracing
  693. //
  694. // Purpose: Constructor for CTracing. Initialize all vars.
  695. //
  696. // Arguments:
  697. // (none)
  698. //
  699. // Returns:
  700. //
  701. // Author: jeffspr 23 Jan 1999
  702. //
  703. // Notes:
  704. //
  705. CTracing::CTracing()
  706. {
  707. m_fInitialized = FALSE; // Has the object been initialized
  708. m_fAttemptedLogFileOpen = FALSE; // Already attempted to open log
  709. m_fDisableLogFile = FALSE; // Disable use of file logging?
  710. m_hLogFile = NULL; // Handle for debug output file
  711. m_szLogFilePath[0] = '\0'; // File for debug output
  712. m_fDebugFlagsLoaded = FALSE; // Have these been loaded yet.
  713. }
  714. //+---------------------------------------------------------------------------
  715. //
  716. // Member: CTracing::HrInit
  717. //
  718. // Purpose: Initialize the CTracing object.
  719. //
  720. // Arguments:
  721. // (none)
  722. //
  723. // Returns: S_OK or valid Win32 HRESULT
  724. //
  725. // Author: jeffspr 9 Apr 1997
  726. //
  727. // Notes: This should get called from some standard exe initialization
  728. // point. And make sure to call HrDeinit when you're done, eh?
  729. //
  730. HRESULT CTracing::HrInit()
  731. {
  732. HRESULT hr = S_OK;
  733. AssertSz(!m_fInitialized,
  734. "CTracing::HrInit -- Let's not go overboard. Already initialized");
  735. // Temporarily set this so the called functions don't believe that we're
  736. // uninitialized. At Exit, if we fail, we'll set it back so no-one tries
  737. // to call these functions when uninitialized.
  738. //
  739. m_fInitialized = TRUE;
  740. // Check for corruptions in the tracing structure. This can't fail, but
  741. // it will send up asserts all over the place if something is amiss.
  742. //
  743. CorruptionCheck();
  744. // Load the "options" section from the ini file
  745. //
  746. hr = HrLoadOptionsFromIniFile();
  747. if (FAILED(hr))
  748. {
  749. goto Exit;
  750. }
  751. // Load the DebugFlags section from the ini file.
  752. //
  753. hr = HrLoadDebugFlagsFromIniFile();
  754. if (FAILED(hr))
  755. {
  756. goto Exit;
  757. }
  758. // Load the tracetag sections from the ini file.
  759. // Make sure this is called after HrLoadDebugFlagsFromIniFile(),
  760. // as those options will affect the tracetag sections (we also
  761. // assert on this)
  762. //
  763. hr = HrLoadSectionsFromIniFile();
  764. if (FAILED(hr))
  765. {
  766. goto Exit;
  767. }
  768. Exit:
  769. if (FAILED(hr))
  770. {
  771. m_fInitialized = FALSE;
  772. }
  773. return hr;
  774. }
  775. //+---------------------------------------------------------------------------
  776. //
  777. // Member: CTracing::HrUnInit
  778. //
  779. // Purpose: Uninitialize the Tracing object
  780. //
  781. // Arguments:
  782. // (none)
  783. //
  784. // Returns: S_OK or valid Win32 HRESULT
  785. //
  786. // Author: jeffspr 12 Apr 1997
  787. //
  788. // Notes:
  789. //
  790. HRESULT CTracing::HrUnInit()
  791. {
  792. HRESULT hr = S_OK;
  793. // Don't assert on m_fInitialized here, because we allow this to
  794. // be called even if initialization failed.
  795. //
  796. if (m_fInitialized)
  797. {
  798. hr = HrWriteDebugFlagsToIniFile();
  799. if (FAILED(hr))
  800. {
  801. // continue on, but I want to know why this is failing.
  802. AssertSz(FALSE, "Whoa, why can't we write the debug flags?");
  803. }
  804. // Close the log file, if there's one open
  805. //
  806. if (m_hLogFile)
  807. {
  808. CloseHandle(m_hLogFile);
  809. m_hLogFile = NULL;
  810. m_fAttemptedLogFileOpen = FALSE;
  811. }
  812. if (m_hMutex)
  813. {
  814. CloseHandle(m_hMutex);
  815. }
  816. // Mark us as being uninitialized.
  817. //
  818. m_fInitialized = FALSE;
  819. }
  820. return hr;
  821. }
  822. //+---------------------------------------------------------------------------
  823. //
  824. // Member: CTracing::HrGetPrivateProfileString
  825. //
  826. // Purpose:
  827. //
  828. // Arguments:
  829. // lpAppName [] points to section name
  830. // lpKeyName [] points to key name
  831. // lpDefault [] points to default string
  832. // lpReturnedString [] points to destination buffer
  833. // nSize [] size of destination buffer
  834. // lpFileName [] points to initialization filename
  835. // pcchReturn return buffer for the old Win32 API return code
  836. //
  837. //
  838. // Returns: S_OK or valid Win32 HRESULT
  839. //
  840. // Author: jeffspr 12 Apr 1997
  841. //
  842. // Notes:
  843. //
  844. HRESULT CTracing::HrGetPrivateProfileString( PCSTR lpAppName,
  845. PCSTR lpKeyName,
  846. PCSTR lpDefault,
  847. PSTR lpReturnedString,
  848. DWORD nSize,
  849. PCSTR lpFileName,
  850. DWORD* pcchReturn
  851. )
  852. {
  853. HRESULT hr = S_OK;
  854. Assert(m_fInitialized);
  855. // Assert on the known conditions required for this API call
  856. //
  857. Assert(lpDefault);
  858. Assert(lpFileName);
  859. // Call the Win32 API
  860. //
  861. DWORD dwGPPSResult = GetPrivateProfileStringA(
  862. lpAppName,
  863. lpKeyName,
  864. lpDefault,
  865. lpReturnedString,
  866. nSize,
  867. lpFileName);
  868. // Check to see if we've gotten a string-size error
  869. if (lpAppName && lpKeyName)
  870. {
  871. // If we get back (nSize - 1), then our string buffer wasn't
  872. // large enough
  873. //
  874. if (dwGPPSResult == (nSize - 1))
  875. {
  876. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  877. goto Exit;
  878. }
  879. }
  880. else
  881. {
  882. // Since either of the app name or key name are NULL, then
  883. // we're supposed to be receiving a doubly-NULL terminated
  884. // list of strings. If we're at (nSize - 2), that means
  885. // our buffer was too small.
  886. //
  887. if (dwGPPSResult == (nSize - 2))
  888. {
  889. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  890. goto Exit;
  891. }
  892. }
  893. Exit:
  894. *pcchReturn = dwGPPSResult;
  895. return hr;
  896. }
  897. //+---------------------------------------------------------------------------
  898. //
  899. // Member: CTracing::HrLoadOptionsFromIniFile
  900. //
  901. // Purpose: Load the options section from the ini file, and set our
  902. // state accordingly
  903. //
  904. // Arguments:
  905. // (none)
  906. //
  907. // Returns: S_OK or valid Win32 HRESULT
  908. //
  909. // Author: jeffspr 10 Apr 1997
  910. //
  911. // Notes:
  912. //
  913. HRESULT CTracing::HrLoadOptionsFromIniFile()
  914. {
  915. HRESULT hr = S_OK;
  916. DWORD cchReturnBufferSize = 0;
  917. CHAR szaLogFilePath[MAX_PATH+1] = { 0 };
  918. DWORD dwTempPathLength = 0;
  919. // Get the explicit log file path, if any. If it doesn't exist, then
  920. // use the default path, which is the temp file path plus the default
  921. // trace file name
  922. //
  923. // Get the location of the "temporary files" path
  924. dwTempPathLength = GetTempPathA(MAX_PATH, szaLogFilePath);
  925. if ((dwTempPathLength == 0) ||
  926. (dwTempPathLength > MAX_PATH))
  927. {
  928. TraceLastWin32Error("GetTempPath failure");
  929. hr = HrFromLastWin32Error();
  930. goto Exit;
  931. }
  932. // Tack the log file name onto the end.
  933. //
  934. wsprintfA(m_szLogFilePath, "%s%s", szaLogFilePath, c_szaTraceLogFileName);
  935. // This will overwrite the log file path if one exists in the INI file
  936. //
  937. hr = HrGetPrivateProfileString(
  938. c_szaOptions, // "Options"
  939. c_szaLogFilePath, // "LogFilePath
  940. m_szLogFilePath, // Default string, already filled
  941. m_szLogFilePath, // Return string (same string)
  942. MAX_PATH+1,
  943. c_szaDebugIniFileName,
  944. &cchReturnBufferSize);
  945. if (FAILED(hr))
  946. {
  947. // This should not cause problems with recursive failure, since
  948. // Traces will work regardless of the state of trace initialization.
  949. //
  950. TraceError(
  951. "GetPrivateProfileString failed on Options::LogFilePath", hr);
  952. goto Exit;
  953. }
  954. // Get the "disable log file option". No return code here.
  955. m_fDisableLogFile = GetPrivateProfileIntA(
  956. c_szaOptions, // "Options"
  957. c_szaDisableLogFile, // "DisableLogFile"
  958. c_iDefaultDisableLogFile,
  959. c_szaDebugIniFileName);
  960. if (FAILED(hr))
  961. {
  962. TraceError(
  963. "GetPrivateProfileInt failed on Options::DisableLogFile", hr);
  964. goto Exit;
  965. }
  966. Exit:
  967. return hr;
  968. }
  969. //+---------------------------------------------------------------------------
  970. //
  971. // Member: CTracing::HrLoadSectionsFromIniFile
  972. //
  973. // Purpose: Load the individual tracetag sections from the ini file, and
  974. // set our array elements accordingly, defaulting if necessary.
  975. //
  976. // Arguments:
  977. // (none)
  978. //
  979. // Returns: S_OK or valid Win32 HRESULT
  980. //
  981. // Author: jeffspr 10 Apr 1997
  982. //
  983. // Notes:
  984. //
  985. HRESULT CTracing::HrLoadSectionsFromIniFile()
  986. {
  987. HRESULT hr = S_OK;
  988. // Make sure that we've loaded the debug flags first, as they can
  989. // affect each tracetag section
  990. //
  991. Assert(m_fDebugFlagsLoaded);
  992. // Loop through the array and load the data.
  993. //
  994. for (INT nLoop = 0; nLoop < g_nTraceTagCount; nLoop++ )
  995. {
  996. // Process the individual lines from the section
  997. hr = HrProcessTagSection(&(g_TraceTags[nLoop]));
  998. if (FAILED(hr))
  999. {
  1000. break;
  1001. }
  1002. }
  1003. return hr;
  1004. }
  1005. //+---------------------------------------------------------------------------
  1006. //
  1007. // Member: CTracing::HrLoadDebugFlagsFromIniFile
  1008. //
  1009. // Purpose: Load the individual debugflag values from the ini file, and
  1010. // set our array elements accordingly, defaulting if necessary.
  1011. //
  1012. // Arguments:
  1013. // (none)
  1014. //
  1015. // Returns: S_OK or valid Win32 HRESULT
  1016. //
  1017. // Author: jeffspr 10 Apr 1997
  1018. //
  1019. // Notes:
  1020. //
  1021. HRESULT CTracing::HrLoadDebugFlagsFromIniFile()
  1022. {
  1023. HRESULT hr = S_OK;
  1024. INT nLoop;
  1025. // Loop through the array and load the data.
  1026. //
  1027. for (nLoop = 0; nLoop < g_nDebugFlagCount; nLoop++)
  1028. {
  1029. // Get the enabled file param
  1030. //
  1031. g_DebugFlags[nLoop].dwValue = GetPrivateProfileIntA(
  1032. "DebugFlags",
  1033. g_DebugFlags[nLoop].szShortName,
  1034. FALSE,
  1035. c_szaDebugIniFileName);
  1036. }
  1037. if (SUCCEEDED(hr))
  1038. {
  1039. m_fDebugFlagsLoaded = TRUE;
  1040. }
  1041. return hr;
  1042. }
  1043. BOOL CTracing::FIniFileExists()
  1044. {
  1045. BOOL fReturn = TRUE;
  1046. CHAR szaPath[MAX_PATH+1] = "";
  1047. UINT uiCharsReturned = 0;
  1048. HANDLE hFile = INVALID_HANDLE_VALUE;
  1049. uiCharsReturned =
  1050. GetWindowsDirectoryA(szaPath, MAX_PATH);
  1051. if ((uiCharsReturned == 0) || (uiCharsReturned > MAX_PATH))
  1052. {
  1053. AssertSz(FALSE, "GetWindowsDirectory failed in CTracing::FIniFileExists");
  1054. fReturn = FALSE;
  1055. goto Exit;
  1056. }
  1057. lstrcatA (szaPath, "\\");
  1058. lstrcatA (szaPath, c_szaDebugIniFileName);
  1059. hFile = CreateFileA(
  1060. szaPath,
  1061. GENERIC_READ,
  1062. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1063. NULL,
  1064. OPEN_EXISTING,
  1065. FILE_ATTRIBUTE_NORMAL,
  1066. NULL);
  1067. if (hFile == INVALID_HANDLE_VALUE)
  1068. {
  1069. DWORD dwLastError = GetLastError();
  1070. if (dwLastError != ERROR_FILE_NOT_FOUND)
  1071. {
  1072. AssertSz(FALSE, "FIniFileExists failed for some reason other than FILE_NOT_FOUND");
  1073. }
  1074. fReturn = FALSE;
  1075. goto Exit;
  1076. }
  1077. Exit:
  1078. if (hFile)
  1079. {
  1080. CloseHandle(hFile);
  1081. hFile = NULL;
  1082. }
  1083. return fReturn;
  1084. }
  1085. HRESULT CTracing::HrWriteDebugFlagsToIniFile()
  1086. {
  1087. HRESULT hr = S_OK;
  1088. // First, check to see if the file exists. If it doesn't, then we don't want
  1089. // to write the entries.
  1090. //
  1091. if (FIniFileExists())
  1092. {
  1093. // Loop through the array and write the data.
  1094. //
  1095. for (INT nLoop = 0; nLoop < g_nDebugFlagCount; nLoop++)
  1096. {
  1097. CHAR szInt[16]; // Sure, it's arbitrary, but it's also OK.
  1098. switch(nLoop)
  1099. {
  1100. // These store a DWORD in its standard form
  1101. //
  1102. case dfidBreakOnHr:
  1103. case dfidBreakOnHrIteration:
  1104. case dfidBreakOnIteration:
  1105. wsprintfA( szInt, "%d", g_DebugFlags[nLoop].dwValue);
  1106. break;
  1107. // default are treated as boolean, and stored that way
  1108. //
  1109. default:
  1110. // !! means it will always be 1 or 0.
  1111. wsprintfA( szInt, "%d", (!!g_DebugFlags[nLoop].dwValue));
  1112. break;
  1113. }
  1114. // Write the param to the ini file
  1115. WritePrivateProfileStringA(
  1116. "DebugFlags",
  1117. g_DebugFlags[nLoop].szShortName,
  1118. szInt,
  1119. c_szaDebugIniFileName);
  1120. }
  1121. }
  1122. // For now, this is always S_OK, since there's nothing above that can
  1123. // fail.
  1124. //
  1125. return hr;
  1126. }
  1127. //+---------------------------------------------------------------------------
  1128. //
  1129. // Member: CTracing::HrProcessTagSection
  1130. //
  1131. // Purpose: Grab the parameters from the ini file. If they're not
  1132. // available, then use the settings in default. Note - this
  1133. // will always work because ttidDefault will always be the first
  1134. // element. If a [default] section wasn't present, then it will
  1135. // be using the settings that were in the struct initialization,
  1136. // which is also fine.
  1137. //
  1138. // Arguments:
  1139. // ptte [] TraceTag element to load
  1140. //
  1141. // Returns:
  1142. //
  1143. // Author: jeffspr 15 Apr 1997
  1144. //
  1145. // Notes:
  1146. //
  1147. HRESULT CTracing::HrProcessTagSection( TraceTagElement * ptte )
  1148. {
  1149. HRESULT hr = S_OK;
  1150. AssertSz(m_fInitialized,
  1151. "CTracing::HrProcessTagSection. Class not initialized");
  1152. AssertSz(ptte, "CTracing::HrProcessTagSection -- invalid ptte");
  1153. // Get the output to file param
  1154. //
  1155. ptte->fOutputToFile = GetPrivateProfileIntA(
  1156. ptte->szShortName,
  1157. "OutputToFile",
  1158. ptte->fVerboseOnly ?
  1159. FALSE : g_TraceTags[ttidDefault].fOutputToFile,
  1160. c_szaDebugIniFileName);
  1161. // Get the OutputDebugString param. Require that the error tag
  1162. // always has at least output debug string on.
  1163. //
  1164. if (ptte->ttid == ttidError)
  1165. {
  1166. ptte->fOutputDebugString = TRUE;
  1167. }
  1168. else
  1169. {
  1170. // Load the OutputToDebug
  1171. ptte->fOutputDebugString = GetPrivateProfileIntA(
  1172. ptte->szShortName,
  1173. "OutputToDebug",
  1174. ptte->fVerboseOnly ?
  1175. FALSE : g_TraceTags[ttidDefault].fOutputDebugString,
  1176. c_szaDebugIniFileName);
  1177. }
  1178. return hr;
  1179. }
  1180. //+---------------------------------------------------------------------------
  1181. //
  1182. // Member: CTracing::CorruptionCheck
  1183. //
  1184. // Purpose: Validate the tracetag array. Check to see that the
  1185. // shortnames are valid, that the descriptions are valid,
  1186. // and that the tracetag elements are not out of order.
  1187. // Also verify that the correct number of tracetag elements
  1188. // exist.
  1189. //
  1190. // Arguments:
  1191. // (none)
  1192. //
  1193. // Returns:
  1194. //
  1195. // Author: jeffspr 15 Apr 1997
  1196. //
  1197. // Notes:
  1198. // (shaunco) 16 Jul 1997: This is #if'defd out until JVert
  1199. // gives us a fix for the alpha compiler. It blows up compiling this
  1200. // function in retail.
  1201. //
  1202. // (jeffspr) Tough noogies for JVert - I need this code. Hopefully
  1203. // this has been fixed by now.
  1204. //
  1205. VOID CTracing::CorruptionCheck()
  1206. {
  1207. INT nLoop = 0;
  1208. // Validate the tracetag structure
  1209. //
  1210. for (nLoop = 0; nLoop < g_nTraceTagCount; nLoop++)
  1211. {
  1212. // Verify that we're not out of order or missing ttids
  1213. //
  1214. AssertSz(g_TraceTags[nLoop].ttid == nLoop,
  1215. "Invalid ttid in the tracetag structure. Out of order. " \
  1216. "CTracing::CorruptionCheck");
  1217. AssertSz(g_TraceTags[nLoop].ttid < g_nTraceTagCount,
  1218. "Invalid ttid (out of range) in CTracing::CorruptionCheck");
  1219. // Validate the shortname (verify not NULL or empty strings)
  1220. //
  1221. AssertSz(g_TraceTags[nLoop].szShortName,
  1222. "Invalid tracetag short name (NULL) in CTracing::CorruptionCheck");
  1223. AssertSz(g_TraceTags[nLoop].szShortName[0] != 0,
  1224. "Invalid tracetagshort name (empty) in CTracing::CorruptionCheck");
  1225. // Validate the descriptions (verify not NULL or empty strings)
  1226. //
  1227. AssertSz(g_TraceTags[nLoop].szDescription,
  1228. "Invalid tracetagdescription in CTracing::CorruptionCheck");
  1229. AssertSz(g_TraceTags[nLoop].szDescription[0] != 0,
  1230. "Invalid tracetagdescription (empty) in CTracing::CorruptionCheck");
  1231. }
  1232. // Validate the debug flags structure
  1233. //
  1234. for (nLoop = 0; nLoop < g_nDebugFlagCount; nLoop++)
  1235. {
  1236. // Verify that we're not out of order or missing dfids
  1237. //
  1238. AssertSz(g_DebugFlags[nLoop].dfid == nLoop,
  1239. "Invalid dfid in the debugflag structure. Out of order. " \
  1240. "CTracing::CorruptionCheck");
  1241. AssertSz(g_DebugFlags[nLoop].dfid < g_nDebugFlagCount,
  1242. "Invalid dfid (out of range) in CTracing::CorruptionCheck");
  1243. // Validate the shortname (verify not NULL or empty strings)
  1244. //
  1245. AssertSz(g_DebugFlags[nLoop].szShortName,
  1246. "Invalid debug flag short name (NULL) in CTracing::CorruptionCheck");
  1247. AssertSz(g_DebugFlags[nLoop].szShortName[0] != 0,
  1248. "Invalid debug flag short name (empty) in CTracing::CorruptionCheck");
  1249. // Validate the descriptions (verify not NULL or empty strings)
  1250. //
  1251. AssertSz(g_DebugFlags[nLoop].szDescription,
  1252. "Invalid debug flag description in CTracing::CorruptionCheck");
  1253. AssertSz(g_DebugFlags[nLoop].szDescription[0] != 0,
  1254. "Invalid debug flag description (empty) in CTracing::CorruptionCheck");
  1255. }
  1256. return;
  1257. }
  1258. //+---------------------------------------------------------------------------
  1259. //
  1260. // Member: CTracing::Trace
  1261. //
  1262. // Purpose: The actual trace call that takes care of doing the output
  1263. // to each trace target (file, OutputDebugString, etc.)
  1264. //
  1265. // Arguments:
  1266. // ttid [] The tracetag to use for output
  1267. // pszaTrace [] The trace string itself.
  1268. //
  1269. // Returns:
  1270. //
  1271. // Author: jeffspr 12 Apr 1997
  1272. //
  1273. // Notes:
  1274. //
  1275. VOID CTracing::Trace( TraceTagId ttid,
  1276. PCSTR pszaTrace )
  1277. {
  1278. // HrInit should have called a corruption checker for the entire trace
  1279. // block, but we'll check again just to make sure.
  1280. //
  1281. AssertSz(g_nTraceTagCount > ttid, "ttid out of range in CTracing::Trace");
  1282. AssertSz(g_TraceTags[ttid].ttid == ttid,
  1283. "TraceTag structure is corrupt in CTracing::Trace");
  1284. // If they want debug string output
  1285. //
  1286. if (g_TraceTags[ttid].fOutputDebugString)
  1287. {
  1288. // Then output the string
  1289. //
  1290. OutputDebugStringA(pszaTrace);
  1291. }
  1292. // If they want file output
  1293. if (g_TraceTags[ttid].fOutputToFile)
  1294. {
  1295. if (!m_hLogFile)
  1296. {
  1297. // Assuming that we haven't already tried to open the file
  1298. // and failed, open it.
  1299. if (!m_fAttemptedLogFileOpen)
  1300. {
  1301. HRESULT hr = HrOpenLogFile();
  1302. if (FAILED(hr))
  1303. {
  1304. AssertSz(FALSE, "Failed to open log file for tracing. No, "
  1305. "this isn't a coding error, but hey, figured that "
  1306. "you'd want to know...");
  1307. }
  1308. }
  1309. }
  1310. // If we were already open, or the open has now succeeded, do the
  1311. // trace
  1312. //
  1313. if (m_hLogFile)
  1314. {
  1315. Assert(pszaTrace);
  1316. // Since pszTrace is guaranteed to be a single-byte trace, we
  1317. // don't need to do the WCHAR multiply on the length, just
  1318. // a char multiply.
  1319. //
  1320. DWORD dwBytesToWrite = lstrlenA(pszaTrace) * sizeof(CHAR);
  1321. DWORD dwBytesWritten = 0;
  1322. BOOL fWriteResult = FALSE;
  1323. WaitForSingleObject(m_hMutex, INFINITE);
  1324. fWriteResult = WriteFile(
  1325. m_hLogFile, // handle to file to write to
  1326. pszaTrace, // pointer to data to write to file
  1327. dwBytesToWrite, // size of trace
  1328. &dwBytesWritten, // Bytes actually written.
  1329. NULL ); // No overlapped
  1330. ReleaseMutex(m_hMutex);
  1331. if (!fWriteResult || (dwBytesToWrite != dwBytesWritten))
  1332. {
  1333. AssertSz(FALSE, "CTracing failure: Can't write to log file."
  1334. " Can't trace or we'll be recursing on this failure.");
  1335. }
  1336. }
  1337. }
  1338. }
  1339. HRESULT CTracing::HrOpenLogFile()
  1340. {
  1341. HRESULT hr = S_OK;
  1342. SECURITY_ATTRIBUTES sa = {0};
  1343. SECURITY_DESCRIPTOR sd = {0};
  1344. InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
  1345. SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
  1346. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  1347. sa.bInheritHandle = FALSE;
  1348. sa.lpSecurityDescriptor = &sd;
  1349. AssertSz(m_fInitialized,
  1350. "CTracing not initialized in HrOpenLogFile()");
  1351. AssertSz(!m_hLogFile,
  1352. "File already open before call to HrOpenLogFile()");
  1353. // Mark us as having attempted to open the file, so we don't call this
  1354. // function everytime we log, if we can't open it.
  1355. //
  1356. m_fAttemptedLogFileOpen = TRUE;
  1357. m_hMutex = CreateMutexA(&sa, FALSE, c_szaLogFileMutex);
  1358. if (!m_hMutex)
  1359. {
  1360. hr = HrFromLastWin32Error();
  1361. goto Exit;
  1362. }
  1363. WaitForSingleObject(m_hMutex, INFINITE);
  1364. // $$TODO (jeffspr) - Allow flags in the Options section of the ini
  1365. // file specify the create flags and attributes, which would allow
  1366. // us to control the overwriting of log files and/or the write-through
  1367. // properties.
  1368. //
  1369. // Actually open the file, creating if necessary.
  1370. //
  1371. m_hLogFile = CreateFileA(
  1372. m_szLogFilePath, // Pointer to name of file
  1373. GENERIC_READ | GENERIC_WRITE, // access (read-write) mode
  1374. FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode (allow read access)
  1375. NULL, // pointer to security attributes
  1376. OPEN_ALWAYS, // how to create
  1377. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
  1378. NULL);
  1379. if (INVALID_HANDLE_VALUE == m_hLogFile)
  1380. {
  1381. m_hLogFile = NULL;
  1382. hr = HrFromLastWin32Error();
  1383. goto ExitAndRelease;
  1384. }
  1385. SetFilePointer(m_hLogFile, 0, NULL, FILE_END);
  1386. ExitAndRelease:
  1387. ReleaseMutex(m_hMutex);
  1388. Exit:
  1389. return hr;
  1390. }
  1391. #endif // ENABLETRACE