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.

371 lines
11 KiB

  1. //#pragma title( "Err.cpp - Basic error handling/message/logging" )
  2. /*
  3. Copyright (c) 1995-1998, Mission Critical Software, Inc. All rights reserved.
  4. ===============================================================================
  5. Module - Err.cpp
  6. System - Common
  7. Author - Tom Bernhardt, Rich Denham
  8. Created - 1994-08-22
  9. Description - Implements the TError class that handles basic exception
  10. handling, message generation, and logging functions.
  11. Updates - 1997-09-12 RED replace TTime class
  12. ===============================================================================
  13. */
  14. #ifdef USE_STDAFX
  15. # include "stdafx.h"
  16. #else
  17. # include <windows.h>
  18. #endif
  19. #ifndef WIN16_VERSION
  20. #include <lm.h>
  21. #endif
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <fcntl.h>
  25. #include <io.h>
  26. #include <string.h>
  27. #include <stdarg.h>
  28. #include <share.h>
  29. #include <time.h>
  30. #include <rpc.h>
  31. #include <rpcdce.h>
  32. #include <sys\types.h>
  33. #include <sys\stat.h>
  34. #include "Common.hpp"
  35. #include "Err.hpp"
  36. #include "UString.hpp"
  37. #define TERR_MAX_MSG_LEN (2000)
  38. #define BYTE_ORDER_MARK (0xFEFF)
  39. TError::TError(
  40. int displevel ,// in -mimimum severity level to display
  41. int loglevel ,// in -mimimum severity level to log
  42. WCHAR const * filename ,// in -file name of log (NULL if none)
  43. int logmode ,// in -0=replace, 1=append
  44. int beeplevel // in -min error level for beeping
  45. )
  46. {
  47. lastError = 0;
  48. maxError = 0;
  49. logLevel = loglevel;
  50. dispLevel = displevel;
  51. logFile = NULL;
  52. beepLevel = beeplevel;
  53. LogOpen(filename, logmode, loglevel);
  54. }
  55. TError::~TError()
  56. {
  57. LogClose();
  58. }
  59. // Closes any existing open logFile and opens a new log file if the fileName is
  60. // not null. If it is a null string, then a default fileName of "Temp.log" is
  61. // used.
  62. BOOL
  63. TError::LogOpen(
  64. WCHAR const * fileName ,// in -name of file including any path
  65. int mode ,// in -0=overwrite, 1=append
  66. int level // in -minimum level to log
  67. )
  68. {
  69. BOOL retval=TRUE;
  70. if ( logFile )
  71. {
  72. fclose(logFile);
  73. logFile = NULL;
  74. }
  75. if ( fileName && fileName[0] )
  76. {
  77. // Check to see if the file already exists
  78. WIN32_FIND_DATA fDat;
  79. HANDLE hFind;
  80. BOOL bExisted = FALSE;
  81. hFind = FindFirstFile(fileName,&fDat);
  82. if ( hFind != INVALID_HANDLE_VALUE )
  83. {
  84. FindClose(hFind);
  85. bExisted = TRUE;
  86. }
  87. logFile = _wfsopen( fileName, mode == 0 ? L"wb" : L"ab", _SH_DENYNO );
  88. if ( !logFile )
  89. {
  90. MsgWrite( 4101, L"Log Open(%s) failed", fileName );
  91. retval = FALSE;
  92. }
  93. else
  94. {
  95. if (! bExisted )
  96. {
  97. // this is a new file we've just created
  98. // we need to write the byte order mark to the beginning of the file
  99. WCHAR x = BYTE_ORDER_MARK;
  100. fwprintf(logFile,L"%lc",x);
  101. }
  102. }
  103. }
  104. logLevel = level;
  105. return retval;
  106. }
  107. //-----------------------------------------------------------------------------
  108. // Writes formatted message to log file and flushes buffers
  109. //-----------------------------------------------------------------------------
  110. void TError::LogWrite(WCHAR const * msg)
  111. {
  112. WCHAR sTime[32];
  113. WCHAR sTemp[TERR_MAX_MSG_LEN];
  114. // Get rid of the <CR> from the end of the message because it causes things
  115. // to run together in the logs
  116. wcscpy(sTemp, msg);
  117. DWORD dwLen = wcslen(sTemp);
  118. if ( sTemp[dwLen-1] == 0x0d )
  119. sTemp[dwLen-1] = 0x00;
  120. if ( logFile )
  121. {
  122. fwprintf(
  123. logFile,
  124. L"%s-%s\r\n",
  125. gTTime.FormatIsoLcl( gTTime.Now( NULL ), sTime ),
  126. sTemp );
  127. fflush( logFile );
  128. }
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Error message with format and arguments
  132. //-----------------------------------------------------------------------------
  133. void __cdecl
  134. TError::MsgWrite(
  135. int num ,// in -error number/level code
  136. WCHAR const msg[] ,// in -error message to display
  137. ... // in -printf args to msg pattern
  138. )
  139. {
  140. WCHAR suffix[TERR_MAX_MSG_LEN];
  141. va_list argPtr;
  142. va_start(argPtr, msg);
  143. _vsnwprintf(suffix, DIM(suffix) - 1, msg, argPtr);
  144. suffix[DIM(suffix) - 1] = L'\0';
  145. va_end(argPtr);
  146. MsgProcess(num, suffix);
  147. }
  148. #ifndef WIN16_VERSION
  149. //-----------------------------------------------------------------------------
  150. // System Error message with format and arguments
  151. //-----------------------------------------------------------------------------
  152. void __cdecl
  153. TError::SysMsgWrite(
  154. int num ,// in -error number/level code
  155. DWORD lastRc ,// in -error return code
  156. WCHAR const msg[] ,// in -error message/pattern to display
  157. ... // in -printf args to msg pattern
  158. )
  159. {
  160. WCHAR suffix[TERR_MAX_MSG_LEN];
  161. va_list argPtr;
  162. int len;
  163. // When an error occurs while in a constructor for a global object,
  164. // the TError object may not yet exist. In this case, "this" is zero
  165. // and we gotta get out of here before we generate a protection exception.
  166. if ( !this )
  167. return;
  168. va_start(argPtr, msg);
  169. len = _vsnwprintf(suffix, DIM(suffix) - 1, msg, argPtr);
  170. // append the system message for the lastRc at the end.
  171. if ( len < DIM(suffix) - 1 )
  172. {
  173. ErrorCodeToText(lastRc, DIM(suffix) - len - 1, suffix + len);
  174. }
  175. suffix[DIM(suffix) - 1] = L'\0';
  176. va_end(argPtr);
  177. MsgProcess(num, suffix);
  178. }
  179. //-----------------------------------------------------------------------------
  180. // System Error message with format and arguments
  181. //-----------------------------------------------------------------------------
  182. void __cdecl
  183. TError::SysMsgWrite(
  184. int num ,// in -error number/level code
  185. WCHAR const msg[] ,// in -error message/pattern to display
  186. ... // in -printf args to msg pattern
  187. )
  188. {
  189. WCHAR suffix[TERR_MAX_MSG_LEN];
  190. va_list argPtr;
  191. int len;
  192. DWORD lastRc = GetLastError();
  193. // When an error occurs while in a constructor for a global object,
  194. // the TError object may not yet exist. In this case, "this" is zero
  195. // and we gotta get out of here before we generate a protection exception.
  196. if ( !this )
  197. return;
  198. va_start( argPtr, msg );
  199. len = _vsnwprintf( suffix, DIM(suffix) - 1, msg, argPtr );
  200. // append the system message for the lastRc at the end.
  201. if ( len < DIM(suffix) - 1 )
  202. {
  203. ErrorCodeToText(lastRc, DIM(suffix) - len - 1, suffix + len);
  204. }
  205. suffix[DIM(suffix) - 1] = L'\0';
  206. va_end(argPtr);
  207. MsgProcess(num, suffix);
  208. }
  209. #endif
  210. //-----------------------------------------------------------------------------
  211. // Error message format, display and exception processing function
  212. //-----------------------------------------------------------------------------
  213. void __stdcall
  214. TError::MsgProcess(
  215. int num ,// in -error number/level code
  216. WCHAR const * str // in -error string to display
  217. )
  218. {
  219. static WCHAR const prefLetter[] = L"TIWESVUXXXXX"; // These form the status code that appears at the start of each error message
  220. WCHAR fullmsg[TERR_MAX_MSG_LEN];
  221. struct
  222. {
  223. USHORT frequency; // audio frequency
  224. USHORT duration; // duration in mSec
  225. } audio[] = {{ 300, 20},{ 500, 50},{ 700, 100},
  226. { 800, 200},{1000, 300},{1500, 400},
  227. {2500, 750},{2500,1000},{2500,1000}};
  228. if ( num >= 0 )
  229. level = num / 10000; // 10000's position of error number
  230. else
  231. level = -1;
  232. if ( num == 0 )
  233. {
  234. wcsncpy(fullmsg, str, DIM(fullmsg));
  235. fullmsg[DIM(fullmsg) - 1] = L'\0'; // ensure null termination
  236. }
  237. else
  238. {
  239. if ( num > maxError )
  240. maxError = num;
  241. _snwprintf(fullmsg, DIM(fullmsg), L"%c%05d: %-s", prefLetter[level+1], num, str);
  242. fullmsg[DIM(fullmsg) - 1] = L'\0'; // ensure null termination
  243. }
  244. lastError = num;
  245. StrWrite(level, fullmsg);
  246. if ( level >= beepLevel )
  247. Beep(audio[level].frequency, audio[level].duration);
  248. if ( level >= logLevel )
  249. LogWrite(fullmsg);
  250. if ( level > 4 )
  251. {
  252. exit(level);
  253. }
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Return text for error code
  257. //-----------------------------------------------------------------------------
  258. WCHAR *
  259. TError::ErrorCodeToText(
  260. DWORD code ,// in -message code
  261. DWORD lenMsg ,// in -length of message text area
  262. WCHAR * msg // out-returned message text
  263. )
  264. {
  265. static HMODULE hNetMsg = NULL;
  266. DWORD rc;
  267. WCHAR * pMsg;
  268. msg[0] = '\0'; // force to null
  269. if ( code >= NERR_BASE && code < MAX_NERR )
  270. {
  271. if ( !hNetMsg )
  272. hNetMsg = LoadLibrary(L"netmsg.dll");
  273. rc = 1;
  274. }
  275. else
  276. {
  277. rc = DceErrorInqText( code, msg );
  278. // Change any imbedded CR or LF to blank.
  279. for ( pMsg = msg;
  280. *pMsg;
  281. pMsg++ )
  282. {
  283. if ( (*pMsg == L'\x0D') || (*pMsg == L'\x0A') )
  284. *pMsg = L' ';
  285. }
  286. // Remove trailing blanks
  287. for ( pMsg--;
  288. pMsg >= msg;
  289. pMsg-- )
  290. {
  291. if ( *pMsg == L' ' )
  292. *pMsg = L'\0';
  293. else
  294. break;
  295. }
  296. }
  297. if ( rc )
  298. {
  299. if ( code >= NERR_BASE && code < MAX_NERR && hNetMsg )
  300. {
  301. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE
  302. | FORMAT_MESSAGE_MAX_WIDTH_MASK
  303. | FORMAT_MESSAGE_IGNORE_INSERTS
  304. | 80,
  305. hNetMsg,
  306. code,
  307. 0,
  308. msg,
  309. lenMsg,
  310. NULL );
  311. }
  312. else
  313. {
  314. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
  315. | FORMAT_MESSAGE_MAX_WIDTH_MASK
  316. | FORMAT_MESSAGE_IGNORE_INSERTS
  317. | 80,
  318. NULL,
  319. code,
  320. 0,
  321. msg,
  322. lenMsg,
  323. NULL );
  324. }
  325. }
  326. return msg;
  327. }
  328. // Err.cpp - end of file