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.

1445 lines
38 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: cmlog.cpp
  4. //
  5. // Module: CMLOG.LIB
  6. //
  7. // Synopsis: Connection Manager Logging File i/o class
  8. //
  9. // Copyright (c) 1998-2000 Microsoft Corporation
  10. //
  11. // Author: 25-May-2000 SumitC Created
  12. //
  13. // Note:
  14. //
  15. //-----------------------------------------------------------------------------
  16. #define CMLOG_IMPLEMENTATION
  17. #ifndef UNICODE
  18. #define UNICODE
  19. #endif
  20. #include <windows.h>
  21. #include <psapi.h>
  22. #include <tlhelp32.h>
  23. #include "cmmaster.h"
  24. #include "CmLogStr.h"
  25. #include "cmlog.h"
  26. #include "cmlogutil.h"
  27. #include "getmodulever.cpp"
  28. //
  29. // Constants
  30. //
  31. LPCTSTR c_szSep = TEXT("\\");
  32. LPCTSTR c_szDotLog = TEXT(".log");
  33. LPCTSTR c_szNewLine = TEXT("\r\n");
  34. LPCTSTR c_szEmpty = TEXT("");
  35. #define CHECKEMPTY(sz) ((sz) ? (sz) : c_szEmpty)
  36. LPCTSTR c_szLineOfStars = TEXT("******************************************************************");
  37. LPCTSTR c_szFieldSeparator = TEXT("\t");
  38. //
  39. // Byte order mark constant, written as the first two bytes to a Unicode file to mark it as such
  40. //
  41. const WCHAR c_wchBOM = BYTE_ORDER_MARK;
  42. //
  43. // Globals
  44. //
  45. extern HINSTANCE g_hInst;
  46. //
  47. // utility macros
  48. //
  49. #define INBETWEEN(x, a, b) ( ( (x) >= (a) ) && ( (x) <= (b) ) )
  50. //
  51. // local function declarations
  52. //
  53. LPTSTR GetLogDesc(_CMLOG_ITEM eItem);
  54. LPTSTR GetLogFormat(_CMLOG_ITEM eItem, BOOL fUnicode);
  55. typedef struct _CM_LOG_ITEM_DESC
  56. {
  57. enum _CMLOG_ITEM eLogItem; // id of the log item (enum is in cmlog.h)
  58. UINT idDesc; // resource id of the description string
  59. UINT idFormat; // resource id of the format string used
  60. }
  61. CMLOGITEM;
  62. //
  63. //
  64. // Array with information about each log entry. All logging is driven by this table.
  65. // See above for column details.
  66. //
  67. //
  68. static CMLOGITEM s_aCmLogItems[] =
  69. {
  70. { LOGGING_ENABLED_EVENT, IDS_LOGDESC_LOGENABLED, 0 },
  71. { LOGGING_DISABLED_EVENT, IDS_LOGDESC_LOGDISABLED, 0 },
  72. { PREINIT_EVENT, IDS_LOGDESC_PREINIT, IDS_LOGFMT_PREINIT, },
  73. { PRECONNECT_EVENT, IDS_LOGDESC_PRECONNECT, IDS_LOGFMT_PRECONNECT },
  74. { PREDIAL_EVENT, IDS_LOGDESC_PREDIAL, IDS_LOGFMT_PREDIAL },
  75. { PRETUNNEL_EVENT, IDS_LOGDESC_PRETUNNEL, IDS_LOGFMT_PRETUNNEL },
  76. { CONNECT_EVENT, IDS_LOGDESC_CONNECT, 0 },
  77. { CUSTOMACTIONDLL, IDS_LOGDESC_CUSTOMACTIONDLL, IDS_LOGFMT_CUSTOMACTIONDLL },
  78. { CUSTOMACTIONEXE, IDS_LOGDESC_CUSTOMACTIONEXE, IDS_LOGFMT_CUSTOMACTIONEXE },
  79. { CUSTOMACTION_NOT_ALLOWED, IDS_LOGDESC_CUSTOMACTION_NOT_ALLOWED, IDS_LOGFMT_CUSTOMACTION_NOT_ALLOWED},
  80. { CUSTOMACTION_WONT_RUN, IDS_LOGDESC_CUSTOMACTION_WONT_RUN, IDS_LOGFMT_CUSTOMACTION_WONT_RUN},
  81. { DISCONNECT_EVENT, IDS_LOGDESC_DISCONNECT, IDS_LOGFMT_DISCONNECT },
  82. { RECONNECT_EVENT, IDS_LOGDESC_RECONNECT, 0 },
  83. { RETRY_AUTH_EVENT, IDS_LOGDESC_RETRYAUTH, 0 },
  84. { CALLBACK_NUMBER_EVENT, IDS_LOGDESC_CALLBACKNUMBER, IDS_LOGFMT_CALLBACKNUMBER },
  85. { PASSWORD_EXPIRED_EVENT, IDS_LOGDESC_PWDEXPIRED, IDS_LOGFMT_PWDEXPIRED },
  86. { PASSWORD_RESET_EVENT, IDS_LOGDESC_PWDRESET, IDS_LOGFMT_PWDRESET },
  87. { CUSTOM_BUTTON_EVENT, IDS_LOGDESC_CUSTOMBUTTON, 0 },
  88. { ONCANCEL_EVENT, IDS_LOGDESC_ONCANCEL, 0 },
  89. { ONERROR_EVENT, IDS_LOGDESC_ONERROR, IDS_LOGFMT_ONERROR },
  90. { CLEAR_LOG_EVENT, IDS_LOGDESC_CLEARLOG, 0 },
  91. { DISCONNECT_EXT, IDS_LOGDESC_EXT_DISCONNECT, 0 },
  92. { DISCONNECT_INT_MANUAL, IDS_LOGDESC_INT_DISCONNECT_MANUAL, 0 },
  93. { DISCONNECT_INT_AUTO, IDS_LOGDESC_INT_DISCONNECT_AUTO, 0 },
  94. { DISCONNECT_EXT_LOST_CONN, IDS_LOGDESC_EXT_DISCONNECT_LOST_CONN, 0 },
  95. { PB_DOWNLOAD_SUCCESS, IDS_LOGDESC_PB_DOWNLOAD_SUCCESS, IDS_LOGFMT_PB_DOWNLOAD_SUCCESS },
  96. { PB_DOWNLOAD_FAILURE, IDS_LOGDESC_PB_DOWNLOAD_FAILURE, IDS_LOGFMT_PB_DOWNLOAD_FAILURE },
  97. { PB_UPDATE_SUCCESS, IDS_LOGDESC_PB_UPDATE_SUCCESSFUL, IDS_LOGFMT_PB_UPDATE_SUCCESSFUL },
  98. { PB_UPDATE_FAILURE_PBS, IDS_LOGDESC_PB_UPDATE_FAILED_PBS, IDS_LOGFMT_PB_UPDATE_FAILED_PBS },
  99. { PB_UPDATE_FAILURE_CMPBK, IDS_LOGDESC_PB_UPDATE_FAILED_CMPBK, IDS_LOGFMT_PB_UPDATE_FAILED_CMPBK },
  100. { PB_ABORTED, IDS_LOGDESC_PB_ABORTED, 0 },
  101. { USER_FORMATTED, 0, 0 }
  102. };
  103. int s_cCmLogItems = sizeof(s_aCmLogItems) / sizeof(CMLOGITEM);
  104. #define VERIFY_CMLOG_ITEM_OK(x) INBETWEEN(x, 1, s_cCmLogItems)
  105. //
  106. // Usage Note: Caller/User of logging must:
  107. // p = new CmLogFile
  108. // p->Init( instancehandle, fIsItAnAllUserProfile, "name of connectoid" )
  109. // p->SetParams( ... the params ... )
  110. // if (p->m_fEnabled)
  111. // p->Start
  112. // else
  113. // p->Stop
  114. //
  115. //+----------------------------------------------------------------------------
  116. //
  117. // Func: CmLogFile::CmLogFile
  118. //
  119. // Desc: constructor
  120. //
  121. // Args: none
  122. //
  123. // Return: n/a
  124. //
  125. // Notes:
  126. //
  127. // History: 30-Apr-2000 SumitC Created
  128. //
  129. //-----------------------------------------------------------------------------
  130. CmLogFile::CmLogFile()
  131. {
  132. m_fInitialized = FALSE;
  133. m_hfile = NULL;
  134. m_dwSize = 0;
  135. m_pszServiceName = NULL;
  136. m_szModule[0] = TEXT('\0');
  137. m_pszLogFile = NULL;
  138. m_dwMaxSize = 0;
  139. m_fEnabled = FALSE;
  140. m_pszLogFileDir = NULL;
  141. }
  142. //+----------------------------------------------------------------------------
  143. //
  144. // Func: CmLogFile::~CmLogFile
  145. //
  146. // Desc: destructor
  147. //
  148. // Args: none
  149. //
  150. // Return: n/a
  151. //
  152. // Notes:
  153. //
  154. // History: 30-Apr-2000 SumitC Created
  155. //
  156. //-----------------------------------------------------------------------------
  157. CmLogFile::~CmLogFile()
  158. {
  159. if (m_fInitialized)
  160. {
  161. DeInit();
  162. }
  163. }
  164. //+----------------------------------------------------------------------------
  165. //
  166. // Func: CmLogFile::Init
  167. //
  168. // Desc: Initializes the CmLogFile object
  169. //
  170. // Args: [hInst] -- instance handle
  171. // [fAllUser] -- is this an all user profile?
  172. // [pszServiceName] -- long service name
  173. //
  174. // Return: HRESULT
  175. //
  176. // Notes: There are both Ansi and Unicode versions for this function
  177. //
  178. // History: 18-Jul-2000 SumitC Created
  179. // 11-Apr-2001 SumitC Added Ansi version
  180. //
  181. //-----------------------------------------------------------------------------
  182. HRESULT
  183. CmLogFile::Init(HINSTANCE hInst, BOOL fAllUser, LPCSTR pszAnsiServiceName)
  184. {
  185. LPWSTR pszServiceName = SzToWzWithAlloc(pszAnsiServiceName);
  186. HRESULT hr = pszServiceName ? Init(hInst, fAllUser, pszServiceName) : E_OUTOFMEMORY;
  187. CmFree(pszServiceName);
  188. return hr;
  189. }
  190. HRESULT
  191. CmLogFile::Init(HINSTANCE hInst, BOOL fAllUser, LPCWSTR pszServiceName)
  192. {
  193. HRESULT hr = S_OK;
  194. // if m_fInitialized is already true, assert and exit
  195. CMASSERTMSG(!m_fInitialized, TEXT("CmLogFile::Init - called twice"));
  196. if (TRUE == m_fInitialized)
  197. {
  198. hr = E_UNEXPECTED;
  199. goto Cleanup;
  200. }
  201. CMASSERTMSG(pszServiceName && pszServiceName[0], TEXT("CmLogFile::Init - invalid servicename, investigate"));
  202. if ((NULL == pszServiceName) || (TEXT('\0') == pszServiceName[0]))
  203. {
  204. hr = E_INVALIDARG;
  205. goto Cleanup;
  206. }
  207. // set the args as member vars
  208. m_fAllUser = fAllUser;
  209. m_pszServiceName = CmStrCpyAlloc(pszServiceName);
  210. if (NULL == m_pszServiceName)
  211. {
  212. hr = E_OUTOFMEMORY;
  213. goto Cleanup;
  214. }
  215. //
  216. // store away the module name
  217. //
  218. if (FALSE == CmGetModuleBaseName(hInst, m_szModule))
  219. {
  220. lstrcpyU(m_szModule, TEXT("cm"));
  221. }
  222. // if all is well, set m_fInitialized to true
  223. m_fInitialized = TRUE;
  224. Cleanup:
  225. CMTRACEHR(TEXT("CmLogFile::Init"), hr);
  226. return hr;
  227. }
  228. //+----------------------------------------------------------------------------
  229. //
  230. // Func: CmLogFile::SetParams
  231. //
  232. // Desc: Read logging params from the CMS file
  233. //
  234. // Args: [fEnabled] -- is logging enabled?
  235. // [dwMaxFileSize] -- maximum file size, in KB.
  236. // [pszLogFileDir] -- put logging files in this dir.
  237. //
  238. // Return: HRESULT
  239. //
  240. // Notes: There are both Ansi and Unicode versions for this function
  241. //
  242. // History: 18-Jul-2000 SumitC Created
  243. // 11-Apr-2001 SumitC Added Ansi version
  244. //
  245. //-----------------------------------------------------------------------------
  246. HRESULT
  247. CmLogFile::SetParams(BOOL fEnabled, DWORD dwMaxFileSize, LPCSTR pszAnsiLogFileDir)
  248. {
  249. LPWSTR pszLogFileDir = SzToWzWithAlloc(pszAnsiLogFileDir);
  250. HRESULT hr = pszLogFileDir ? SetParams(fEnabled, dwMaxFileSize, pszLogFileDir) : E_OUTOFMEMORY;
  251. CmFree(pszLogFileDir);
  252. return hr;
  253. }
  254. HRESULT
  255. CmLogFile::SetParams(BOOL fEnabled, DWORD dwMaxFileSize, LPCWSTR pszLogFileDir)
  256. {
  257. HRESULT hr = S_OK;
  258. LPTSTR szUnexpanded = NULL;
  259. CIni * pIni = NULL;
  260. //
  261. // logging must be stopped for this function to be called
  262. //
  263. CMASSERTMSG(NULL == m_hfile, TEXT("CmLogFile::SetParams - m_hfile must be null when this is called"));
  264. if (m_hfile)
  265. {
  266. CMTRACE(TEXT("CmLogFile::SetParams was called during logging - must call Stop first"));
  267. hr = E_UNEXPECTED;
  268. goto Cleanup;
  269. }
  270. //
  271. // EnableLogging (BOOL)
  272. //
  273. m_fEnabled = fEnabled;
  274. //
  275. // MaxFileSize (DWORD)
  276. //
  277. m_dwMaxSize = dwMaxFileSize;
  278. if (0 == m_dwMaxSize)
  279. {
  280. m_dwMaxSize = c_dwMaxFileSize;
  281. }
  282. m_dwMaxSize *= 1024; // size was in KB, convert to bytes.
  283. //
  284. // FileDirectory (string)
  285. //
  286. if (CmStrStr(pszLogFileDir, TEXT("%")))
  287. {
  288. //
  289. // now expand the string we have
  290. //
  291. LPTSTR sz = NULL;
  292. DWORD cch = ExpandEnvironmentStringsU(pszLogFileDir, NULL, 0);
  293. //
  294. // if cch is zero, the pszLogFileDir string supplied is essentially bogus,
  295. // i.e. it contains '%' indicating there's a macro to be expanded, but
  296. // ExpandEnvironmentStrings can't expand it. Here we let m_pszLogFileDir
  297. // be set to NULL (the logging code will then use the Temp dir.
  298. //
  299. if (cch)
  300. {
  301. sz = (LPTSTR) CmMalloc(cch * sizeof(TCHAR));
  302. if (NULL == sz)
  303. {
  304. hr = E_OUTOFMEMORY;
  305. goto Cleanup;
  306. }
  307. if (cch != ExpandEnvironmentStringsU(pszLogFileDir, sz, cch))
  308. {
  309. hr = HRESULT_FROM_WIN32(GetLastError());
  310. CmFree(sz);
  311. goto Cleanup;
  312. }
  313. // success...
  314. }
  315. CmFree(m_pszLogFileDir);
  316. m_pszLogFileDir = sz;
  317. }
  318. else
  319. {
  320. CmFree(m_pszLogFileDir);
  321. if (pszLogFileDir)
  322. {
  323. m_pszLogFileDir = CmStrCpyAlloc(pszLogFileDir);
  324. if (NULL == m_pszLogFileDir)
  325. {
  326. hr = E_OUTOFMEMORY;
  327. goto Cleanup;
  328. }
  329. }
  330. else
  331. {
  332. m_pszLogFileDir = NULL;
  333. }
  334. }
  335. Cleanup:
  336. CMTRACEHR(TEXT("CmLogFile::SetParams"), hr);
  337. return hr;
  338. }
  339. //+----------------------------------------------------------------------------
  340. //
  341. // Func: CmLogFile::Start
  342. //
  343. // Desc: Start logging
  344. //
  345. // Args: [fBanner] -- write a banner when starting
  346. //
  347. // Return: HRESULT
  348. //
  349. // Notes:
  350. //
  351. // History: 18-Jul-2000 SumitC Created
  352. //
  353. //-----------------------------------------------------------------------------
  354. HRESULT
  355. CmLogFile::Start(BOOL fBanner)
  356. {
  357. HRESULT hr = S_OK;
  358. // if already started, or already Initialized, or not enabled, exit
  359. CMASSERTMSG(!m_hfile, TEXT("CmLogFile::Start - already started!"));
  360. CMASSERTMSG(m_fInitialized, TEXT("CmLogFile::Start - must be initialized"));
  361. CMASSERTMSG(m_fEnabled, TEXT("CmLogFile::Start - must be enabled"));
  362. if (NULL != m_hfile || FALSE == m_fInitialized || FALSE == m_fEnabled)
  363. {
  364. hr = E_UNEXPECTED;
  365. goto Cleanup;
  366. }
  367. // open log file
  368. hr = OpenFile();
  369. if (S_OK != hr)
  370. {
  371. goto Cleanup;
  372. }
  373. // set m_dwSize while doing so.
  374. m_dwSize = GetFileSize(m_hfile, NULL);
  375. if (DWORD(-1) == m_dwSize)
  376. {
  377. hr = HRESULT_FROM_WIN32(GetLastError());
  378. m_dwSize = 0;
  379. goto Cleanup;
  380. }
  381. //
  382. // no matter what the size of the file, we only clear an 'over the size limit'
  383. // file at the start of a call. The fBanner param covers this.
  384. //
  385. if (fBanner)
  386. {
  387. // check file size, if over size Clear the file
  388. if (m_dwSize > m_dwMaxSize)
  389. {
  390. Clear(); // this writes a banner as well
  391. }
  392. else
  393. {
  394. // log banner
  395. Banner();
  396. }
  397. }
  398. CMASSERTMSG(m_hfile, TEXT("CmLogFile::Start - at end of fn, m_hfile must be valid"));
  399. Cleanup:
  400. CMTRACEHR(TEXT("CmLogFile::Start"), hr);
  401. return hr;
  402. }
  403. //+----------------------------------------------------------------------------
  404. //
  405. // Func: CmLogFile::Stop
  406. //
  407. // Desc: Stops logging
  408. //
  409. // Args: none
  410. //
  411. // Return: HRESULT
  412. //
  413. // Notes:
  414. //
  415. // History: 18-Jul-2000 SumitC Created
  416. //
  417. //-----------------------------------------------------------------------------
  418. HRESULT
  419. CmLogFile::Stop()
  420. {
  421. HRESULT hr = S_OK;
  422. //
  423. // if initialized is false, assert and exit
  424. //
  425. CMASSERTMSG(m_fInitialized, TEXT("CmLogFile::Stop - must be initialized"));
  426. if (FALSE == m_fInitialized)
  427. {
  428. hr = E_UNEXPECTED;
  429. goto Cleanup;
  430. }
  431. //
  432. // if already stopped, exit - nothing to do
  433. //
  434. if (NULL == m_hfile || FALSE == m_fEnabled)
  435. {
  436. hr = E_UNEXPECTED;
  437. goto Cleanup;
  438. }
  439. //
  440. // end log and close file
  441. //
  442. CloseFile();
  443. m_fEnabled = FALSE;
  444. CMASSERTMSG(NULL == m_hfile, TEXT("CmLogFile::Stop - at end of fn, m_hfile must be NULL"));
  445. Cleanup:
  446. CMTRACEHR(TEXT("CmLogFile::Stop"), hr);
  447. return hr;
  448. }
  449. //+----------------------------------------------------------------------------
  450. //
  451. // Func: CmLogFile::DeInit
  452. //
  453. // Desc: Uninitializes cm logging
  454. //
  455. // Args: none
  456. //
  457. // Return: HRESULT
  458. //
  459. // Notes:
  460. //
  461. // History: 18-Jul-2000 SumitC Created
  462. //
  463. //-----------------------------------------------------------------------------
  464. HRESULT
  465. CmLogFile::DeInit()
  466. {
  467. HRESULT hr = S_OK;
  468. //
  469. // if initialized is false, assert and exit
  470. //
  471. CMASSERTMSG(m_fInitialized, TEXT("CmLogFile::DeInit - must be initialized"));
  472. if (FALSE == m_fInitialized)
  473. {
  474. hr = E_UNEXPECTED;
  475. goto Cleanup;
  476. }
  477. //
  478. // end log and close file
  479. //
  480. CloseFile();
  481. CmFree(m_pszServiceName);
  482. m_pszServiceName = NULL;
  483. CmFree(m_pszLogFileDir);
  484. m_pszLogFileDir = NULL;
  485. CmFree(m_pszLogFile);
  486. m_pszLogFile = NULL;
  487. m_fInitialized = FALSE;
  488. Cleanup:
  489. CMTRACEHR(TEXT("CmLogFile::DeInit"), hr);
  490. return hr;
  491. }
  492. //+----------------------------------------------------------------------------
  493. //
  494. // Func: CmLogFile::Log
  495. //
  496. // Desc: Logs a connection manager or connection point services event
  497. //
  498. // Args: [fUnicode] - are the args Unicode or ANSI?
  499. // [eLogItem] - word containing source, type & description of log item
  500. // [...] - optional args (depends on log item)
  501. //
  502. // Return: void
  503. //
  504. // Notes:
  505. //
  506. // History: 30-Apr-2000 SumitC Created
  507. //
  508. //-----------------------------------------------------------------------------
  509. void
  510. CmLogFile::Log(_CMLOG_ITEM eLogItem, ...)
  511. {
  512. TCHAR sz[2*MAX_PATH]; // REVIEW: Is this big enough? Could we dynamically allocate it?
  513. LPTSTR pszTmp = NULL;
  514. CMASSERTMSG(m_fInitialized, TEXT("CmLogFile::Log - must be initialized"));
  515. CMASSERTMSG((m_hfile && m_fEnabled) || (!m_hfile && !m_fEnabled), TEXT("CmLogFile::Log - m_hfile and m_fenabled must be in sync"));
  516. if (NULL == m_hfile || NULL == m_fEnabled)
  517. {
  518. // Start hasn't been called yet, or logging is disabled. Nothing to do.
  519. goto Cleanup;
  520. }
  521. //
  522. // Verify that the log item is a valid one
  523. //
  524. CMASSERTMSG(VERIFY_CMLOG_ITEM_OK(eLogItem), TEXT("CmLogFile::Log - eItem must represent valid Log item"));
  525. #if DBG
  526. pszTmp = GetLogDesc(eLogItem);
  527. CMTRACE2(TEXT("Logging item = %d, desc = %s"), eLogItem, CHECKEMPTY(pszTmp));
  528. CmFree(pszTmp);
  529. #endif
  530. if (VERIFY_CMLOG_ITEM_OK(eLogItem))
  531. {
  532. switch (eLogItem)
  533. {
  534. case USER_FORMATTED:
  535. va_list valArgs;
  536. va_start(valArgs, eLogItem);
  537. lstrcpyU(sz, va_arg(valArgs, LPTSTR));
  538. FormatWrite(eLogItem, sz);
  539. va_end(valArgs);
  540. break;
  541. default:
  542. //
  543. // Format the arguments, and log the result
  544. //
  545. lstrcpyU(sz, c_szEmpty);
  546. pszTmp = GetLogFormat(eLogItem, TRUE);
  547. if (pszTmp)
  548. {
  549. va_list valArgs;
  550. va_start(valArgs, eLogItem);
  551. wvsprintfU(sz, pszTmp, valArgs);
  552. CmFree(pszTmp);
  553. FormatWrite(eLogItem, sz);
  554. va_end(valArgs);
  555. }
  556. else
  557. {
  558. FormatWrite(eLogItem, NULL);
  559. }
  560. }
  561. }
  562. else
  563. {
  564. CMTRACE2(TEXT("Illegal CmLog entry %d (0x%x)"), eLogItem, eLogItem);
  565. CMASSERTMSG(FALSE, TEXT("Illegal CmLog type - check trace, then edit code to fix"));
  566. }
  567. Cleanup:
  568. ;
  569. }
  570. //+----------------------------------------------------------------------------
  571. //
  572. // Func: CmLogFile::Write
  573. //
  574. // Desc: Actually writes out the logged string (to debug console and logfile)
  575. //
  576. // Args: [szLog] - string to log
  577. //
  578. // Return: void
  579. //
  580. // Notes: *ALL* writes to the log file must be done using this function
  581. //
  582. // History: 30-Apr-2000 SumitC Created
  583. //
  584. //-----------------------------------------------------------------------------
  585. HRESULT
  586. CmLogFile::Write(LPTSTR szLog)
  587. {
  588. HRESULT hr = S_OK;
  589. DWORD cb = 0;
  590. DWORD cbActuallyWritten = 0;
  591. LPSTR szLogAnsi = NULL;
  592. CMASSERTMSG(m_hfile, TEXT("CmLogFile::Write - m_hfile must be valid, check code"));
  593. if (NULL == m_hfile)
  594. {
  595. hr = E_UNEXPECTED;
  596. goto Cleanup;
  597. }
  598. #if 0
  599. //
  600. // Dump string to debug console as well
  601. //
  602. CMTRACE(szLog);
  603. #endif
  604. //
  605. // Check for max size, open new log file if necessary
  606. //
  607. if (OS_NT)
  608. {
  609. cb = lstrlenW(szLog) * sizeof(TCHAR);
  610. }
  611. else
  612. {
  613. szLogAnsi = WzToSzWithAlloc(szLog);
  614. cb = lstrlenA(szLogAnsi) * sizeof(CHAR);
  615. }
  616. #if 0
  617. // I'm leaving this here, but for now logging will not terminate a log file
  618. // during a log even if it goes past the max size.
  619. //
  620. if (m_dwSize + cb > m_dwMaxSize)
  621. {
  622. Clear();
  623. }
  624. #endif
  625. //
  626. // Write string to logfile
  627. //
  628. SetFilePointer(m_hfile, 0, NULL, FILE_END);
  629. if (OS_NT)
  630. {
  631. WriteFile(m_hfile, szLog, cb, &cbActuallyWritten, 0);
  632. }
  633. else
  634. {
  635. WriteFile(m_hfile, szLogAnsi, cb, &cbActuallyWritten, 0);
  636. }
  637. if (cb != cbActuallyWritten)
  638. {
  639. hr = HRESULT_FROM_WIN32(GetLastError());
  640. CMTRACE(TEXT("CMLOG: incomplete write to logfile"));
  641. goto Cleanup;
  642. }
  643. m_dwSize += cb;
  644. Cleanup:
  645. CmFree(szLogAnsi);
  646. CMTRACEHR(TEXT("CmLogFile::Write"), hr);
  647. return hr;
  648. }
  649. //+----------------------------------------------------------------------------
  650. //
  651. // Func: CmLogFile::FormatWrite
  652. //
  653. // Desc: Formats a log message with additional information and call Write fn
  654. //
  655. // Args: [eItem] - id of item being logged
  656. // [szArgs] - string containing all the args.
  657. //
  658. // Return: void
  659. //
  660. // Notes:
  661. //
  662. // History: 30-Apr-2000 SumitC Created
  663. //
  664. //-----------------------------------------------------------------------------
  665. void
  666. CmLogFile::FormatWrite(_CMLOG_ITEM eItem, LPTSTR szArgs)
  667. {
  668. TCHAR szLog[2*MAX_PATH]; // REVIEW: Is this big enough? Could we dynamically allocate it?
  669. TCHAR sz[2*MAX_PATH]; // REVIEW: Is this big enough? Could we dynamically allocate it?
  670. CMASSERTMSG(VERIFY_CMLOG_ITEM_OK(eItem), TEXT("CmLogFile::FormatWrite - eItem must represent valid Log item"));
  671. lstrcpyU(szLog, TEXT(""));
  672. //
  673. // Thread and Module name
  674. //
  675. TCHAR szModuleWithParens[11];
  676. wsprintfU(szModuleWithParens, TEXT("[%s]"), m_szModule);
  677. wsprintfU(sz, TEXT("%-10s%s"), szModuleWithParens, c_szFieldSeparator);
  678. lstrcatU(szLog, sz);
  679. //
  680. // Time
  681. //
  682. LPTSTR pszTime = NULL;
  683. CmGetDateTime(NULL, &pszTime);
  684. if (pszTime)
  685. {
  686. lstrcatU(szLog, pszTime);
  687. lstrcatU(szLog, c_szFieldSeparator);
  688. CmFree(pszTime);
  689. }
  690. //
  691. // Description
  692. //
  693. if (USER_FORMATTED == eItem)
  694. {
  695. wsprintfU(sz, TEXT("%02d%s%s\r\n"), eItem, c_szFieldSeparator, szArgs);
  696. }
  697. else
  698. {
  699. LPTSTR pszDesc = GetLogDesc(eItem);
  700. if (szArgs)
  701. {
  702. wsprintfU(sz, TEXT("%02d%s%s%s%s\r\n"),
  703. eItem, c_szFieldSeparator, CHECKEMPTY(pszDesc), c_szFieldSeparator, szArgs);
  704. }
  705. else
  706. {
  707. wsprintfU(sz, TEXT("%02d%s%s\r\n"),
  708. eItem, c_szFieldSeparator, CHECKEMPTY(pszDesc));
  709. }
  710. CmFree(pszDesc);
  711. }
  712. lstrcatU(szLog, sz);
  713. //
  714. // Write it out...
  715. //
  716. Write(szLog);
  717. }
  718. //+----------------------------------------------------------------------------
  719. //
  720. // Func: CmLogFile::OpenFile
  721. //
  722. // Desc: Utility function to open the log file
  723. //
  724. // Args: none
  725. //
  726. // Return: HRESULT (S_OK for success, else error)
  727. //
  728. // Notes:
  729. //
  730. // History: 22-Jul-2000 SumitC Created
  731. //
  732. //-----------------------------------------------------------------------------
  733. HRESULT
  734. CmLogFile::OpenFile()
  735. {
  736. HRESULT hr = S_OK;
  737. HANDLE hDir = NULL;
  738. LPTSTR pszUsers = NULL;
  739. BOOL fFileOpened = FALSE;
  740. CMASSERTMSG(m_pszServiceName, TEXT("CmLogFile::OpenFile - m_pszServiceName must be valid"));
  741. if (m_fAllUser)
  742. {
  743. // this is the more common case, so no suffix
  744. pszUsers = CmStrCpyAlloc(TEXT(""));
  745. }
  746. else
  747. {
  748. LPTSTR pszTmp = CmLoadString(g_hInst, IDS_LOGSTR_SINGLEUSER);
  749. if (pszTmp)
  750. {
  751. pszUsers = (LPTSTR) CmMalloc((lstrlenU(pszTmp) + 4) * sizeof(TCHAR));
  752. if (pszUsers)
  753. {
  754. wsprintfU(pszUsers, TEXT(" (%s)"), pszTmp);
  755. }
  756. CmFree(pszTmp);
  757. }
  758. }
  759. if (NULL == pszUsers)
  760. {
  761. hr = E_OUTOFMEMORY;
  762. CMTRACE1(TEXT("CmLogFile::OpenFile - couldn't get Users strings, hr=%x"), hr);
  763. goto Cleanup;
  764. }
  765. //
  766. // To open a log file, we first try the location provided by the user. If
  767. // that fails for whatever reason, we try GetTempPath. If that fails, no
  768. // logging.
  769. //
  770. for (int i = 0; (i < 2) && (FALSE == fFileOpened); ++i)
  771. {
  772. TCHAR szBuf[2 * MAX_PATH];
  773. CMTRACE1(TEXT("CmLogFile::OpenFile, iteration %d."), i + 1);
  774. //
  775. // get the directory name
  776. //
  777. switch (i)
  778. {
  779. case 0:
  780. if (m_pszLogFileDir)
  781. {
  782. lstrcpyU(szBuf, m_pszLogFileDir);
  783. }
  784. else
  785. {
  786. continue;
  787. }
  788. break;
  789. case 1:
  790. if (0 == GetTempPathU(2 * MAX_PATH, szBuf))
  791. {
  792. hr = HRESULT_FROM_WIN32(GetLastError());
  793. CMTRACE1(TEXT("GetTempPath failed with error 0x%x"), hr);
  794. goto Cleanup;
  795. }
  796. break;
  797. default:
  798. MYDBGASSERT(0);
  799. goto Cleanup;
  800. break;
  801. }
  802. CMTRACE1(TEXT("CmLogFile::OpenFile, directory name is %s"), szBuf);
  803. //
  804. // see if the directory exists, if not try to create it
  805. //
  806. DWORD dwAttrib = GetFileAttributesU(szBuf);
  807. if (-1 == dwAttrib)
  808. {
  809. // directory does not exist
  810. CMTRACE(TEXT("CmLogFile::OpenFile - directory does not exist, trying to create it"));
  811. if (FALSE == CreateDirectoryU(szBuf, NULL))
  812. {
  813. DWORD dw = GetLastError();
  814. if (ERROR_ALREADY_EXISTS != dw)
  815. {
  816. // real failure
  817. hr = HRESULT_FROM_WIN32(dw);
  818. CMTRACE2(TEXT("CmLogFile::OpenFile - Failed to create logging directory (%s), hr=%x"), szBuf, hr);
  819. continue;
  820. }
  821. //
  822. // On Win95/98, CreateDirectory fails with ERROR_ALREADY_EXISTS
  823. // if the dir already exists. i.e. we have a dir, so keep going.
  824. //
  825. CMTRACE(TEXT("CmLogFile::OpenFile - directory created"));
  826. }
  827. }
  828. else
  829. {
  830. CMTRACE(TEXT("CmLogFile::OpenFile - directory already exists"));
  831. if (0 == (FILE_ATTRIBUTE_DIRECTORY & dwAttrib))
  832. {
  833. // there is a file of that name
  834. CMTRACE(TEXT("CmLogFile::OpenFile - there is a file of the same name as requested dir"));
  835. hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
  836. continue;
  837. }
  838. else if (FILE_ATTRIBUTE_READONLY & dwAttrib)
  839. {
  840. // the directory is readonly
  841. CMTRACE(TEXT("CmLogFile::OpenFile - the directory is readonly"));
  842. hr = E_ACCESSDENIED;
  843. continue;
  844. }
  845. }
  846. //
  847. // the directory exists, try to create/open the logfile
  848. //
  849. if (*c_szSep != szBuf[lstrlenU(szBuf) - 1])
  850. {
  851. lstrcatU(szBuf, c_szSep);
  852. }
  853. lstrcatU(szBuf, m_pszServiceName);
  854. lstrcatU(szBuf, pszUsers);
  855. lstrcatU(szBuf, c_szDotLog);
  856. m_hfile = CreateFileU(szBuf,
  857. GENERIC_READ | GENERIC_WRITE,
  858. FILE_SHARE_READ | FILE_SHARE_WRITE,
  859. NULL,
  860. OPEN_EXISTING,
  861. FILE_ATTRIBUTE_NORMAL,
  862. NULL);
  863. //
  864. // Since we asked for open existing, the file may just need to be created
  865. //
  866. if (INVALID_HANDLE_VALUE == m_hfile)
  867. {
  868. m_hfile = CreateFileU(szBuf,
  869. GENERIC_READ | GENERIC_WRITE,
  870. FILE_SHARE_READ | FILE_SHARE_WRITE,
  871. NULL,
  872. CREATE_NEW,
  873. FILE_ATTRIBUTE_NORMAL,
  874. NULL);
  875. if ((INVALID_HANDLE_VALUE != m_hfile) && OS_NT)
  876. {
  877. //
  878. // Set the Byte order mark on the file
  879. //
  880. DWORD cbActuallyWritten = 0;
  881. WriteFile(m_hfile, &c_wchBOM, sizeof(c_wchBOM), &cbActuallyWritten, 0);
  882. if (sizeof(c_wchBOM) != cbActuallyWritten)
  883. {
  884. hr = HRESULT_FROM_WIN32(GetLastError());
  885. CMTRACE(TEXT("CMLOG: Unable to set the Byte order mark while opening the file"));
  886. goto Cleanup;
  887. }
  888. m_dwSize += sizeof(c_wchBOM);
  889. }
  890. }
  891. if (INVALID_HANDLE_VALUE == m_hfile)
  892. {
  893. hr = HRESULT_FROM_WIN32(GetLastError());
  894. CMTRACE2(TEXT("CmLogFile::OpenFile - Failed to open log file in dir %s with error 0x%x"), szBuf, hr);
  895. continue;
  896. }
  897. //
  898. // Success!!
  899. //
  900. CmFree(m_pszLogFile);
  901. m_pszLogFile = CmStrCpyAlloc(szBuf);
  902. if (NULL == m_pszLogFile)
  903. {
  904. hr = E_OUTOFMEMORY;
  905. goto Cleanup;
  906. }
  907. hr = S_OK;
  908. fFileOpened = TRUE;
  909. }
  910. #if DBG
  911. if (S_OK == hr)
  912. {
  913. CMASSERTMSG(m_hfile, TEXT("CmLogFile::OpenFile - at end. m_hfile must be valid here"));
  914. }
  915. #endif
  916. Cleanup:
  917. CmFree(pszUsers);
  918. CMTRACEHR(TEXT("CmLogFile::OpenFile"), hr);
  919. return hr;
  920. }
  921. //+----------------------------------------------------------------------------
  922. //
  923. // Func: CmLogFile::CloseFile
  924. //
  925. // Desc: Closes the logging file
  926. //
  927. // Args: none
  928. //
  929. // Return: HRESULT
  930. //
  931. // Notes:
  932. //
  933. // History: 30-Apr-2000 SumitC Created
  934. //
  935. //-----------------------------------------------------------------------------
  936. HRESULT
  937. CmLogFile::CloseFile()
  938. {
  939. HRESULT hr = S_OK;
  940. if (m_hfile)
  941. {
  942. //
  943. // Close the file
  944. //
  945. FlushFileBuffers(m_hfile);
  946. CloseHandle(m_hfile);
  947. m_hfile = NULL;
  948. }
  949. CMTRACEHR(TEXT("CmLogFile::CloseFile"), hr);
  950. return hr;
  951. }
  952. //+----------------------------------------------------------------------------
  953. //
  954. // Func: CmLogFile::Clear
  955. //
  956. // Desc: Clears (resets) the logging file
  957. //
  958. // Args: [fWriteBannerAfterwards] -- after clearing, write the banner?
  959. //
  960. // Return: void
  961. //
  962. // Notes:
  963. //
  964. // History: 17-Jul-2000 SumitC Created
  965. //
  966. //-----------------------------------------------------------------------------
  967. void
  968. CmLogFile::Clear(BOOL fWriteBannerAfterwards)
  969. {
  970. HRESULT hr = S_OK;
  971. BOOL fWasDisabled = FALSE;
  972. if (NULL == m_hfile)
  973. {
  974. fWasDisabled = TRUE; // if called when logging is disabled, we still clear the log file
  975. hr = OpenFile();
  976. if (S_OK != hr)
  977. {
  978. goto Cleanup;
  979. }
  980. }
  981. //
  982. // make sure everything gets written out (ignore errors for this one)
  983. //
  984. FlushFileBuffers(m_hfile);
  985. //
  986. // clear the file (set fileptr to the start, then set EOF to that).
  987. //
  988. if (INVALID_SET_FILE_POINTER == SetFilePointer(m_hfile, 0, NULL, FILE_BEGIN))
  989. {
  990. hr = HRESULT_FROM_WIN32(GetLastError());
  991. goto Cleanup;
  992. }
  993. if (FALSE == SetEndOfFile(m_hfile))
  994. {
  995. hr = HRESULT_FROM_WIN32(GetLastError());
  996. goto Cleanup;
  997. }
  998. m_dwSize = 0;
  999. CMTRACE(TEXT("CmLogFile::Clear - cleared log file"));
  1000. //
  1001. // If this is NT and thus a Unicode file, we need to set the Byte order mark
  1002. //
  1003. if (OS_NT)
  1004. {
  1005. if ((INVALID_HANDLE_VALUE != m_hfile) && OS_NT)
  1006. {
  1007. //
  1008. // Set the Byte order mark on the file
  1009. //
  1010. DWORD cbActuallyWritten = 0;
  1011. WriteFile(m_hfile, &c_wchBOM, sizeof(c_wchBOM), &cbActuallyWritten, 0);
  1012. if (sizeof(c_wchBOM) != cbActuallyWritten)
  1013. {
  1014. hr = HRESULT_FROM_WIN32(GetLastError());
  1015. CMTRACE(TEXT("CMLOG: Unable to set the Byte order mark while clearing the file"));
  1016. goto Cleanup;
  1017. }
  1018. m_dwSize += sizeof(c_wchBOM);
  1019. }
  1020. }
  1021. if (fWriteBannerAfterwards)
  1022. {
  1023. Banner();
  1024. }
  1025. if (fWasDisabled)
  1026. {
  1027. CloseFile();
  1028. }
  1029. Cleanup:
  1030. CMTRACEHR(TEXT("CmLogFile::Clear"), hr);
  1031. return;
  1032. }
  1033. //+----------------------------------------------------------------------------
  1034. //
  1035. // Func: CmLogFile::Banner
  1036. //
  1037. // Desc: Logs the banner heading for a Connection Manager log
  1038. //
  1039. // Args: none
  1040. //
  1041. // Return: void
  1042. //
  1043. // Notes:
  1044. //
  1045. // History: 30-Apr-2000 SumitC Created
  1046. //
  1047. //-----------------------------------------------------------------------------
  1048. void
  1049. CmLogFile::Banner()
  1050. {
  1051. HRESULT hr = S_OK;
  1052. LPTSTR psz = NULL;
  1053. if (NULL == m_hfile)
  1054. {
  1055. return;
  1056. }
  1057. //
  1058. // System information, Process, Time
  1059. //
  1060. OSVERSIONINFO VersionInfo;
  1061. LPTSTR pszPlatform = TEXT("NT");
  1062. ZeroMemory(&VersionInfo, sizeof(VersionInfo));
  1063. VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
  1064. GetVersionExU(&VersionInfo);
  1065. if (VER_PLATFORM_WIN32_WINDOWS == VersionInfo.dwPlatformId)
  1066. {
  1067. pszPlatform = TEXT("9x");
  1068. }
  1069. else if (VER_PLATFORM_WIN32_NT == VersionInfo.dwPlatformId)
  1070. {
  1071. pszPlatform = TEXT("NT");
  1072. }
  1073. else
  1074. {
  1075. CMASSERTMSG(0, TEXT("CmLogFile::Banner - platform ID is not Windows or NT"));
  1076. }
  1077. //
  1078. // Connection Manager version number (using cmdial32.dll)
  1079. //
  1080. DWORD dwCMVer = 0;
  1081. DWORD dwCMBuild = 0;
  1082. DWORD dwLCID = 0;
  1083. TCHAR szModulePath[MAX_PATH + 1];
  1084. UINT uRet = 0;
  1085. uRet = GetSystemDirectoryU(szModulePath, MAX_PATH);
  1086. if (0 == uRet)
  1087. {
  1088. CMTRACE1(TEXT("CmLogFile::Banner - GetSystemDirectoryU failed, GLE=%d"), GetLastError());
  1089. }
  1090. else
  1091. {
  1092. const LPTSTR c_pszCmdial32 = TEXT("\\cmdial32.dll");
  1093. if ((uRet + lstrlenU(c_pszCmdial32) + 1) <= MAX_PATH)
  1094. {
  1095. lstrcatU(szModulePath, c_pszCmdial32);
  1096. hr = GetModuleVersionAndLCID(szModulePath, &dwCMVer, &dwCMBuild, &dwLCID);
  1097. if (FAILED(hr))
  1098. {
  1099. CMTRACE1(TEXT("CmLogFile::Banner - couldn't get CM version, hr=%x"), hr);
  1100. }
  1101. }
  1102. }
  1103. //
  1104. // Date & Time
  1105. //
  1106. LPTSTR pszDate = NULL;
  1107. LPTSTR pszTime = NULL;
  1108. CmGetDateTime(&pszDate, &pszTime);
  1109. // strings can be NULL, but we handle that when using them (below)
  1110. LPTSTR pszFmt = CmLoadString(g_hInst, IDS_LOGFMT_BANNER);
  1111. LPTSTR pszUsers = CmLoadString(g_hInst,
  1112. m_fAllUser ? IDS_LOGSTR_ALLUSERS : IDS_LOGSTR_SINGLEUSER);
  1113. if (pszFmt && pszUsers)
  1114. {
  1115. UINT cch = lstrlenU(pszFmt) +
  1116. 1 +
  1117. (3 * lstrlenU(c_szLineOfStars)) + // occurs thrice total
  1118. lstrlenU(pszPlatform) +
  1119. (6 * 10) + // how big can a DWORD get
  1120. lstrlenU(VersionInfo.szCSDVersion) +
  1121. lstrlenU(m_pszServiceName) +
  1122. lstrlenU(pszUsers) +
  1123. (pszDate ? lstrlenU(pszDate) : 0) +
  1124. (pszTime ? lstrlenU(pszTime) : 0) +
  1125. 1;
  1126. psz = (LPTSTR) CmMalloc(cch * sizeof(TCHAR));
  1127. CMASSERTMSG(psz, TEXT("CmLogFile::Banner - couldn't log banner, malloc failed"));
  1128. if (psz)
  1129. {
  1130. //
  1131. // Unicode logfiles are marked as such using a byte order mark, which
  1132. // means that to check for an "empty" file we have to account for the
  1133. // presence of the BOM.
  1134. //
  1135. BOOL fFileIsEmpty = (m_dwSize == (OS_NT ? sizeof(c_wchBOM) : 0));
  1136. wsprintfU(psz, pszFmt,
  1137. fFileIsEmpty ? c_szEmpty : c_szNewLine, // don't start with a newline if the file is empty
  1138. c_szLineOfStars,
  1139. pszPlatform,
  1140. VersionInfo.dwMajorVersion, VersionInfo.dwMinorVersion, VersionInfo.szCSDVersion,
  1141. HIWORD(dwCMVer), LOWORD(dwCMVer), HIWORD(dwCMBuild), LOWORD(dwCMBuild),
  1142. m_pszServiceName,
  1143. pszUsers,
  1144. (pszDate ? pszDate : TEXT("")),
  1145. (pszTime ? pszTime : TEXT("")),
  1146. c_szLineOfStars,
  1147. c_szLineOfStars);
  1148. CMTRACE(TEXT("CmLogFile::Banner - wrote banner"));
  1149. }
  1150. }
  1151. CmFree(pszFmt);
  1152. CmFree(pszUsers);
  1153. CmFree(pszDate);
  1154. CmFree(pszTime);
  1155. //
  1156. // Write it out...
  1157. //
  1158. if (psz)
  1159. {
  1160. Write(psz);
  1161. CmFree(psz);
  1162. }
  1163. }
  1164. //+----------------------------------------------------------------------------
  1165. //
  1166. // Func: GetLogDesc
  1167. //
  1168. // Desc: Utility function, returns log item friendly name (desc)
  1169. //
  1170. // Args: [eItem] - the log item about which to return information
  1171. //
  1172. // Return: LPTSTR if found, or NULL if not
  1173. //
  1174. // Notes:
  1175. //
  1176. // History: 30-Apr-2000 SumitC Created
  1177. //
  1178. //-----------------------------------------------------------------------------
  1179. LPTSTR
  1180. GetLogDesc(_CMLOG_ITEM eItem)
  1181. {
  1182. CMASSERTMSG(VERIFY_CMLOG_ITEM_OK(eItem), TEXT("GetLogDesc - eItem must represent valid Log item"));
  1183. return CmLoadString(g_hInst, s_aCmLogItems[eItem - 1].idDesc);
  1184. }
  1185. //+----------------------------------------------------------------------------
  1186. //
  1187. // Func: GetLogFormat
  1188. //
  1189. // Desc: Utility function, returns log item Format
  1190. //
  1191. // Args: [eItem] - the log item about which to return information
  1192. // [fUnicode] - is the caller unicode?
  1193. //
  1194. // Return: LPTSTR if found, or NULL if not
  1195. //
  1196. // Notes:
  1197. //
  1198. // History: 30-Apr-2000 SumitC Created
  1199. //
  1200. //-----------------------------------------------------------------------------
  1201. LPTSTR
  1202. GetLogFormat(_CMLOG_ITEM eItem, BOOL fUnicode)
  1203. {
  1204. CMASSERTMSG(VERIFY_CMLOG_ITEM_OK(eItem), TEXT("GetLogFormat - eItem must represent valid Log item"));
  1205. CMASSERTMSG(fUnicode, TEXT("GetLogFormat - currently cmlog is only being compiled unicode"));
  1206. LPTSTR pszFmt = CmLoadString(g_hInst, s_aCmLogItems[eItem - 1].idFormat);
  1207. if (0 == lstrcmpU(TEXT(""), pszFmt))
  1208. {
  1209. // NOTE: CmLoadString has a rather broken implementation where it decides
  1210. // to return empty strings in case of failure. This is a problem
  1211. // because (a) it makes it impossible to detect an actual failure,
  1212. // as opposed to an empty string, and and (b) it uses an alloc within
  1213. // a return statement, so it can fail anyway. This 'if' block
  1214. // gives me back a NULL so that my code can work the way it should.
  1215. CmFree(pszFmt);
  1216. return NULL;
  1217. }
  1218. else if (pszFmt)
  1219. {
  1220. // If the module is compiled unicode, then fUnicode=false requires conversion.
  1221. // If the module is compiled ANSI, then fUnicode=true requires conversion.
  1222. #if 0 // since we're compiled Unicode for now
  1223. #ifdef UNICODE
  1224. if (!fUnicode)
  1225. {
  1226. if (FALSE == ConvertFormatString(pszFmt))
  1227. {
  1228. return NULL;
  1229. }
  1230. }
  1231. #else
  1232. if (fUnicode)
  1233. {
  1234. if (FALSE == ConvertFormatString(pszFmt))
  1235. {
  1236. return NULL;
  1237. }
  1238. }
  1239. #endif
  1240. #endif // 0
  1241. return pszFmt;
  1242. }
  1243. else
  1244. {
  1245. return NULL;
  1246. }
  1247. }
  1248. #undef CMLOG_IMPLEMENTATION