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.

325 lines
11 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. log.c
  5. Abstract:
  6. This module contains the implementation of factory specific logging functions.
  7. Author:
  8. Adrian Cosma (acosma) - 2/14/2001
  9. Revision History:
  10. Details:
  11. There are 3 logging functions:
  12. 1) DWORD FacLogFile(DWORD dwLogOpt, UINT uFormat, ...)
  13. - This takes a variable list of arguments and a resource ID for the error message, followed by
  14. strings to fill in any fields specified int the resource string. The format sepcifiers are the
  15. standard C printf() format specifiers.
  16. 2) DWORD FacLogFileStr(DWORD dwLogOpt, LPTSTR lpFormat, ...)
  17. - This takes a variable list of arguments and a string for the error message followed by a variable
  18. number of strings to fill in any fields specified in the error string. The format sepcifiers are the
  19. standard C printf() format specifiers.
  20. 3) DWORD FacLogFileLst(LPCTSTR lpFileName, DWORD dwLogOpt, LPTSTR lpFormat, va_list lpArgs)
  21. - This takes a variable list of arguments as a va_list. Normally you should not call this function directly.
  22. Logging options in dwLogOpt - these flags are defined in factoryp.h.
  23. #define LOG_DEBUG 0x00000003 // Only log in debug builds if this is specified. (Debug Level for logging.)
  24. #define LOG_MSG_BOX 0x00000010 // Also display a message box with the error message if this is enabled.
  25. #define LOG_ERR 0x00000020 // Prefix the logged string with "Error:" if the message is level 0,
  26. // or "WARNx" if the message is at level x > 0.
  27. #define LOG_TIME 0x00000040 // Log time if this is enabled
  28. #define LOG_NO_NL 0x00000080 // Don't add new Line to the end of log string if this is set.
  29. ( A '\n' is appended by default to all strings logged if there is no
  30. terminating '\n'.)
  31. The LogLevel can be set through the winbom through LogLevel=N in the [Factory] section. The default LogLevel in free builds is 0, and the default LogLevel in
  32. checked builds is LOG_DEBUG (3). The maximum log level in free builds is 2. Any message at MessageLogLevel <= LogLevel
  33. will be logged.
  34. Return value: DWORD - number of bytes written to the log file (this is twice the number of chars in case of UNICODE).
  35. Examples:
  36. FacLogFileStr(3 | LOG_TIME, _T("Starting to format %c:."), pCur->cDriveLetter);
  37. - Only log this in Debug builds (3), log the time along with the error message.
  38. FacLogFile(0 | LOG_ERR, IDS_ERR_HUGE_ERROR, dwErrorCode);
  39. - Always log this error. IDS_ERR_HUGE_ERROR must be defined as a resource in this image.
  40. IDS_ERR_HUGE_ERROR should look something like this: "Huge Error! Error code: %d". Note the %d is
  41. for the dwErrorCode.
  42. --*/
  43. //
  44. // Includes
  45. //
  46. #include "factoryp.h"
  47. //
  48. // Defines
  49. //
  50. #ifdef CHR_NEWLINE
  51. #undef CHR_NEWLINE
  52. #endif // CHR_NEWLINE
  53. #define CHR_NEWLINE _T('\n')
  54. #ifdef CHR_CR
  55. #undef CHR_CR
  56. #endif // CHR_CR
  57. #define CHR_CR _T('\r')
  58. //
  59. // NTRAID#NTBUG9-549770-2002/02/26-acosma - Buffer overruns everywhere in this code. lstrcpy, lstrcat, wsprintf, etc.
  60. //
  61. //
  62. // Function Implementations
  63. //
  64. DWORD FacLogFileLst(LPCTSTR lpFileName, DWORD dwLogOpt, LPTSTR lpFormat, va_list lpArgs)
  65. {
  66. LPTSTR lpAppName = NULL;
  67. LPTSTR lpPreOut = NULL;
  68. LPTSTR lpOut = NULL;
  69. DWORD dwSize = 1024;
  70. TCHAR szPreLog[MAX_PATH] = NULLSTR;
  71. HANDLE hFile;
  72. DWORD dwWritten = 0;
  73. DWORD cbAppName = 0;
  74. DWORD dwLogLevel = (DWORD) (dwLogOpt & LOG_LEVEL_MASK);
  75. if ( ( dwLogLevel <= g_dwDebugLevel) && lpFormat )
  76. {
  77. // Get the application title from resource.
  78. //
  79. lpAppName = AllocateString(g_hInstance, IDS_APPNAME);
  80. // Build the output string.
  81. //
  82. if ( lpAppName )
  83. {
  84. // Create the prefix string
  85. //
  86. lstrcpyn(szPreLog, lpAppName, AS ( szPreLog ) );
  87. if ( FAILED ( StringCchCat ( szPreLog, AS ( szPreLog ), _T("::")) ) )
  88. {
  89. FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szPreLog, _T("::") ) ;
  90. }
  91. }
  92. // This is for skipping the App Name prefix when printing to the log file
  93. //
  94. cbAppName = lstrlen(szPreLog);
  95. if ( GET_FLAG(dwLogOpt, LOG_ERR) )
  96. {
  97. if ( 0 == dwLogLevel )
  98. {
  99. if ( FAILED ( StringCchCat ( szPreLog, AS ( szPreLog ), _T("ERROR: ")) ) )
  100. {
  101. FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szPreLog, _T("ERROR: ") ) ;
  102. }
  103. }
  104. else
  105. {
  106. if ( FAILED ( StringCchPrintfW ( szPreLog + cbAppName, AS ( szPreLog ) - cbAppName, _T("WARN%d: "), dwLogLevel) ) )
  107. {
  108. FacLogFileStr(3, _T("StringCchPrintfW failed %s WARN%d: \n"), szPreLog, dwLogLevel ) ;
  109. }
  110. }
  111. }
  112. if ( GET_FLAG(dwLogOpt, LOG_TIME) )
  113. {
  114. TCHAR szTime[100] = NULLSTR;
  115. GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, NULL, _T("'['HH':'mm':'ss'] '"), szTime, AS(szTime));
  116. if ( FAILED ( StringCchCat ( szPreLog, AS ( szPreLog ), szTime) ) )
  117. {
  118. FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szPreLog, szTime ) ;
  119. }
  120. }
  121. // Replace all the parameters in the Error string. Allocate more memory if necessary.
  122. // In case something goes seriously wrong here, cap memory allocation at 1 megabyte.
  123. //
  124. for ( lpPreOut = (LPTSTR) MALLOC((dwSize) * sizeof(TCHAR));
  125. lpPreOut && ( FAILED ( StringCchVPrintfW(lpPreOut, dwSize, lpFormat, lpArgs)) ) && dwSize < (1024 * 1024);
  126. FREE(lpPreOut), lpPreOut = (LPTSTR) MALLOC((dwSize *= 2) * sizeof(TCHAR))
  127. );
  128. //
  129. // We now have the Error string and the prefix string. Copy this to the final
  130. // string that we need to output.
  131. //
  132. if ( lpPreOut )
  133. {
  134. // Allocate another string that will be the final output string.
  135. // We need 1 extra TCHAR for NULL terminator and 2 extra for
  136. // an optional NewLine + Linefeed TCHAR pair that may be added.
  137. //
  138. dwSize = lstrlen(szPreLog) + lstrlen(lpPreOut) + 3;
  139. lpOut = (LPTSTR) MALLOC( (dwSize) * sizeof(TCHAR) );
  140. if ( lpOut )
  141. {
  142. lstrcpyn(lpOut, szPreLog, dwSize);
  143. if ( FAILED ( StringCchCat ( lpOut, dwSize, lpPreOut) ) )
  144. {
  145. FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), lpOut, lpPreOut ) ;
  146. }
  147. // Make sure that string is terminated by NewLine unless the caller doesn't want to.
  148. //
  149. if ( !GET_FLAG(dwLogOpt, LOG_NO_NL) )
  150. {
  151. LPTSTR lpNL = lpOut;
  152. TCHAR szCRLF[] = _T("\r\n");
  153. BOOL bStringOk = FALSE;
  154. // Find the end of the string.
  155. //
  156. lpNL = lpNL + lstrlen(lpNL);
  157. // Make sure the string is terminated by "\r\n".
  158. //
  159. // There are three cases here:
  160. // 1. The string is already terminated by \r\n. Leave it alone.
  161. // 2. String is terminated by \n. Replace \n with \r\n.
  162. // 3. String is not terminated by anything. Append string with \r\n.
  163. //
  164. if ( CHR_NEWLINE == *(lpNL = (CharPrev(lpOut, lpNL))) )
  165. {
  166. if ( CHR_CR != *(CharPrev(lpOut, lpNL)) )
  167. {
  168. *(lpNL) = NULLCHR;
  169. }
  170. else
  171. {
  172. bStringOk = TRUE;
  173. }
  174. }
  175. // If there is a need to, fix up the string
  176. //
  177. if ( !bStringOk )
  178. {
  179. if ( FAILED ( StringCchCat ( lpOut, dwSize, szCRLF) ) )
  180. {
  181. FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), lpOut, szCRLF ) ;
  182. }
  183. }
  184. }
  185. // Write the error to the file and close the file.
  186. // Skip the "AppName::" at the beginning of the string when printing to the file.
  187. //
  188. if ( lpFileName && lpFileName[0] &&
  189. ( INVALID_HANDLE_VALUE != (hFile = CreateFile(g_szLogFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)))
  190. )
  191. {
  192. if ( INVALID_SET_FILE_POINTER != SetFilePointer(hFile, 0, 0, FILE_END) )
  193. {
  194. WriteFile(hFile, (lpOut + cbAppName), lstrlen(lpOut + cbAppName) * sizeof(TCHAR), &dwWritten, NULL);
  195. }
  196. CloseHandle(hFile);
  197. }
  198. // Output the string to the debugger and free it.
  199. //
  200. OutputDebugString(lpOut);
  201. FREE(lpOut);
  202. }
  203. // Put up the MessageBox if specified. This only allows message boxes
  204. // to be log level 0.
  205. //
  206. if ( !GET_FLAG(g_dwFactoryFlags, FLAG_QUIET_MODE) &&
  207. GET_FLAG(dwLogOpt, LOG_MSG_BOX) &&
  208. (0 == dwLogLevel)
  209. )
  210. MessageBox(NULL, lpPreOut, lpAppName, MB_OK | MB_SYSTEMMODAL |
  211. (GET_FLAG(dwLogOpt, LOG_ERR) ? MB_ICONERROR : MB_ICONWARNING) );
  212. // Free the error string
  213. //
  214. FREE(lpPreOut);
  215. }
  216. }
  217. // Return the number of bytes written to the file.
  218. //
  219. return dwWritten;
  220. }
  221. DWORD FacLogFile(DWORD dwLogOpt, UINT uFormat, ...)
  222. {
  223. va_list lpArgs;
  224. DWORD dwWritten = 0;
  225. LPTSTR lpFormat = NULL;
  226. // Initialize the lpArgs parameter with va_start().
  227. //
  228. va_start(lpArgs, uFormat);
  229. if ( lpFormat = AllocateString(NULL, uFormat) )
  230. {
  231. dwWritten = FacLogFileLst(g_szLogFile, dwLogOpt, lpFormat, lpArgs);
  232. }
  233. // Free the format string.
  234. //
  235. FREE(lpFormat);
  236. // Return the value saved from the previous function call.
  237. //
  238. return dwWritten;
  239. }
  240. DWORD FacLogFileStr(DWORD dwLogOpt, LPTSTR lpFormat, ...)
  241. {
  242. va_list lpArgs;
  243. DWORD dwWritten = 0;
  244. // Initialize the lpArgs parameter with va_start().
  245. //
  246. va_start(lpArgs, lpFormat);
  247. dwWritten = FacLogFileLst(g_szLogFile, dwLogOpt, lpFormat, lpArgs);
  248. // Return the value saved from the previous function call.
  249. //
  250. return dwWritten;
  251. }