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.

865 lines
18 KiB

  1. /* dbg.cpp */
  2. #include "precomp.h"
  3. #include <cstring.hpp>
  4. #include <regentry.h>
  5. #include <confreg.h>
  6. #include <confdbg.h>
  7. #ifdef NM_DEBUG /* Almost the whole file */
  8. // Special Debugbreak macro
  9. #if defined (_M_IX86)
  10. #define _DbgBreak() __asm { int 3 }
  11. #else
  12. #define _DbgBreak() DebugBreak()
  13. #endif
  14. // Special Mutex Macros
  15. #define ACQMUTEX(hMutex) WaitForSingleObject(hMutex, INFINITE)
  16. #define RELMUTEX(hMutex) ReleaseMutex(hMutex)
  17. // Constant for GlobalAddAtom
  18. const int CCHMAX_ATOM = 255;
  19. // Local Variables
  20. static PNMDBG _gpDbg = NULL; // Shared data in mmf after zone info
  21. static HANDLE _ghMutexFile = NULL; // Mutex for writing to file
  22. static PZONEINFO _gprgZoneInfo = NULL; // the address in which the zone is mapped,points to an array of zones
  23. static HANDLE _ghDbgZoneMap = NULL; // the handle of the memory mapped file for zones
  24. static HANDLE _ghDbgZoneMutex = NULL; // Mutex for accessing Zone information
  25. static long _gLockCount = 0;
  26. VOID DbgCurrentTime(PCHAR psz);
  27. /* _ D B G P R I N T F */
  28. /*-------------------------------------------------------------------------
  29. %%Function: _DbgPrintf
  30. The main, low level, debug output routine.
  31. -------------------------------------------------------------------------*/
  32. static VOID WINAPI _DbgPrintf(LPCSTR pszFile, PCSTR pszPrefix, PCSTR pszFormat, va_list ap)
  33. {
  34. CHAR szOutput[1024];
  35. PCHAR pszOutput = szOutput;
  36. UINT cch;
  37. if (NULL == _gprgZoneInfo)
  38. return;
  39. if (DBG_FMTTIME_NONE != _gpDbg->uShowTime)
  40. {
  41. DbgCurrentTime(pszOutput);
  42. pszOutput += lstrlenA(pszOutput);
  43. }
  44. if (_gpDbg->fShowThreadId)
  45. {
  46. wsprintfA(pszOutput, "[%04X] ", GetCurrentThreadId());
  47. pszOutput += lstrlenA(pszOutput);
  48. }
  49. wvsprintfA(pszOutput, pszFormat, ap);
  50. // Append carriage return, if necessary
  51. // WARNING: This code is not DBCS-safe.
  52. cch = lstrlenA(szOutput);
  53. if (szOutput[cch-1] == '\n')
  54. {
  55. if (szOutput[cch-2] != '\r')
  56. {
  57. lstrcpyA(&szOutput[cch-1], "\r\n");
  58. cch++;
  59. }
  60. }
  61. else
  62. {
  63. lstrcpyA(&szOutput[cch], "\r\n");
  64. cch += 2;
  65. }
  66. // Output to debug handler
  67. if (_gpDbg->fOutputDebugString)
  68. {
  69. OutputDebugStringA(szOutput);
  70. }
  71. // Output to File
  72. if (_gpDbg->fFileOutput || (NULL != pszFile))
  73. {
  74. HANDLE hFile;
  75. DWORD dw;
  76. // Lock access to file
  77. ACQMUTEX(_ghMutexFile);
  78. if (NULL == pszFile)
  79. pszFile = _gpDbg->szFile;
  80. // open a log file for appending. create if does not exist
  81. hFile = CreateFileA(pszFile, GENERIC_WRITE, 0, NULL,
  82. OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  83. if (hFile != INVALID_HANDLE_VALUE)
  84. {
  85. // seek to end of file
  86. dw = SetFilePointer(hFile, 0, NULL, FILE_END);
  87. #ifdef TEST /* Test/Retail version truncates at 40K */
  88. if (dw > 0x040000)
  89. {
  90. CloseHandle(hFile);
  91. hFile = CreateFileA(pszFile, GENERIC_WRITE, 0, NULL,
  92. TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  93. }
  94. if (INVALID_HANDLE_VALUE != hFile)
  95. #endif
  96. {
  97. WriteFile(hFile, szOutput, lstrlenA(szOutput), &dw, NULL);
  98. CloseHandle(hFile);
  99. }
  100. }
  101. // Unlock access to file
  102. RELMUTEX(_ghMutexFile);
  103. }
  104. // Output to viewer. This is at the end of the function because
  105. // we potentially truncate szOutput.
  106. if ((_gpDbg->fWinOutput) && (NULL != _gpDbg->hwndCtrl))
  107. {
  108. // Make sure that the string doesn't exceed the maximum atom size.
  109. // WARNING: This code is not DBCS-safe.
  110. static const CHAR szTruncatedSuffix[] = "...\r\n";
  111. static const int cchTruncatedSuffix = ARRAY_ELEMENTS(szTruncatedSuffix) - 1;
  112. if (CCHMAX_ATOM < cch)
  113. {
  114. lstrcpyA(&szOutput[CCHMAX_ATOM - cchTruncatedSuffix], szTruncatedSuffix);
  115. }
  116. ATOM aDbgAtom = GlobalAddAtomA(szOutput);
  117. if (aDbgAtom)
  118. {
  119. if (!PostMessage(_gpDbg->hwndCtrl, _gpDbg->msgDisplay, (WPARAM)aDbgAtom, 0L))
  120. {
  121. // Unable to post Message, so free the atom
  122. GlobalDeleteAtom(aDbgAtom);
  123. }
  124. }
  125. }
  126. }
  127. PSTR WINAPI DbgZPrintf(HDBGZONE hZone, UINT iZone, PSTR pszFormat,...)
  128. {
  129. CHAR sz[MAXSIZE_OF_MODULENAME+MAXSIZE_OF_ZONENAME+1];
  130. PCHAR psz;
  131. va_list v1;
  132. va_start(v1, pszFormat);
  133. if ((NULL != hZone) && (iZone < MAXNUM_OF_ZONES))
  134. {
  135. wsprintfA(sz, "%hs:%hs", ((PZONEINFO) hZone)->pszModule, ((PZONEINFO) hZone)->szZoneNames[iZone]);
  136. psz = sz;
  137. }
  138. else
  139. {
  140. psz = NULL;
  141. }
  142. if ((NULL != hZone) && ('\0' != ((PZONEINFO) hZone)->szFile[0]))
  143. {
  144. // Use the private module output filename, if specified
  145. _DbgPrintf(((PZONEINFO) hZone)->szFile, psz, pszFormat, v1);
  146. }
  147. else
  148. {
  149. _DbgPrintf(NULL, psz, pszFormat, v1);
  150. }
  151. va_end(v1);
  152. return pszFormat;
  153. }
  154. PSTR WINAPI DbgZVPrintf(HDBGZONE hZone, UINT iZone, PSTR pszFormat, va_list ap)
  155. {
  156. CHAR sz[MAXSIZE_OF_MODULENAME+MAXSIZE_OF_ZONENAME+1];
  157. PCHAR psz;
  158. if ((NULL != hZone) && (iZone < MAXNUM_OF_ZONES))
  159. {
  160. wsprintfA(sz, "%hs:%hs", ((PZONEINFO) hZone)->pszModule, ((PZONEINFO) hZone)->szZoneNames[iZone]);
  161. psz = sz;
  162. }
  163. else
  164. {
  165. psz = NULL;
  166. }
  167. if ((NULL != hZone) && ('\0' != ((PZONEINFO) hZone)->szFile[0]))
  168. {
  169. // Use the private module output filename, if specified
  170. _DbgPrintf(((PZONEINFO) hZone)->szFile, psz, pszFormat, ap);
  171. }
  172. else
  173. {
  174. _DbgPrintf(NULL, psz, pszFormat, ap);
  175. }
  176. return pszFormat;
  177. }
  178. VOID WINAPI DbgPrintf(PCSTR pszPrefix, PCSTR pszFormat, va_list ap)
  179. {
  180. _DbgPrintf(NULL, pszPrefix, pszFormat, ap);
  181. }
  182. VOID DbgInitEx(HDBGZONE * phDbgZone, PCHAR * psz, UINT cZones, long ulZoneDefault)
  183. {
  184. UINT i;
  185. HDBGZONE hDbgZone;
  186. DBGZONEINFO dbgZoneParm;
  187. //DbgMsg("Module %s (%d zones)", *psz, cZones);
  188. InterlockedIncrement( &_gLockCount );
  189. InitDbgZone();
  190. if (cZones > MAXNUM_OF_ZONES)
  191. cZones = MAXNUM_OF_ZONES;
  192. ZeroMemory(&dbgZoneParm, sizeof(dbgZoneParm));
  193. // First string is the module name
  194. lstrcpynA(dbgZoneParm.pszModule, *psz, CCHMAX(dbgZoneParm.pszModule));
  195. // Copy the zone names
  196. for (i = 0; i < cZones; i++)
  197. {
  198. lstrcpynA(dbgZoneParm.szZoneNames[i], psz[1+i], CCHMAX(dbgZoneParm.szZoneNames[0]));
  199. }
  200. // Get the detault zone settings
  201. dbgZoneParm.ulZoneMask = ulZoneDefault;
  202. hDbgZone = NmDbgCreateZone(dbgZoneParm.pszModule);
  203. if (NULL == hDbgZone)
  204. {
  205. OutputDebugStringA("DbgInit: Failed to create zones!\r\n");
  206. return;
  207. }
  208. NmDbgSetZone(hDbgZone, &dbgZoneParm);
  209. *phDbgZone = hDbgZone;
  210. }
  211. VOID DbgDeInit(HDBGZONE * phDbgZone)
  212. {
  213. if (NULL == phDbgZone)
  214. return;
  215. if (NULL == *phDbgZone)
  216. return;
  217. //DbgMsg("Freeing Zone [%s]",((PZONEINFO)(*phDbgZone))->pszModule);
  218. NmDbgDeleteZone("", *phDbgZone);
  219. *phDbgZone = NULL;
  220. if( 0 == InterlockedDecrement( &_gLockCount ) )
  221. {
  222. UnMapDebugZoneArea();
  223. if( _ghMutexFile )
  224. {
  225. CloseHandle( _ghMutexFile );
  226. _ghMutexFile = NULL;
  227. }
  228. if( _ghDbgZoneMutex )
  229. {
  230. CloseHandle( _ghDbgZoneMutex );
  231. _ghDbgZoneMutex = NULL;
  232. }
  233. }
  234. }
  235. //////////////////////////////////////////////////////////////////////////////////
  236. // from dbgzone.cpp
  237. /***************************************************************************
  238. Name : NmDbgCreateZones
  239. Purpose : A module calls this to allocate/initialize the zone area for debugging
  240. purposes.
  241. Parameters: pszName - the name of the module
  242. Returns :
  243. Comment :
  244. ***************************************************************************/
  245. HDBGZONE WINAPI NmDbgCreateZone(LPSTR pszName)
  246. {
  247. PZONEINFO pZoneInfo=NULL;
  248. if (!(pZoneInfo = FindZoneForModule(pszName)))
  249. pZoneInfo = AllocZoneForModule(pszName);
  250. return ((HDBGZONE)pZoneInfo);
  251. }
  252. /***************************************************************************
  253. Name : NmDbgDeleteZones
  254. Purpose :
  255. Parameters:
  256. Returns :
  257. Comment :
  258. ***************************************************************************/
  259. void WINAPI NmDbgDeleteZone(LPSTR pszName, HDBGZONE hDbgZone)
  260. {
  261. //decrement reference count
  262. PZONEINFO pZoneInfo = (PZONEINFO)hDbgZone;
  263. ASSERT( _ghDbgZoneMutex );
  264. ACQMUTEX(_ghDbgZoneMutex);
  265. if (pZoneInfo)
  266. {
  267. pZoneInfo->ulRefCnt--;
  268. if (pZoneInfo->ulRefCnt == 0)
  269. {
  270. pZoneInfo->bInUse = FALSE;
  271. pZoneInfo->ulSignature = 0;
  272. }
  273. }
  274. RELMUTEX(_ghDbgZoneMutex);
  275. }
  276. /***************************************************************************
  277. Name : NmDbgSetZones
  278. Purpose :
  279. Parameters:
  280. Returns :
  281. Comment :
  282. ***************************************************************************/
  283. BOOL WINAPI NmDbgSetZone(HDBGZONE hDbgZone, PDBGZONEINFO pZoneParam)
  284. {
  285. PZONEINFO pZoneInfo = (PZONEINFO)hDbgZone;
  286. if (!pZoneInfo)
  287. return FALSE;
  288. if (lstrcmpA(pZoneInfo->pszModule,pZoneParam->pszModule))
  289. return FALSE;
  290. pZoneInfo->ulZoneMask = pZoneParam->ulZoneMask;
  291. CopyMemory(pZoneInfo->szZoneNames, pZoneParam->szZoneNames,
  292. (sizeof(CHAR) * MAXNUM_OF_ZONES * MAXSIZE_OF_ZONENAME));
  293. return(TRUE);
  294. }
  295. /***************************************************************************
  296. Name : NmDbgGetZoneParams
  297. Purpose :
  298. Parameters:
  299. Returns :
  300. Comment :
  301. ***************************************************************************/
  302. BOOL WINAPI NmDbgGetAllZoneParams(PDBGZONEINFO *plpZoneParam,LPUINT puCnt)
  303. {
  304. UINT ui;
  305. PZONEINFO pCurZone;
  306. if ((NULL == plpZoneParam) || (NULL == puCnt))
  307. return FALSE;
  308. ACQMUTEX(_ghDbgZoneMutex);
  309. *puCnt = 0;
  310. for (pCurZone = _gprgZoneInfo, ui=0;
  311. ui<MAXNUM_OF_MODULES && pCurZone!=NULL;
  312. ui++,pCurZone++)
  313. {
  314. if ((pCurZone->bInUse) && (pCurZone->ulSignature == ZONEINFO_SIGN))
  315. {
  316. (*puCnt)++;
  317. }
  318. }
  319. *plpZoneParam = _gprgZoneInfo;
  320. RELMUTEX(_ghDbgZoneMutex);
  321. return TRUE;
  322. }
  323. BOOL WINAPI NmDbgFreeZoneParams(PDBGZONEINFO pZoneParam)
  324. {
  325. return TRUE;
  326. }
  327. PZONEINFO FindZoneForModule(LPCSTR pszModule)
  328. {
  329. int i;
  330. PZONEINFO pCurZone;
  331. for (pCurZone = _gprgZoneInfo,i=0;i<MAXNUM_OF_MODULES && pCurZone!=NULL;i++,pCurZone++)
  332. {
  333. if ((pCurZone->bInUse) && (pCurZone->ulSignature == ZONEINFO_SIGN)
  334. && (!lstrcmpA(pCurZone->pszModule,pszModule)))
  335. {
  336. ACQMUTEX(_ghDbgZoneMutex);
  337. pCurZone->ulRefCnt++;
  338. RELMUTEX(_ghDbgZoneMutex);
  339. return pCurZone;
  340. }
  341. }
  342. return NULL;
  343. }
  344. /***************************************************************************
  345. Name : AllocZoneForModule
  346. Purpose : Allocates the
  347. Parameters:
  348. Returns :
  349. Comment :
  350. ***************************************************************************/
  351. PZONEINFO AllocZoneForModule(LPCSTR pszModule)
  352. {
  353. int i;
  354. PZONEINFO pCurZone;
  355. PZONEINFO pZoneForMod=NULL;
  356. ACQMUTEX(_ghDbgZoneMutex);
  357. for (pCurZone = _gprgZoneInfo,i=0;
  358. (i<MAXNUM_OF_MODULES && pCurZone!=NULL);
  359. i++,pCurZone++)
  360. {
  361. if (!(pCurZone->bInUse))
  362. {
  363. pCurZone->bInUse = TRUE;
  364. pCurZone->ulSignature = ZONEINFO_SIGN;
  365. pCurZone->ulRefCnt = 1;
  366. lstrcpyA(pCurZone->pszModule, pszModule);
  367. pZoneForMod = pCurZone;
  368. break;
  369. }
  370. }
  371. RELMUTEX(_ghDbgZoneMutex);
  372. return(pZoneForMod);
  373. }
  374. VOID SetDbgFlags(void)
  375. {
  376. PTSTR psz;
  377. _gpDbg->fOutputDebugString = TRUE;
  378. _gpDbg->fWinOutput = FALSE;
  379. _gpDbg->fFileOutput = FALSE;
  380. _gpDbg->uShowTime = DBG_FMTTIME_NONE;
  381. _gpDbg->fShowThreadId = FALSE;
  382. _gpDbg->fShowModule = FALSE;
  383. {
  384. UINT cchFile;
  385. cchFile = GetWindowsDirectoryA(_gpDbg->szFile, CCHMAX(_gpDbg->szFile));
  386. _gpDbg->szFile[cchFile++] = '\\';
  387. lstrcpyA(_gpDbg->szFile + cchFile, CUSTRING(TEXT("rddbg.txt")));
  388. }
  389. }
  390. VOID InitZoneMmf(PZONEINFO prgZoneInfo)
  391. {
  392. ZeroMemory(prgZoneInfo, CBMMFDBG);
  393. SetDbgFlags();
  394. }
  395. PZONEINFO MapDebugZoneArea(void)
  396. {
  397. PZONEINFO prgZoneInfo;
  398. BOOL fCreated;
  399. SECURITY_DESCRIPTOR sd;
  400. SECURITY_ATTRIBUTES sa;
  401. // Obtain a true NULL security descriptor (so if running as a service, user processes can access it)
  402. InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
  403. SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); // NULL DACL = wide open
  404. FillMemory(&sa, sizeof(sa), 0);
  405. sa.nLength = sizeof(sa);
  406. sa.lpSecurityDescriptor = &sd;
  407. //create a memory mapped object that is backed by paging file
  408. _ghDbgZoneMap = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE,
  409. 0, CBMMFDBG, SZ_DBG_MAPPED_ZONE);
  410. if (NULL == _ghDbgZoneMap)
  411. return NULL;
  412. fCreated = (0 == GetLastError());
  413. prgZoneInfo = (PZONEINFO) MapViewOfFile(_ghDbgZoneMap, FILE_MAP_READ|FILE_MAP_WRITE, 0,0,0);
  414. if (NULL != prgZoneInfo)
  415. {
  416. // Grab pointer to shared data area
  417. _gpDbg = (PNMDBG) (((PBYTE) prgZoneInfo) + (MAXNUM_OF_MODULES * sizeof(ZONEINFO)));
  418. if (fCreated)
  419. InitZoneMmf(prgZoneInfo);
  420. }
  421. return prgZoneInfo;
  422. }
  423. VOID UnMapDebugZoneArea(void)
  424. {
  425. if (_gprgZoneInfo)
  426. {
  427. UnmapViewOfFile(_gprgZoneInfo);
  428. _gprgZoneInfo = NULL;
  429. }
  430. if (_ghDbgZoneMap)
  431. {
  432. CloseHandle(_ghDbgZoneMap);
  433. _ghDbgZoneMap = NULL;
  434. }
  435. }
  436. VOID InitDbgZone(void)
  437. {
  438. if (NULL != _gprgZoneInfo)
  439. return; // already initialized
  440. _gprgZoneInfo = MapDebugZoneArea();
  441. // Create log file data
  442. SECURITY_DESCRIPTOR sd;
  443. SECURITY_ATTRIBUTES sa;
  444. // Obtain a true NULL security descriptor (so if running as a service, user processes can access it)
  445. InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
  446. SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); // NULL DACL = wide open
  447. FillMemory(&sa, sizeof(sa), 0);
  448. sa.nLength = sizeof(sa);
  449. sa.lpSecurityDescriptor = &sd;
  450. _ghMutexFile = CreateMutex(&sa, FALSE, SZ_DBG_FILE_MUTEX);
  451. _ghDbgZoneMutex = CreateMutex(&sa, FALSE, SZ_DBG_ZONE_MUTEX);
  452. if (_gpDbg->fFileOutput)
  453. {
  454. HANDLE hFile;
  455. DWORD dw;
  456. CHAR sz[MAX_PATH];
  457. SYSTEMTIME systime;
  458. hFile = CreateFileA(_gpDbg->szFile,
  459. GENERIC_WRITE | GENERIC_WRITE, 0, &sa,
  460. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  461. if (INVALID_HANDLE_VALUE == hFile)
  462. {
  463. _gpDbg->fFileOutput = FALSE;
  464. return;
  465. }
  466. GetLocalTime(&systime);
  467. wsprintfA(sz,
  468. "\r\n======== TRACE Started: %hu/%hu/%hu (%hu:%hu)\r\n",
  469. systime.wMonth, systime.wDay, systime.wYear, systime.wHour, systime.wMinute);
  470. SetFilePointer(hFile, 0, NULL, FILE_END);
  471. WriteFile(hFile, sz, lstrlenA(sz), &dw, NULL);
  472. CloseHandle(hFile);
  473. }
  474. }
  475. ///////////////////////////////////////
  476. // Routines for controlling debug output
  477. BOOL WINAPI NmDbgRegisterCtl(HWND hwnd, UINT uDisplayMsg)
  478. {
  479. if ((NULL == _gpDbg) || (NULL != _gpDbg->hwndCtrl))
  480. return FALSE;
  481. _gpDbg->msgDisplay = uDisplayMsg;
  482. _gpDbg->hwndCtrl = hwnd;
  483. return TRUE;
  484. }
  485. BOOL WINAPI NmDbgDeregisterCtl(HWND hwnd)
  486. {
  487. if ((NULL == _gpDbg) || (hwnd != _gpDbg->hwndCtrl))
  488. return FALSE;
  489. _gpDbg->hwndCtrl = NULL;
  490. _gpDbg->msgDisplay = 0;
  491. return TRUE;
  492. }
  493. BOOL WINAPI NmDbgSetLoggingOptions(HWND hwnd, UINT uOptions)
  494. {
  495. return FALSE;
  496. }
  497. PNMDBG WINAPI GetPNmDbg(void)
  498. {
  499. return _gpDbg;
  500. }
  501. VOID WINAPI NmDbgSetZoneFileName(HDBGZONE hZone, LPCSTR pszFile)
  502. {
  503. PSTR pszZoneFile;
  504. if (IsBadWritePtr((PVOID) hZone, sizeof(ZONEINFO)))
  505. return;
  506. if (((PZONEINFO) hZone)->ulSignature != ZONEINFO_SIGN)
  507. return;
  508. pszZoneFile = &(((PZONEINFO) hZone)->szFile[0]);
  509. if (NULL == pszFile)
  510. {
  511. *pszZoneFile = '\0';
  512. }
  513. else
  514. {
  515. lstrcpynA(pszZoneFile, pszFile, CCHMAX(((PZONEINFO) hZone)->szFile));
  516. }
  517. }
  518. /* D B G C U R R E N T T I M E */
  519. /*-------------------------------------------------------------------------
  520. %%Function: DbgCurrentTime
  521. Format the current time
  522. -------------------------------------------------------------------------*/
  523. VOID DbgCurrentTime(PCHAR psz)
  524. {
  525. if (DBG_FMTTIME_TICK == _gpDbg->uShowTime)
  526. {
  527. wsprintfA(psz, "[%04X] ", GetTickCount());
  528. }
  529. else
  530. {
  531. SYSTEMTIME sysTime;
  532. GetLocalTime(&sysTime);
  533. switch (_gpDbg->uShowTime)
  534. {
  535. default:
  536. case DBG_FMTTIME_FULL:
  537. wsprintfA(psz, "[%04d/%02d/%02d %02d:%02d:%02d.%03d] ",
  538. sysTime.wYear, sysTime.wMonth, sysTime.wDay,
  539. sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds);
  540. break;
  541. case DBG_FMTTIME_DAY:
  542. wsprintfA(psz, "[%02d:%02d:%02d.%03d] ",
  543. sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds);
  544. break;
  545. }
  546. }
  547. }
  548. /* P S Z P R I N T F */
  549. /*-------------------------------------------------------------------------
  550. %%Function: PszPrintf
  551. Utility function to wsprintf a string for debug.
  552. -------------------------------------------------------------------------*/
  553. PSTR PszPrintf(PCSTR pszFormat,...)
  554. {
  555. PSTR psz = (PSTR) LocalAlloc(LMEM_FIXED, MAX_PATH);
  556. if (NULL != psz)
  557. {
  558. va_list v1;
  559. va_start(v1, pszFormat);
  560. wvsprintfA(psz, pszFormat, v1);
  561. va_end(v1);
  562. }
  563. return psz;
  564. }
  565. /* D E B U G T R A P F N */
  566. /*-------------------------------------------------------------------------
  567. %%Function: DebugTrapFn
  568. -------------------------------------------------------------------------*/
  569. VOID DebugTrapFn(VOID)
  570. {
  571. _DbgBreak();
  572. }
  573. VOID DebugPrintfTraceMem(LPCSTR pszFormat,...)
  574. {
  575. // DO NOTHING
  576. va_list arglist;
  577. va_start(arglist, pszFormat);
  578. va_end(arglist);
  579. }
  580. #endif /* NM_DEBUG - almost the whole file */
  581. /*************************************************************************/
  582. const int RPF_UNKNOWN = 0;
  583. const int RPF_ENABLED = 1;
  584. const int RPF_DISABLED = 2;
  585. static int gRpf = RPF_UNKNOWN;
  586. static TCHAR gszRetailOutputFilename[MAX_PATH]; // retail trace filename
  587. /* F E N A B L E D R E T A I L P R I N T F */
  588. /*-------------------------------------------------------------------------
  589. %%Function: FEnabledRetailPrintf
  590. Return TRUE if retail output is enabled.
  591. -------------------------------------------------------------------------*/
  592. BOOL FEnabledRetailPrintf(VOID)
  593. {
  594. if (RPF_UNKNOWN == gRpf)
  595. {
  596. gRpf = RPF_DISABLED;
  597. if (RPF_ENABLED != gRpf)
  598. {
  599. gRpf = RPF_DISABLED;
  600. }
  601. else
  602. {
  603. lstrcat(gszRetailOutputFilename, TEXT("rdlog.txt"));
  604. }
  605. }
  606. return (RPF_ENABLED == gRpf);
  607. }
  608. /* R E T A I L P R I N T F T R A C E */
  609. /*-------------------------------------------------------------------------
  610. %%Function: RetailPrintfTrace
  611. Print retail information to a file
  612. -------------------------------------------------------------------------*/
  613. VOID WINAPI RetailPrintfTrace(LPCSTR pszFormat,...)
  614. {
  615. HANDLE hFile;
  616. va_list v1;
  617. CHAR szOutput[1024];
  618. if (!FEnabledRetailPrintf())
  619. return; // Retail output is disabled
  620. va_start(v1, pszFormat);
  621. #ifdef DEBUG
  622. // Also use normal output mechanism for debug builds
  623. _DbgPrintf(NULL, "Retail:PrintfTrace", pszFormat, v1);
  624. #endif
  625. wvsprintfA(szOutput, pszFormat, v1);
  626. // Always append the CRLF
  627. ASSERT(lstrlenA(szOutput) < (CCHMAX(szOutput)-2));
  628. lstrcatA(szOutput, "\r\n");
  629. // open a log file for appending. create if does not exist
  630. hFile = CreateFile(gszRetailOutputFilename, GENERIC_WRITE,
  631. 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  632. if (hFile != INVALID_HANDLE_VALUE)
  633. {
  634. // seek to end of file
  635. DWORD dw = SetFilePointer(hFile, 0, NULL, FILE_END);
  636. WriteFile(hFile, szOutput, lstrlenA(szOutput), &dw, NULL);
  637. CloseHandle(hFile);
  638. }
  639. va_end(v1);
  640. }
  641.