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.

673 lines
16 KiB

  1. /////////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1998 Active Voice Corporation. All Rights Reserved.
  4. //
  5. // Active Agent(r) and Unified Communications(tm) are trademarks of Active Voice Corporation.
  6. //
  7. // Other brand and product names used herein are trademarks of their respective owners.
  8. //
  9. // The entire program and user interface including the structure, sequence, selection,
  10. // and arrangement of the dialog, the exclusively "yes" and "no" choices represented
  11. // by "1" and "2," and each dialog message are protected by copyrights registered in
  12. // the United States and by international treaties.
  13. //
  14. // Protected by one or more of the following United States patents: 5,070,526, 5,488,650,
  15. // 5,434,906, 5,581,604, 5,533,102, 5,568,540, 5,625,676, 5,651,054.
  16. //
  17. // Active Voice Corporation
  18. // Seattle, Washington
  19. // USA
  20. //
  21. /////////////////////////////////////////////////////////////////////////////////////////
  22. ////
  23. // trace.c - debug trace functions
  24. ////
  25. #ifndef NOTRACE
  26. #include "winlocal.h"
  27. #include <stdlib.h>
  28. #include <stdarg.h>
  29. #include "trace.h"
  30. #include "mem.h"
  31. #include "sys.h"
  32. #include "str.h"
  33. ////
  34. // private definitions
  35. ////
  36. // wOutputTo values
  37. //
  38. #define TRACE_OUTPUTNONE 0x0000
  39. #define TRACE_OUTPUTDEBUGSTRING 0x0001
  40. #define TRACE_OUTPUTCOMM 0x0002
  41. #if 0 // no longer supported
  42. #define TRACE_OUTPUTFILE 0x0004
  43. #endif
  44. #ifdef _WIN32
  45. #define TRACE_OUTPUTCONSOLE 0x0008
  46. #endif
  47. // trace control struct
  48. //
  49. typedef struct TRACE
  50. {
  51. DWORD dwVersion;
  52. HINSTANCE hInst;
  53. HTASK hTask;
  54. int nLevel;
  55. int wOutputTo;
  56. #ifdef TRACE_OUTPUTFILE
  57. HFIL hFile;
  58. #endif
  59. #ifdef _WIN32
  60. HANDLE hConsole;
  61. #endif
  62. int hComm;
  63. LPTSTR lpszTemp;
  64. } TRACE, FAR *LPTRACE;
  65. // shared trace engine handle
  66. //
  67. static LPTRACE lpTraceShare = NULL;
  68. static int cShareUsage = 0;
  69. #define TRACE_SECTION TEXT("TRACE")
  70. #define TRACE_PROFILE TraceGetProfile()
  71. // helper functions
  72. //
  73. static LPTRACE TraceGetPtr(HTRACE hTrace);
  74. static HTRACE TraceGetHandle(LPTRACE lpTrace);
  75. static int TraceError(LPCTSTR lpszFormat, ...);
  76. static LPTSTR TraceGetProfile(void);
  77. ////
  78. // public functions
  79. ////
  80. // TraceInit - initialize trace engine
  81. // <dwVersion> (i) must be TRACE_VERSION
  82. // <hInst> (i) instance of calling module
  83. // return handle to trace engine (NULL if error)
  84. //
  85. // NOTE: The level and destination of trace output is determined
  86. // by values found in the file TRACE.INI in the Windows directory.
  87. // TRACE.INI is expected to have the following format:
  88. //
  89. // [TRACE]
  90. // Level=0 {TRACE_MINLEVEL...TRACE_MAXLEVEL}
  91. // OutputTo= OutputDebugString()
  92. // =COM1 COM1:9600,n,8,1
  93. // =COM2:2400,n,8,1 specified comm device
  94. // =filename specified file
  95. #ifdef _WIN32
  96. // =console stdout
  97. #endif
  98. //
  99. HTRACE DLLEXPORT WINAPI TraceInit(DWORD dwVersion, HINSTANCE hInst)
  100. {
  101. BOOL fSuccess = TRUE;
  102. LPTRACE lpTrace = NULL;
  103. TCHAR szOutputTo[_MAX_PATH];
  104. #ifdef _WIN32
  105. BOOL fShare = TRUE; // FALSE;
  106. #else
  107. BOOL fShare = TRUE;
  108. #endif
  109. int nLevel = -1;
  110. LPTSTR lpszOutputTo = NULL;
  111. if (dwVersion != TRACE_VERSION)
  112. fSuccess = FALSE;
  113. else if (hInst == NULL)
  114. fSuccess = FALSE;
  115. else if (nLevel != -1 &&
  116. (nLevel < TRACE_MINLEVEL || nLevel > TRACE_MAXLEVEL))
  117. fSuccess = FALSE;
  118. // if a shared trace engine already exists,
  119. // use it rather than create another one
  120. //
  121. else if (fShare && cShareUsage > 0 && lpTraceShare != NULL)
  122. lpTrace = lpTraceShare;
  123. #if 0 // can't call mem functions, because they require trace functions
  124. else if ((lpTrace = (LPTRACE) MemAlloc(NULL, sizeof(TRACE), 0)) == NULL)
  125. #else
  126. #ifdef _WIN32
  127. else if ((lpTrace = (LPTRACE) HeapAlloc(GetProcessHeap(),
  128. HEAP_ZERO_MEMORY, sizeof(TRACE))) == NULL)
  129. #else
  130. else if ((lpTrace = (LPTRACE) GlobalAllocPtr(GMEM_MOVEABLE |
  131. GMEM_ZEROINIT, sizeof(TRACE))) == NULL)
  132. #endif
  133. #endif
  134. fSuccess = FALSE;
  135. else
  136. {
  137. lpTrace->dwVersion = dwVersion;
  138. lpTrace->hInst = hInst;
  139. lpTrace->hTask = GetCurrentTask();
  140. lpTrace->nLevel = nLevel != -1 ? nLevel :
  141. GetPrivateProfileInt(TRACE_SECTION, TEXT("Level"), 0, TRACE_PROFILE);
  142. lpTrace->wOutputTo = TRACE_OUTPUTNONE;
  143. #ifdef TRACE_OUTPUTFILE
  144. lpTrace->hFile = NULL;
  145. #endif
  146. #ifdef _WIN32
  147. lpTrace->hConsole = NULL;
  148. #endif
  149. lpTrace->hComm = -1;
  150. lpTrace->lpszTemp = NULL;
  151. // use the specified destination if possible
  152. //
  153. if (lpszOutputTo != NULL)
  154. StrNCpy(szOutputTo, lpszOutputTo, SIZEOFARRAY(szOutputTo));
  155. // else use the last known destination
  156. //
  157. else
  158. {
  159. GetPrivateProfileString(TRACE_SECTION, TEXT("OutputTo"), TEXT(""),
  160. szOutputTo, SIZEOFARRAY(szOutputTo), TRACE_PROFILE);
  161. }
  162. // use OutputDebugString() if destination == ""
  163. //
  164. if (*szOutputTo == '\0')
  165. lpTrace->wOutputTo = TRACE_OUTPUTDEBUGSTRING;
  166. // use standard output console if specified
  167. //
  168. else if (StrICmp(szOutputTo, TEXT("Console")) == 0)
  169. {
  170. #ifdef _WIN32
  171. COORD coord;
  172. lpTrace->wOutputTo = TRACE_OUTPUTCONSOLE;
  173. AllocConsole();
  174. lpTrace->hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
  175. coord.X = 80;
  176. coord.Y = 1000;
  177. SetConsoleScreenBufferSize(lpTrace->hConsole, coord);
  178. #else
  179. lpTrace->wOutputTo = TRACE_OUTPUTDEBUGSTRING;
  180. #endif
  181. }
  182. // use serial comm device if destination starts with "COMx"
  183. //
  184. else if (StrNICmp(szOutputTo, TEXT("COM"), 3) == 0 &&
  185. ChrIsDigit(*(szOutputTo + 3)))
  186. {
  187. // Comm functions not available under WIN32
  188. //
  189. #ifdef _WIN32
  190. lpTrace->wOutputTo = TRACE_OUTPUTDEBUGSTRING;
  191. #else
  192. TCHAR szComX[16];
  193. DCB dcb;
  194. int iError;
  195. StrNCpy(szComX, szOutputTo, 5);
  196. *(szComX + 5) = '\0';
  197. // convert "COM1" to "COM1:"
  198. //
  199. if (*(szOutputTo + 4) == '\0')
  200. StrCat(szOutputTo, TEXT(":"));
  201. // convert "COM1:" to "COM1:9600,n,8,1"
  202. //
  203. if (*(szOutputTo + 5) == '\0')
  204. StrCat(szOutputTo, TEXT("9600,n,8,1"));
  205. // [From the WinSDK KnowledgeBase PSS ID Number: Q102642]
  206. // The cbInQueue and cbOutQueue parameters of OpenComm() are
  207. // both type UINT and should be valid up to 64K. However,
  208. // values greater than or equal to 32K cause strange behavior.
  209. //
  210. if ((lpTrace->hComm = OpenComm(szComX, 1024, 32767)) < 0)
  211. {
  212. TraceError(TEXT("OpenComm error (%d)\n"), lpTrace->hComm);
  213. lpTrace->hComm = -1;
  214. fSuccess = FALSE;
  215. }
  216. else if ((iError = BuildCommDCB(szOutputTo, &dcb)) != 0)
  217. {
  218. TraceError(TEXT("BuildCommDCB error (%d)\n"), iError);
  219. fSuccess = FALSE;
  220. }
  221. else if ((iError = SetCommState(&dcb)) != 0)
  222. {
  223. TraceError(TEXT("SetCommState error (%d)\n"), iError);
  224. fSuccess = FALSE;
  225. }
  226. else
  227. lpTrace->wOutputTo = TRACE_OUTPUTCOMM;
  228. #endif
  229. }
  230. #ifdef TRACE_OUTPUTFILE
  231. // else assume the string must be a file name
  232. //
  233. else
  234. {
  235. if ((lpTrace->hFile = FileCreate(szOutputTo, 0, !fShare)) == NULL)
  236. {
  237. TraceError(TEXT("FileCreate error (%s)\n"), (LPTSTR) szOutputTo);
  238. fSuccess = FALSE;
  239. }
  240. else
  241. lpTrace->wOutputTo = TRACE_OUTPUTFILE;
  242. }
  243. #else
  244. else
  245. {
  246. TraceError(TEXT("Unknown trace OutputTo (%s)\n"), (LPTSTR) szOutputTo);
  247. fSuccess = FALSE;
  248. }
  249. #endif
  250. if (fSuccess &&
  251. #if 0 // can't call mem functions, because they require trace functions
  252. (lpTrace->lpszTemp = (LPTSTR) MemAlloc(NULL,
  253. 1024 * sizeof(TCHAR), 0)) == NULL)
  254. #else
  255. #ifdef _WIN32
  256. (lpTrace->lpszTemp = (LPTSTR) HeapAlloc(GetProcessHeap(),
  257. HEAP_ZERO_MEMORY, 1024 * sizeof(TCHAR))) == NULL)
  258. #else
  259. (lpTrace->lpszTemp = (LPTSTR) GlobalAllocPtr(
  260. GMEM_MOVEABLE | GMEM_ZEROINIT, 1024 * sizeof(TCHAR))) == NULL)
  261. #endif
  262. #endif
  263. fSuccess = FALSE;
  264. }
  265. if (!fSuccess)
  266. {
  267. TraceTerm(TraceGetHandle(lpTrace));
  268. lpTrace = NULL;
  269. }
  270. // keep track of total modules sharing a task engine handle
  271. //
  272. if (fSuccess && fShare)
  273. {
  274. if (++cShareUsage == 1)
  275. lpTraceShare = lpTrace;
  276. }
  277. return fSuccess ? TraceGetHandle(lpTrace) : NULL;
  278. }
  279. // TraceTerm - shut down trace engine
  280. // <hTrace> (i) handle returned from TraceInit or NULL
  281. // return 0 if success
  282. //
  283. int DLLEXPORT WINAPI TraceTerm(HTRACE hTrace)
  284. {
  285. BOOL fSuccess = TRUE;
  286. LPTRACE lpTrace;
  287. if ((lpTrace = TraceGetPtr(hTrace)) == NULL)
  288. fSuccess = FALSE;
  289. // only shut down trace engine if handle
  290. // is not shared (or is no longer being shared)
  291. //
  292. else if (lpTrace != lpTraceShare || --cShareUsage <= 0)
  293. {
  294. #ifndef _WIN32
  295. int iError;
  296. #endif
  297. // shared trace engine handle no longer valid
  298. //
  299. if (cShareUsage <= 0)
  300. lpTraceShare = NULL;
  301. // Comm functions not available under WIN32
  302. //
  303. #ifndef _WIN32
  304. if (lpTrace->hComm != -1 &&
  305. (iError = CloseComm(lpTrace->hComm)) != 0)
  306. {
  307. TraceError(TEXT("CloseComm error (%d)\n"), iError);
  308. fSuccess = FALSE;
  309. }
  310. else
  311. lpTrace->hComm = -1;
  312. #endif
  313. #ifdef _WIN32
  314. if (lpTrace->hConsole != NULL)
  315. {
  316. FreeConsole();
  317. lpTrace->hConsole = NULL;
  318. }
  319. #endif
  320. #ifdef TRACE_OUTPUTFILE
  321. if (lpTrace->hFile != NULL &&
  322. FileClose(lpTrace->hFile) != 0)
  323. {
  324. TraceError(TEXT("FileClose error\n"));
  325. fSuccess = FALSE;
  326. }
  327. else
  328. lpTrace->hFile = NULL;
  329. #endif
  330. if (lpTrace->lpszTemp != NULL &&
  331. #if 0 // can't call mem functions, because they require trace functions
  332. (lpTrace->lpszTemp = MemFree(NULL, lpTrace->lpszTemp)) != NULL)
  333. #else
  334. #ifdef _WIN32
  335. (!HeapFree(GetProcessHeap(), 0, lpTrace->lpszTemp)))
  336. #else
  337. (GlobalFreePtr(lpTrace->lpszTemp) != 0))
  338. #endif
  339. #endif
  340. fSuccess = FALSE;
  341. lpTrace->wOutputTo = TRACE_OUTPUTNONE;
  342. #if 0 // can't call mem functions, because they require trace functions
  343. if ((lpTrace = MemFree(NULL, lpTrace)) != NULL)
  344. #else
  345. #ifdef _WIN32
  346. if (!HeapFree(GetProcessHeap(), 0, lpTrace->lpszTemp))
  347. #else
  348. if (GlobalFreePtr(lpTrace->lpszTemp) != 0)
  349. #endif
  350. #endif
  351. fSuccess = FALSE;
  352. }
  353. return fSuccess ? 0 : -1;
  354. }
  355. // TraceGetLevel - get current trace level
  356. // <hTrace> (i) handle returned from TraceInit or NULL
  357. // return trace level (-1 if error)
  358. //
  359. int DLLEXPORT WINAPI TraceGetLevel(HTRACE hTrace)
  360. {
  361. BOOL fSuccess = TRUE;
  362. LPTRACE lpTrace;
  363. if ((lpTrace = TraceGetPtr(hTrace)) == NULL)
  364. fSuccess = FALSE;
  365. return fSuccess ? lpTrace->nLevel : -1;
  366. }
  367. // TraceSetLevel - set new trace level (-1 if error)
  368. // <hTrace> (i) handle returned from TraceInit or NULL
  369. // <nLevel> (i) new trace level {TRACE_MINLEVEL...TRACE_MAXLEVEL}
  370. // return 0 if success
  371. //
  372. int DLLEXPORT WINAPI TraceSetLevel(HTRACE hTrace, int nLevel)
  373. {
  374. BOOL fSuccess = TRUE;
  375. LPTRACE lpTrace;
  376. if ((lpTrace = TraceGetPtr(hTrace)) == NULL)
  377. fSuccess = FALSE;
  378. else if (nLevel < TRACE_MINLEVEL || nLevel > TRACE_MAXLEVEL)
  379. fSuccess = FALSE;
  380. else
  381. {
  382. TCHAR szLevel[17];
  383. lpTrace->nLevel = nLevel;
  384. // save the level for next time
  385. //
  386. StrItoA(lpTrace->nLevel, szLevel, 10);
  387. WritePrivateProfileString(TRACE_SECTION, TEXT("Level"), szLevel, TRACE_PROFILE);
  388. // display new trace level whenever it changes
  389. //
  390. TracePrintf_1(hTrace, 1, TEXT("TraceLevel=%d\n"),
  391. (int) lpTrace->nLevel);
  392. }
  393. return fSuccess ? 0 : -1;
  394. }
  395. // TraceOutput - output debug string
  396. // <hTrace> (i) handle returned from TraceInit or NULL
  397. // <nLevel> (i) output only if current trace level is >= nLevel
  398. // <lpszText> (i) string to output
  399. // return 0 if success
  400. //
  401. int DLLEXPORT WINAPI TraceOutput(HTRACE hTrace, int nLevel, LPCTSTR lpszText)
  402. {
  403. BOOL fSuccess = TRUE;
  404. LPTRACE lpTrace;
  405. if ((lpTrace = TraceGetPtr(hTrace)) == NULL)
  406. fSuccess = FALSE;
  407. else if (lpszText == NULL)
  408. fSuccess = FALSE;
  409. else if (nLevel > 0 && nLevel <= lpTrace->nLevel)
  410. {
  411. switch (lpTrace->wOutputTo)
  412. {
  413. case TRACE_OUTPUTNONE:
  414. break;
  415. case TRACE_OUTPUTDEBUGSTRING:
  416. OutputDebugString(lpszText);
  417. break;
  418. #ifdef _WIN32
  419. case TRACE_OUTPUTCONSOLE:
  420. if (lpTrace->hConsole != NULL)
  421. {
  422. DWORD dwBytes;
  423. WriteFile(lpTrace->hConsole, lpszText, StrLen(lpszText), &dwBytes, NULL);
  424. }
  425. break;
  426. #endif
  427. case TRACE_OUTPUTCOMM:
  428. // Comm functions not available under WIN32
  429. //
  430. #ifdef _WIN32
  431. OutputDebugString(lpszText);
  432. #else
  433. if (lpTrace->hComm != -1)
  434. {
  435. LPCTSTR lpsz;
  436. TCHAR chReturn = '\r';
  437. for (lpsz = lpszText; *lpsz != '\0'; lpsz = StrNextChr(lpsz))
  438. {
  439. if ((*lpsz == '\n' &&
  440. WriteComm(lpTrace->hComm, &chReturn, 1) < 0) ||
  441. WriteComm(lpTrace->hComm, lpsz, 1) <= 0)
  442. {
  443. COMSTAT comstat;
  444. GetCommError(lpTrace->hComm, &comstat);
  445. TraceError(TEXT("WriteComm error (%u, %u, %u) %s\n"),
  446. (UINT) comstat.status,
  447. (UINT) comstat.cbInQue,
  448. (UINT) comstat.cbOutQue,
  449. (LPTSTR) lpszText);
  450. fSuccess = FALSE;
  451. break;
  452. }
  453. }
  454. }
  455. #endif
  456. break;
  457. #ifdef TRACE_OUTPUTFILE
  458. case TRACE_OUTPUTFILE:
  459. if (lpTrace->hFile != NULL)
  460. {
  461. LPCTSTR lpsz;
  462. TCHAR chReturn = '\r';
  463. for (lpsz = lpszText; *lpsz != '\0'; lpsz = StrNextChr(lpsz))
  464. {
  465. if ((*lpsz == '\n' &&
  466. FileWrite(lpTrace->hFile, &chReturn, 1) == -1) ||
  467. FileWrite(lpTrace->hFile, lpsz, 1) == -1)
  468. {
  469. TraceError(TEXT("FileWrite error: %s\n"),
  470. (LPTSTR) lpszText);
  471. fSuccess = FALSE;
  472. break;
  473. }
  474. }
  475. }
  476. break;
  477. #endif
  478. default:
  479. break;
  480. }
  481. }
  482. return fSuccess ? 0 : -1;
  483. }
  484. // TracePrintf - output formatted debug string
  485. // <hTrace> (i) handle returned from TraceInit or NULL
  486. // <nLevel> (i) output only if current trace level is >= nLevel
  487. // <lpszFormat,...> (i) format string and arguments to output
  488. // return 0 if success
  489. //
  490. int DLLEXPORT FAR CDECL TracePrintf(HTRACE hTrace, int nLevel, LPCTSTR lpszFormat, ...)
  491. {
  492. BOOL fSuccess = TRUE;
  493. LPTRACE lpTrace;
  494. if ((lpTrace = TraceGetPtr(hTrace)) == NULL)
  495. fSuccess = FALSE;
  496. else if (nLevel <= lpTrace->nLevel)
  497. {
  498. va_list args;
  499. va_start(args, lpszFormat);
  500. wvsprintf(lpTrace->lpszTemp, lpszFormat, args);
  501. va_end(args);
  502. if (TraceOutput(hTrace, nLevel, lpTrace->lpszTemp) != 0)
  503. fSuccess = FALSE;
  504. }
  505. return fSuccess ? 0 : -1;
  506. }
  507. ////
  508. // private functions
  509. ////
  510. // TraceGetPtr - convert trace handle to trace pointer
  511. // <hTrace> (i) handle returned from TraceInit or NULL
  512. // return trace pointer (NULL if error)
  513. //
  514. static LPTRACE TraceGetPtr(HTRACE hTrace)
  515. {
  516. BOOL fSuccess = TRUE;
  517. LPTRACE lpTrace;
  518. // use shared trace handle if no other supplied
  519. //
  520. if (hTrace == NULL && lpTraceShare != NULL)
  521. lpTrace = lpTraceShare;
  522. // create shared trace handle if no other supplied
  523. //
  524. else if (hTrace == NULL && lpTraceShare == NULL &&
  525. (hTrace = TraceInit(TRACE_VERSION, SysGetTaskInstance(NULL))) == NULL)
  526. fSuccess = FALSE;
  527. else if ((lpTrace = (LPTRACE) hTrace) == NULL)
  528. fSuccess = FALSE;
  529. // note: check for good pointer made only if not using lpTraceShare
  530. //
  531. else if (lpTrace != lpTraceShare &&
  532. IsBadWritePtr(lpTrace, sizeof(TRACE)))
  533. fSuccess = FALSE;
  534. #ifdef CHECKTASK
  535. // make sure current task owns the trace handle
  536. // except when shared trace handle is used
  537. //
  538. if (fSuccess && lpTrace != lpTraceShare &&
  539. lpTrace->hTask != GetCurrentTask())
  540. fSuccess = FALSE;
  541. #endif
  542. return fSuccess ? lpTrace : NULL;
  543. }
  544. // TraceGetHandle - convert trace pointer to trace handle
  545. // <lpTrace> (i) pointer to TRACE struct
  546. // return trace handle (NULL if error)
  547. //
  548. static HTRACE TraceGetHandle(LPTRACE lpTrace)
  549. {
  550. BOOL fSuccess = TRUE;
  551. HTRACE hTrace;
  552. if ((hTrace = (HTRACE) lpTrace) == NULL)
  553. fSuccess = FALSE;
  554. return fSuccess ? hTrace : NULL;
  555. }
  556. // TraceError - display formatted trace error string
  557. // <lpszFormat...> (i) format string and arguments to output
  558. // return 0 if success
  559. //
  560. static int TraceError(LPCTSTR lpszFormat, ...)
  561. {
  562. BOOL fSuccess = TRUE;
  563. va_list args;
  564. TCHAR lpszTemp[256];
  565. va_start(args, lpszFormat);
  566. wvsprintf(lpszTemp, lpszFormat, args);
  567. va_end(args);
  568. OutputDebugString(lpszTemp);
  569. return fSuccess ? 0 : -1;
  570. }
  571. // TraceGetProfile - get trace ini file name
  572. // return pointer to file name
  573. //
  574. static LPTSTR TraceGetProfile(void)
  575. {
  576. return TEXT("trace.ini");
  577. }
  578. #endif // #ifndef NOTRACE