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.

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