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.

2201 lines
109 KiB

  1. /****************************************************************************/
  2. /* ntrcint.c */
  3. /* */
  4. /* Internal tracing functions - Windows NT specific */
  5. /* */
  6. /* Copyright(C) Microsoft Corporation 1997-1998 */
  7. /****************************************************************************/
  8. #include <adcg.h>
  9. /****************************************************************************/
  10. /* Define TRC_FILE and TRC_GROUP. */
  11. /****************************************************************************/
  12. #undef TRC_FILE
  13. #define TRC_FILE "ntrcint"
  14. #define TRC_GROUP TRC_GROUP_TRACE
  15. /****************************************************************************/
  16. /* Trace specific includes. */
  17. /****************************************************************************/
  18. #include <atrcapi.h>
  19. #include <atrcint.h>
  20. #ifndef OS_WINCE
  21. #include <imagehlp.h>
  22. #endif
  23. #include <ndcgver.h>
  24. /****************************************************************************/
  25. /* */
  26. /* DATA */
  27. /* */
  28. /****************************************************************************/
  29. #define DC_INCLUDE_DATA
  30. #include <atrcdata.c>
  31. #undef DC_INCLUDE_DATA
  32. /****************************************************************************/
  33. /* */
  34. /* FUNCTIONS */
  35. /* */
  36. /****************************************************************************/
  37. /****************************************************************************/
  38. /* FUNCTION: DllMain(...) */
  39. /* */
  40. /* DESCRIPTION: */
  41. /* ============ */
  42. /* Entry/exit point for the trace DLL. This function is called whenever a */
  43. /* process or thread attaches or detaches from this DLL. */
  44. /* */
  45. /* PARAMETERS: */
  46. /* =========== */
  47. /* hModule : a module handle. */
  48. /* reasonForCall : an enumerated type that indicates which of the four */
  49. /* reasons the DLLMain function is being called: process */
  50. /* attach, thread attach, thread detach or process */
  51. /* detach. */
  52. /* lpReserved : unused. */
  53. /* */
  54. /* RETURNS: */
  55. /* ======== */
  56. /* TRUE if the attachment succeeds and FALSE otherwise. */
  57. /* */
  58. /****************************************************************************/
  59. #ifndef STATICONLY
  60. int APIENTRY DllMain(HANDLE hModule,
  61. DWORD reasonForCall,
  62. LPVOID lpReserved)
  63. {
  64. DCBOOL retValue = TRUE;
  65. DCUINT rc = 0;
  66. DC_IGNORE_PARAMETER(lpReserved);
  67. #ifdef OS_WINCE
  68. DC_IGNORE_PARAMETER(hModule);
  69. #endif // OS_WINCE
  70. /************************************************************************/
  71. /* Determine the reason for the call. Note that anything we do in here */
  72. /* is thread safe as we implicitly have the process critical section. */
  73. /************************************************************************/
  74. switch (reasonForCall)
  75. {
  76. #ifndef OS_WINCE
  77. /********************************************************************/
  78. /* A process is attaching to this DLL. */
  79. /********************************************************************/
  80. case DLL_PROCESS_ATTACH:
  81. {
  82. /****************************************************************/
  83. /* Call the internal function to initialize the trace DLL. */
  84. /* This function sets up the memory mapped shared data, and */
  85. /* opens and initializes the trace files. It may be called */
  86. /* either via a process attach or by the first person to call */
  87. /* the trace DLL. The latter case can only occur if another */
  88. /* DLL performs trace calls in its <DllMain> function and that */
  89. /* DLLs <DllMain> function is called before the trace DLLs */
  90. /* <DllMain> function (i.e. this function!). */
  91. /****************************************************************/
  92. rc = TRC_Initialize(TRUE);
  93. if (0 != rc)
  94. {
  95. retValue = FALSE;
  96. DC_QUIT;
  97. }
  98. /****************************************************************/
  99. /* Save the module handle. */
  100. /****************************************************************/
  101. trchModule = hModule;
  102. /****************************************************************/
  103. /* Get the trace DLL module file name. We use this later when */
  104. /* we get a stack trace. */
  105. /****************************************************************/
  106. if ( TRCGetModuleFileName(
  107. trcpSharedData->trcpModuleFileName,
  108. SIZE_TCHARS(trcpSharedData->trcpModuleFileName)) !=
  109. DC_RC_OK )
  110. {
  111. retValue = FALSE;
  112. DC_QUIT;
  113. }
  114. /****************************************************************/
  115. /* A process is attaching so trace this fact out. */
  116. /****************************************************************/
  117. TRCInternalTrace(TRC_PROCESS_ATTACH_NOTIFY);
  118. }
  119. break;
  120. /********************************************************************/
  121. /* A process is detaching from this DLL. */
  122. /********************************************************************/
  123. case DLL_PROCESS_DETACH:
  124. {
  125. /****************************************************************/
  126. /* Write out the process detach trace line. */
  127. /****************************************************************/
  128. TRCInternalTrace(TRC_PROCESS_DETACH_NOTIFY);
  129. /****************************************************************/
  130. /* Call the trace DLL termination function. This will close */
  131. /* all files, free the shared data and then close the mutex */
  132. /* handle. */
  133. /****************************************************************/
  134. TRC_Terminate(TRUE);
  135. }
  136. break;
  137. /********************************************************************/
  138. /* A thread is attaching to this DLL. */
  139. /********************************************************************/
  140. case DLL_THREAD_ATTACH:
  141. {
  142. /****************************************************************/
  143. /* Write out the thread attach trace line. */
  144. /****************************************************************/
  145. TRCInternalTrace(TRC_THREAD_ATTACH_NOTIFY);
  146. }
  147. break;
  148. /********************************************************************/
  149. /* A thread is detaching from this DLL. */
  150. /********************************************************************/
  151. case DLL_THREAD_DETACH:
  152. {
  153. /****************************************************************/
  154. /* Write out the thread detach trace line. */
  155. /****************************************************************/
  156. TRCInternalTrace(TRC_THREAD_DETACH_NOTIFY);
  157. }
  158. break;
  159. #endif // OS_WINCE
  160. }
  161. /************************************************************************/
  162. /* Now return the appropriate return value. NT currently only checks */
  163. /* the value for the DLL_PROCESS_ATTACH case - if it is false then the */
  164. /* app will fail to initialize. */
  165. /************************************************************************/
  166. DC_EXIT_POINT:
  167. return(retValue);
  168. } /* DllMain */
  169. #endif
  170. /****************************************************************************/
  171. /* FUNCTION: TRCBlankFile(...) */
  172. /* */
  173. /* DESCRIPTION: */
  174. /* ============ */
  175. /* This function fills the specified trace file with spaces. */
  176. /* */
  177. /* PARAMETERS: */
  178. /* =========== */
  179. /* fileNumber : which file to blank. */
  180. /* */
  181. /* RETURNS: */
  182. /* ======== */
  183. /* Nothing. */
  184. /* */
  185. /****************************************************************************/
  186. DCVOID DCINTERNAL TRCBlankFile(DCUINT fileNumber)
  187. {
  188. /************************************************************************/
  189. /* Use DC_MEMSET to fill the file with spaces. */
  190. /************************************************************************/
  191. DC_MEMSET(trcpFiles[fileNumber], '\0', trcpConfig->maxFileSize);
  192. /************************************************************************/
  193. /* Finally flush this change to disk. Setting the second parameter to */
  194. /* zero flushes the whole file to disk. */
  195. /************************************************************************/
  196. FlushViewOfFile(trcpFiles[fileNumber], 0);
  197. return;
  198. } /* TRC_BlankFile */
  199. /****************************************************************************/
  200. /* FUNCTION: TRCCloseSharedData(...) */
  201. /* */
  202. /* DESCRIPTION: */
  203. /* ============ */
  204. /* This function closes the shared data memory mapped file. */
  205. /* */
  206. /* PARAMETERS: */
  207. /* =========== */
  208. /* None. */
  209. /* */
  210. /* RETURNS: */
  211. /* ======== */
  212. /* Nothing. */
  213. /* */
  214. /****************************************************************************/
  215. DCVOID DCINTERNAL TRCCloseSharedData(DCVOID)
  216. {
  217. /************************************************************************/
  218. /* Now we need to unmap our view of the file. */
  219. /************************************************************************/
  220. UnmapViewOfFile(trcpSharedData);
  221. trcpSharedData = NULL;
  222. /************************************************************************/
  223. /* Now close the handle to the file mapping object. */
  224. /************************************************************************/
  225. CloseHandle(trchSharedDataObject);
  226. trchSharedDataObject = NULL;
  227. /************************************************************************/
  228. /* NULL our static pointer to the shared configuration data. */
  229. /************************************************************************/
  230. trcpConfig = NULL;
  231. /************************************************************************/
  232. /* That's it so just return. */
  233. /************************************************************************/
  234. return;
  235. } /* TRCCloseSharedData */
  236. /****************************************************************************/
  237. /* FUNCTION: TRCCloseSingleFile(...) */
  238. /* */
  239. /* DESCRIPTION: */
  240. /* ============ */
  241. /* Closes a single trace memory mapped file. */
  242. /* */
  243. /* PARAMETERS: */
  244. /* =========== */
  245. /* fileNumber : which file to close. */
  246. /* seconds : value to set the seconds time stamp of the file to. */
  247. /* */
  248. /* RETURNS: */
  249. /* ======== */
  250. /* Nothing. */
  251. /* */
  252. /****************************************************************************/
  253. DCVOID DCINTERNAL TRCCloseSingleFile(DCUINT fileNumber, DCUINT seconds)
  254. {
  255. FILETIME fileTime;
  256. SYSTEMTIME systemTime;
  257. DCUINT32 offset;
  258. /************************************************************************/
  259. /* We need to reset the size of this file - we do this by determining */
  260. /* the trace file offset. Make sure that we do this before we unmap */
  261. /* the file. */
  262. /************************************************************************/
  263. offset = TRCDetermineOffset(fileNumber);
  264. /************************************************************************/
  265. /* Unmap the view of the file. */
  266. /************************************************************************/
  267. UnmapViewOfFile(trcpFiles[fileNumber]);
  268. trcpFiles[fileNumber] = NULL;
  269. /************************************************************************/
  270. /* Free up the handle to the file mapping object. */
  271. /************************************************************************/
  272. CloseHandle(trchMappingObjects[fileNumber]);
  273. trchMappingObjects[fileNumber] = NULL;
  274. /************************************************************************/
  275. /* Now set the file pointer to the end of all the trace text and then */
  276. /* set the end of the file to this position. */
  277. /************************************************************************/
  278. SetFilePointer(trchFileObjects[fileNumber],
  279. offset,
  280. NULL,
  281. FILE_BEGIN);
  282. SetEndOfFile(trchFileObjects[fileNumber]);
  283. /************************************************************************/
  284. /* Now we have to do something a little messy - the file time is not */
  285. /* properly updated when the memory mapped file is closed and we rely */
  286. /* on the file time to decide which file to start tracing to at the */
  287. /* start of day. Therefore we need to force the system to update the */
  288. /* file times using SetFileTime (we set the created, modified and */
  289. /* accessed times). On NT4.0 this does not guarantee that the times */
  290. /* are the same - one file had a created time of 16:35:16 and a */
  291. /* modified time of 16:35:18 after a call to SetFileTime! Files only */
  292. /* have a time resolution of two seconds if they are stored on a FAT */
  293. /* partition by NT. */
  294. /************************************************************************/
  295. GetSystemTime(&systemTime);
  296. /************************************************************************/
  297. /* Set the number of seconds of the file. */
  298. /************************************************************************/
  299. systemTime.wSecond = (WORD) seconds;
  300. /************************************************************************/
  301. /* Now convert the system time to a file time and update the file time. */
  302. /************************************************************************/
  303. SystemTimeToFileTime(&systemTime, &fileTime);
  304. SetFileTime(trchFileObjects[fileNumber], &fileTime, &fileTime, &fileTime);
  305. /************************************************************************/
  306. /* Close the file handle. */
  307. /************************************************************************/
  308. CloseHandle(trchFileObjects[fileNumber]);
  309. trchFileObjects[fileNumber] = NULL;
  310. return;
  311. } /* TRCCloseSingleFile */
  312. /****************************************************************************/
  313. /* FUNCTION: TRCDetermineIndicator(...) */
  314. /* */
  315. /* DESCRIPTION: */
  316. /* ============ */
  317. /* This function sets the trace file indicator as follows: */
  318. /* */
  319. /* - No trace files exist : indicator set to 0 */
  320. /* - One trace file exists : indicator set to the existing file (0 or 1) */
  321. /* - Both trace files exist : indicator set to the newer file. */
  322. /* */
  323. /* PARAMETERS: */
  324. /* =========== */
  325. /* None. */
  326. /* */
  327. /* RETURNS: */
  328. /* ======== */
  329. /* Nothing. */
  330. /* */
  331. /****************************************************************************/
  332. DCVOID DCINTERNAL TRCDetermineIndicator(DCVOID)
  333. {
  334. DCINT i;
  335. DCBOOL rc[TRC_NUM_FILES];
  336. DCINT32 tdRC;
  337. FILETIME fileTime[TRC_NUM_FILES];
  338. /************************************************************************/
  339. /* We also need to set up the trace file indicator. By default we use */
  340. /* trace file 0. */
  341. /************************************************************************/
  342. trcpSharedData->trcIndicator = 0;
  343. /************************************************************************/
  344. /* Determine the most recent trace file. Use GetFileTime to get the */
  345. /* date and time of this file. */
  346. /************************************************************************/
  347. for (i = 0; i < TRC_NUM_FILES; i++)
  348. {
  349. rc[i] = TRCGetFileTime(i, &(fileTime[i]));
  350. }
  351. /************************************************************************/
  352. /* Now check to see which file we should return based on the following */
  353. /* options: */
  354. /* */
  355. /* �������������������������������������������Ŀ */
  356. /* � File 0 exists � File 1 exists � return � */
  357. /* �������������������������������������������Ĵ */
  358. /* � No � No � file 0 � */
  359. /* � No � Yes � file 1 � */
  360. /* � Yes � Yes � compare � */
  361. /* � Yes � No � file 0 � */
  362. /* ��������������������������������������������� */
  363. /************************************************************************/
  364. /************************************************************************/
  365. /* If file 1 does not exist then we return file 0 regardless. */
  366. /************************************************************************/
  367. if (FALSE == rc[1])
  368. {
  369. DC_QUIT;
  370. }
  371. /************************************************************************/
  372. /* If file 0 does not exist and file 1 does, then return file 1. */
  373. /************************************************************************/
  374. if ((FALSE == rc[0]) && (TRUE == rc[1]))
  375. {
  376. trcpSharedData->trcIndicator = 1;
  377. DC_QUIT;
  378. }
  379. /************************************************************************/
  380. /* If we have got this far then both trace files exist so we need to */
  381. /* make a decision based on their ages. User the Win32 CompareFileTime */
  382. /* function to do this. */
  383. /************************************************************************/
  384. tdRC = CompareFileTime(&(fileTime[0]), &(fileTime[1]));
  385. /************************************************************************/
  386. /* If the file times are equal or the first file is newer than the */
  387. /* second then select file 0 (i.e. just quit). */
  388. /************************************************************************/
  389. if (tdRC >= 0)
  390. {
  391. DC_QUIT;
  392. }
  393. /************************************************************************/
  394. /* If we get here then file 1 is newer than file 0 so set the indicator */
  395. /* to file 1. */
  396. /************************************************************************/
  397. trcpSharedData->trcIndicator = 1;
  398. DC_EXIT_POINT:
  399. return;
  400. } /* TRCDetermineIndicator */
  401. /****************************************************************************/
  402. /* FUNCTION: TRCDetermineOffset(...) */
  403. /* */
  404. /* DESCRIPTION: */
  405. /* ============ */
  406. /* This function determines the end-of-file offset in the selected trace */
  407. /* file. */
  408. /* */
  409. /* PARAMETERS: */
  410. /* =========== */
  411. /* fileNum : the number of the file to determine the offset for. */
  412. /* */
  413. /* RETURNS: */
  414. /* ======== */
  415. /* The offset in that file. */
  416. /* */
  417. /****************************************************************************/
  418. DCUINT32 DCINTERNAL TRCDetermineOffset(DCUINT32 fileNum)
  419. {
  420. DCUINT32 retVal;
  421. PDCTCHAR pTemp;
  422. PDCUINT8 pWork;
  423. /************************************************************************/
  424. /* Set the temporary pointer to point at the end of the trace file. */
  425. /************************************************************************/
  426. pWork = (PDCUINT8)(trcpFiles[fileNum]);
  427. if(NULL == pWork)
  428. {
  429. return 0;
  430. }
  431. pWork += trcpConfig->maxFileSize - sizeof(DCTCHAR);
  432. pTemp = (PDCTCHAR)pWork;
  433. /************************************************************************/
  434. /* Now run back through the trace file looking for the first non-space */
  435. /* character. */
  436. /************************************************************************/
  437. while ((pTemp >= trcpFiles[fileNum]) &&
  438. (_T('\0') == *pTemp))
  439. {
  440. pTemp--;
  441. }
  442. /************************************************************************/
  443. /* Increment forward to the next blank character. It does not matter */
  444. /* if we increment past the end of the file as we check whether we need */
  445. /* to flip the trace files everytime we write a trace line. */
  446. /************************************************************************/
  447. pTemp++;
  448. /************************************************************************/
  449. /* Now set the offset correctly. */
  450. /************************************************************************/
  451. retVal = (DCUINT32)(pTemp - trcpFiles[fileNum]);
  452. return(retVal);
  453. } /* TRCDetermineOffset */
  454. /****************************************************************************/
  455. /* FUNCTION: TRCExitProcess(...) */
  456. /* */
  457. /* DESCRIPTION: */
  458. /* ============ */
  459. /* This function kills the current process. */
  460. /* */
  461. /* PARAMETERS: */
  462. /* =========== */
  463. /* exitCode : exit code for the terminating process */
  464. /* */
  465. /* RETURNS: */
  466. /* ======== */
  467. /* Nothing. */
  468. /* */
  469. /****************************************************************************/
  470. DCVOID DCINTERNAL TRCExitProcess(DCUINT32 exitCode)
  471. {
  472. #ifndef OS_WINCE
  473. ExitProcess(exitCode);
  474. #else
  475. //BUGBUG this is broken if not called from the main
  476. //thread.
  477. ExitThread(exitCode);
  478. #endif
  479. }
  480. /****************************************************************************/
  481. /* FUNCTION: TRCGetCurrentDate(...) */
  482. /* */
  483. /* DESCRIPTION: */
  484. /* ============ */
  485. /* This function gets the current local date and returns it in a DC_DATE */
  486. /* structure. */
  487. /* */
  488. /* PARAMETERS: */
  489. /* =========== */
  490. /* pDate : a pointer to a DC_DATE structure. */
  491. /* */
  492. /* RETURNS: */
  493. /* ======== */
  494. /* Nothing. */
  495. /* */
  496. /****************************************************************************/
  497. DCVOID DCINTERNAL TRCGetCurrentDate(PDC_DATE pDate)
  498. {
  499. SYSTEMTIME systemTime;
  500. /************************************************************************/
  501. /* Call the Win32 API function to get the current time. */
  502. /************************************************************************/
  503. GetLocalTime(&systemTime);
  504. /************************************************************************/
  505. /* Reformat the date into a DC_DATE structure. */
  506. /************************************************************************/
  507. pDate->day = (DCUINT8) systemTime.wDay;
  508. pDate->month = (DCUINT8) systemTime.wMonth;
  509. pDate->year = (DCUINT16) systemTime.wYear;
  510. } /* TRCGetCurrentDate */
  511. /****************************************************************************/
  512. /* FUNCTION: TRCGetCurrentTime(...) */
  513. /* */
  514. /* DESCRIPTION: */
  515. /* ============ */
  516. /* This function gets the current local time and returns it in a DC_TIME */
  517. /* structure. */
  518. /* */
  519. /* PARAMETERS: */
  520. /* =========== */
  521. /* pTime : a pointer to a DC_TIME structure. */
  522. /* */
  523. /* RETURNS: */
  524. /* ======== */
  525. /* Nothing. */
  526. /* */
  527. /****************************************************************************/
  528. DCVOID DCINTERNAL TRCGetCurrentTime(PDC_TIME pTime)
  529. {
  530. SYSTEMTIME systemTime;
  531. /************************************************************************/
  532. /* Call the Win32 API function to get the current time. */
  533. /************************************************************************/
  534. GetLocalTime(&systemTime);
  535. /************************************************************************/
  536. /* Reformat the time into a DC_TIME structure. */
  537. /************************************************************************/
  538. pTime->hour = (DCUINT8)systemTime.wHour;
  539. pTime->min = (DCUINT8)systemTime.wMinute;
  540. pTime->sec = (DCUINT8)systemTime.wSecond;
  541. pTime->hundredths = (DCUINT8)(systemTime.wMilliseconds / 10);
  542. } /* TRCGetCurrentTime */
  543. /****************************************************************************/
  544. /* FUNCTION: TRCGetFileTime(...) */
  545. /* */
  546. /* DESCRIPTION: */
  547. /* ============ */
  548. /* This function tests if the specified file exists - if it does it */
  549. /* returns TRUE and fills in pFileTime with a FILETIME structure. If the */
  550. /* file does not exist it returns FALSE. */
  551. /* */
  552. /* PARAMETERS: */
  553. /* =========== */
  554. /* fileNumber : number of file to query. */
  555. /* pFileTime : a pointer to a FILETIME structure. */
  556. /* */
  557. /* RETURNS: */
  558. /* ======== */
  559. /* Nothing. */
  560. /* */
  561. /****************************************************************************/
  562. DCBOOL DCINTERNAL TRCGetFileTime(DCUINT fileNumber,
  563. PDCFILETIME pFileTime)
  564. {
  565. DCBOOL rc = FALSE;
  566. HANDLE hFile;
  567. /************************************************************************/
  568. /* Attempt to open the file. By specifying OPEN_EXISITING, we only try */
  569. /* to open an existing file - the call will fail if the file doesn't */
  570. /* already exist. */
  571. /************************************************************************/
  572. hFile = CreateFile(trcpConfig->fileNames[fileNumber],
  573. GENERIC_READ,
  574. FILE_SHARE_READ,
  575. NULL,
  576. OPEN_EXISTING,
  577. FILE_ATTRIBUTE_NORMAL,
  578. NULL);
  579. /************************************************************************/
  580. /* Now check to see if the file exists - if it is invalid then the file */
  581. /* doesn't exist. */
  582. /************************************************************************/
  583. if (INVALID_HANDLE_VALUE == hFile)
  584. {
  585. /********************************************************************/
  586. /* The file doesn't exist so return FALSE. */
  587. /********************************************************************/
  588. DC_QUIT;
  589. }
  590. /************************************************************************/
  591. /* Determine the most recent trace file. Use GetFileTime to get the */
  592. /* date and time of this file. */
  593. /************************************************************************/
  594. rc = GetFileTime(hFile, NULL, NULL, pFileTime);
  595. /************************************************************************/
  596. /* Finally close the file handle. */
  597. /************************************************************************/
  598. CloseHandle(hFile);
  599. DC_EXIT_POINT:
  600. return(rc);
  601. } /* TRCGetFileTime */
  602. /****************************************************************************/
  603. /* FUNCTION: TRCSystemError(...) */
  604. /* */
  605. /* DESCRIPTION: */
  606. /* ============ */
  607. /* This function obtains the value of the system error flag and outputs it */
  608. /* to the trace file as an alert level trace. */
  609. /* */
  610. /* Note that NT maintains the last system error on a per-thread basis and */
  611. /* that most Win32 API function calls set it if they fail. */
  612. /* */
  613. /* PARAMETERS: */
  614. /* =========== */
  615. /* traceComponent : the trace component. */
  616. /* lineNumber : the line number. */
  617. /* funcName : the function name. */
  618. /* fileName : the file name. */
  619. /* */
  620. /* RETURNS: */
  621. /* ======== */
  622. /* Nothing. */
  623. /* */
  624. /****************************************************************************/
  625. DCVOID DCINTERNAL TRCSystemError(DCUINT traceComponent,
  626. DCUINT lineNumber,
  627. PDCTCHAR funcName,
  628. PDCTCHAR fileName,
  629. PDCTCHAR string)
  630. {
  631. DCUINT32 length;
  632. DWORD lastError;
  633. DWORD rc;
  634. HRESULT hr;
  635. /************************************************************************/
  636. /* Get the last system error for this thread. We will restore this at */
  637. /* the end of this function. */
  638. /************************************************************************/
  639. lastError = GetLastError();
  640. /************************************************************************/
  641. /* Grab the mutex. */
  642. /************************************************************************/
  643. TRCGrabMutex();
  644. /************************************************************************/
  645. /* The output string will be of the format: */
  646. /* */
  647. /* SYSTEM ERROR in <System Call>, <id of error> , <associated string> */
  648. /* */
  649. /* So create the first entry in the string. */
  650. /************************************************************************/
  651. hr = StringCchPrintf(trcpOutputBuffer,
  652. TRC_LINE_BUFFER_SIZE,
  653. _T("SYSTEM ERROR in %s, %d, "),
  654. string,
  655. lastError);
  656. if (SUCCEEDED(hr)) {
  657. length = DC_TSTRLEN(trcpOutputBuffer);
  658. rc = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  659. NULL,
  660. lastError,
  661. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  662. &(trcpOutputBuffer[length]),
  663. TRC_LINE_BUFFER_SIZE - length * sizeof(DCTCHAR),
  664. NULL);
  665. }
  666. else {
  667. DC_QUIT;
  668. }
  669. /************************************************************************/
  670. /* Check the return code. */
  671. /************************************************************************/
  672. if (0 == rc)
  673. {
  674. hr = StringCchPrintf(trcpOutputBuffer + length,
  675. TRC_LINE_BUFFER_SIZE - length -1,
  676. _T("<FormatMessage> failed with rc %#hx"),
  677. GetLastError());
  678. if (FAILED(hr)) {
  679. DC_QUIT;
  680. }
  681. }
  682. else
  683. {
  684. /********************************************************************/
  685. /* <FormatMessage> adds an additional '\r\n' to the end of the */
  686. /* message string - however we don't need this so we strip it off. */
  687. /********************************************************************/
  688. length = DC_TSTRLEN(trcpOutputBuffer);
  689. trcpOutputBuffer[length - 2] = _T('\0');
  690. }
  691. /************************************************************************/
  692. /* Now call our internal trace buffer function to trace this message */
  693. /* out. Note that we don't need to worry about freeing the mutex - */
  694. /* <TRC_TraceBuffer> will do that for us. */
  695. /************************************************************************/
  696. TRC_TraceBuffer(TRC_LEVEL_ALT,
  697. traceComponent,
  698. lineNumber,
  699. funcName,
  700. fileName);
  701. DC_EXIT_POINT:
  702. /************************************************************************/
  703. /* Finally we will restore the original value of last error. */
  704. /************************************************************************/
  705. SetLastError(lastError);
  706. return;
  707. } /* TRCSystemError */
  708. /****************************************************************************/
  709. /* FUNCTION: TRCOpenAllFiles(...) */
  710. /* */
  711. /* DESCRIPTION: */
  712. /* ============ */
  713. /* Opens all the trace files. */
  714. /* */
  715. /* PARAMETERS: */
  716. /* =========== */
  717. /* None. */
  718. /* */
  719. /* RETURNS: */
  720. /* ======== */
  721. /* 0 : Function succeeded. */
  722. /* */
  723. /****************************************************************************/
  724. DCUINT DCINTERNAL TRCOpenAllFiles(DCVOID)
  725. {
  726. DCUINT rc = 0;
  727. DCUINT i;
  728. DCUINT j;
  729. /************************************************************************/
  730. /* Now if we are the first process to attach then set up the trace */
  731. /* indicator. This tells us which file is currently active (i.e. */
  732. /* being used for trace output). We need to do this before we open the */
  733. /* files as if they both exist already, they will both be created. */
  734. /* File 2 will be created after file 1 and as we trace to the most */
  735. /* recent file we will end up tracing to file 2 - and you don't want to */
  736. /* do that! */
  737. /************************************************************************/
  738. if (trcCreatedTraceFiles)
  739. {
  740. TRCDetermineIndicator();
  741. }
  742. /************************************************************************/
  743. /* Open all the trace output files. */
  744. /************************************************************************/
  745. for (i = 0; i < TRC_NUM_FILES; i++)
  746. {
  747. /********************************************************************/
  748. /* Call TRCOpenSingleFile to open a single trace file. */
  749. /********************************************************************/
  750. rc = TRCOpenSingleFile(i);
  751. if (0 != rc)
  752. {
  753. DC_QUIT;
  754. }
  755. }
  756. /************************************************************************/
  757. /* Finally, if we are the first process to attach, then set up the */
  758. /* trace offset. This is the offset within the currently active trace */
  759. /* file. */
  760. /************************************************************************/
  761. if (trcCreatedTraceFiles)
  762. {
  763. trcpSharedData->trcOffset =
  764. TRCDetermineOffset(trcpSharedData->trcIndicator);
  765. }
  766. DC_EXIT_POINT:
  767. if (0 != rc)
  768. {
  769. /********************************************************************/
  770. /* Close any files that we may already have opened. We do not need */
  771. /* to call TRCCloseSingleFile for the file which failed to open */
  772. /* correctly as TRCOpenSingleFile will tidy up that file for us. */
  773. /********************************************************************/
  774. for (j = i; j > 0; j--)
  775. {
  776. TRCCloseSingleFile(j - 1, 0);
  777. }
  778. /********************************************************************/
  779. /* Clear the trace-to-file flag - we can't do it. */
  780. /********************************************************************/
  781. CLEAR_FLAG(trcpConfig->flags, TRC_OPT_FILE_OUTPUT);
  782. }
  783. /************************************************************************/
  784. /* Always return 0 to allow tracing to continue to the debugger. */
  785. /************************************************************************/
  786. return(0);
  787. } /* TRCOpenAllFiles */
  788. /****************************************************************************/
  789. /* FUNCTION: TRCOpenSharedData(...) */
  790. /* */
  791. /* DESCRIPTION: */
  792. /* ============ */
  793. /* This function opens the shared data memory mapped file. */
  794. /* */
  795. /* PARAMETERS: */
  796. /* =========== */
  797. /* None. */
  798. /* */
  799. /* RETURNS: */
  800. /* ======== */
  801. /* 0 : Function succeeded */
  802. /* TRC_RC_CREATE_MAPPING_FAILED : Failed to create the file mapping */
  803. /* TRC_RC_MAP_VIEW_FAILED : MapViewOfFile failed. */
  804. /* */
  805. /****************************************************************************/
  806. DCUINT DCINTERNAL TRCOpenSharedData(DCVOID)
  807. {
  808. DCUINT rc = 0;
  809. #ifdef RUN_ON_WINNT
  810. DWORD dwrc;
  811. #endif
  812. #ifndef OS_WINCE
  813. OSVERSIONINFO ver;
  814. SECURITY_ATTRIBUTES sa;
  815. SECURITY_DESCRIPTOR sd;
  816. PSID psidEveryone = NULL;
  817. SID_IDENTIFIER_AUTHORITY sidEveryoneAuthority = SECURITY_WORLD_SID_AUTHORITY;
  818. DCUINT32 dwDaclLength;
  819. PACL pDacl = NULL;
  820. #endif
  821. /************************************************************************/
  822. /* Attempt to create the shared data memory mapped file. If this has */
  823. /* already been created by another instance of this DLL then */
  824. /* CreateFileMapping will simply return the handle of the existing */
  825. /* object. Passing 0xFFFFFFFF creates a shared data memory mapped */
  826. /* file. */
  827. /************************************************************************/
  828. #ifdef OS_WINCE
  829. /************************************************************************/
  830. /* For Windows CE, just use global data; always reset it. Note that */
  831. /* this prevents shared use of the Trace DLL. */
  832. /************************************************************************/
  833. trchSharedDataObject = NULL;
  834. trcpSharedData = &trcSharedData;
  835. trcCreatedTraceFiles = TRUE;
  836. #else
  837. ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  838. GetVersionEx(&ver);
  839. if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  840. /************************************************************************/
  841. /* Get the SID for the Everyone group */
  842. /************************************************************************/
  843. if (!AllocateAndInitializeSid (
  844. &sidEveryoneAuthority, // pIdentifierAuthority
  845. 1, // count of subauthorities
  846. SECURITY_WORLD_RID, // subauthority 0
  847. 0, 0, 0, 0, 0, 0, 0, // subauthorities n
  848. &psidEveryone)) { // pointer to pointer to SID
  849. rc = TRC_RC_MAP_VIEW_FAILED;
  850. OutputDebugString(_T("AllocateAndInitializeSid failed.\n"));
  851. DC_QUIT;
  852. }
  853. /************************************************************************/
  854. /* Allocate the Dacl */
  855. /************************************************************************/
  856. dwDaclLength = sizeof(ACL);
  857. dwDaclLength += (sizeof(ACCESS_DENIED_ACE) - sizeof(DWORD)) +
  858. GetLengthSid(psidEveryone);
  859. dwDaclLength += (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) +
  860. GetLengthSid(psidEveryone);
  861. pDacl = (PACL)LocalAlloc(LMEM_FIXED, dwDaclLength);
  862. if (pDacl == NULL) {
  863. OutputDebugString(_T("Can't allocate Dacl.\n"));
  864. rc = TRC_RC_MAP_VIEW_FAILED;
  865. DC_QUIT;
  866. }
  867. /************************************************************************/
  868. /* Initialize it. */
  869. /************************************************************************/
  870. if (!InitializeAcl(pDacl, dwDaclLength, ACL_REVISION)) {
  871. rc = TRC_RC_MAP_VIEW_FAILED;
  872. OutputDebugString(_T("InitializeAcl failed.\n"));
  873. DC_QUIT;
  874. }
  875. /************************************************************************/
  876. /* Allow all access */
  877. /************************************************************************/
  878. if (!AddAccessAllowedAce(
  879. pDacl,
  880. ACL_REVISION,
  881. GENERIC_ALL,
  882. psidEveryone)) {
  883. rc = TRC_RC_MAP_VIEW_FAILED;
  884. OutputDebugString(_T("AddAccessAllowedAce failed.\n"));
  885. DC_QUIT;
  886. }
  887. /************************************************************************/
  888. /* Block Write-DACL Access */
  889. /************************************************************************/
  890. if (!AddAccessDeniedAce(
  891. pDacl,
  892. ACL_REVISION,
  893. WRITE_DAC,
  894. psidEveryone)) {
  895. rc = TRC_RC_MAP_VIEW_FAILED;
  896. OutputDebugString(_T("AddAccessDeniedAceEx failed.\n"));
  897. DC_QUIT;
  898. }
  899. /************************************************************************/
  900. /* Create the File Mapping */
  901. /************************************************************************/
  902. InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
  903. SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE);
  904. sa.lpSecurityDescriptor = &sd;
  905. trchSharedDataObject = CreateFileMapping(INVALID_HANDLE_VALUE,
  906. &sa,
  907. PAGE_READWRITE,
  908. 0,
  909. sizeof(TRC_SHARED_DATA),
  910. TRC_SHARED_DATA_NAME);
  911. }
  912. else {
  913. trchSharedDataObject = CreateFileMapping(INVALID_HANDLE_VALUE,
  914. NULL,
  915. PAGE_READWRITE,
  916. 0,
  917. sizeof(TRC_SHARED_DATA),
  918. TRC_SHARED_DATA_NAME);
  919. }
  920. /************************************************************************/
  921. /* Check that we succeeded in creating the file mapping. */
  922. /************************************************************************/
  923. if (NULL == trchSharedDataObject)
  924. {
  925. TRCDebugOutput(_T("NULL trchSharedDataObject.\n"));
  926. rc = TRC_RC_CREATE_MAPPING_FAILED;
  927. DC_QUIT;
  928. }
  929. /************************************************************************/
  930. /* Determine if the file mapping already exists - if it does then we */
  931. /* won't bother reading the registry data in or setting up the file */
  932. /* offset and indicator values. Note that up to this point */
  933. /* <trcCreatedTraceFiles> has been set to TRUE. */
  934. /************************************************************************/
  935. if (ERROR_ALREADY_EXISTS == GetLastError())
  936. {
  937. trcCreatedTraceFiles = FALSE;
  938. }
  939. /************************************************************************/
  940. /* We now have a handle to the shared data MMF which now needs to be */
  941. /* mapped into our address space. Setting the third, fourth and fifth */
  942. /* parameters of MapViewOfFile to zero maps the whole file into our */
  943. /* address space starting with the first byte of the file. */
  944. /************************************************************************/
  945. trcpSharedData = (PTRC_SHARED_DATA) MapViewOfFile(trchSharedDataObject,
  946. FILE_MAP_ALL_ACCESS,
  947. 0,
  948. 0,
  949. 0);
  950. if (NULL == trcpSharedData)
  951. {
  952. /********************************************************************/
  953. /* Free up the handle to the file mapping object. */
  954. /********************************************************************/
  955. CloseHandle(trchSharedDataObject);
  956. trchSharedDataObject = NULL;
  957. /********************************************************************/
  958. /* Output a debug string and then quit. */
  959. /********************************************************************/
  960. TRCDebugOutput(_T("NULL trcpSharedData.\n"));
  961. rc = TRC_RC_MAP_VIEW_FAILED;
  962. DC_QUIT;
  963. }
  964. #endif /* OS_WINCE */
  965. /************************************************************************/
  966. /* Set up our static pointer to the shared configuration data and to */
  967. /* the filter data. */
  968. /************************************************************************/
  969. trcpConfig = &(trcpSharedData->trcConfig);
  970. trcpFilter = &(trcpSharedData->trcFilter);
  971. trcpOutputBuffer = trcpSharedData->trcpOutputBuffer;
  972. /************************************************************************/
  973. /* Finally initialize the shared data block and then read in the */
  974. /* configuration data - but only if we are the first to open the file */
  975. /* mapping. */
  976. /************************************************************************/
  977. if (trcCreatedTraceFiles)
  978. {
  979. /********************************************************************/
  980. /* Initialize the shared data memory mapped file. */
  981. /********************************************************************/
  982. DC_MEMSET(trcpSharedData, 0, sizeof(TRC_SHARED_DATA));
  983. /********************************************************************/
  984. /* Initialize the internal status flags. The following flags apply */
  985. /* to all the processes. */
  986. /********************************************************************/
  987. CLEAR_FLAG(trcpFilter->trcStatus, TRC_STATUS_ASSERT_DISPLAYED);
  988. /********************************************************************/
  989. /* The following flags are maintained on a per-process basis. */
  990. /********************************************************************/
  991. CLEAR_FLAG(trcProcessStatus, TRC_STATUS_SYMBOLS_LOADED);
  992. /********************************************************************/
  993. /* Read in the configuration data. */
  994. /********************************************************************/
  995. TRCReadSharedDataConfig();
  996. /********************************************************************/
  997. /* Now split the prefix list. */
  998. /********************************************************************/
  999. TRCSplitPrefixes();
  1000. }
  1001. DC_EXIT_POINT:
  1002. #ifndef OS_WINCE
  1003. if (trchSharedDataObject == NULL) {
  1004. if (pDacl) LocalFree(pDacl);
  1005. if (psidEveryone) FreeSid(psidEveryone);
  1006. }
  1007. #endif
  1008. return(rc);
  1009. } /* TRCOpenSharedData */
  1010. /****************************************************************************/
  1011. /* FUNCTION: TRCOpenSingleFile(...) */
  1012. /* */
  1013. /* DESCRIPTION: */
  1014. /* ============ */
  1015. /* Opens a single trace memory mapped file. */
  1016. /* */
  1017. /* PARAMETERS: */
  1018. /* =========== */
  1019. /* fileNum : which file to open. */
  1020. /* */
  1021. /* RETURNS: */
  1022. /* ======== */
  1023. /* 0 : Function succeeded */
  1024. /* TRC_RC_CREATE_FILE_FAILED : CreateFile call failed */
  1025. /* TRC_RC_MAP_VIEW_FAILED : MapViewOfFile failed */
  1026. /* TRC_RC_CREATE_MAPPING_FAILED : Failed to create the file mapping */
  1027. /* */
  1028. /****************************************************************************/
  1029. DCUINT DCINTERNAL TRCOpenSingleFile(DCUINT fileNum)
  1030. {
  1031. DCUINT rc = 0;
  1032. DCBOOL blankFile = FALSE;
  1033. #ifndef OS_WINCE
  1034. DCTCHAR objectName[30];
  1035. SECURITY_ATTRIBUTES sa;
  1036. SECURITY_DESCRIPTOR sd;
  1037. PSID psidEveryone = NULL;
  1038. SID_IDENTIFIER_AUTHORITY sidEveryoneAuthority = SECURITY_WORLD_SID_AUTHORITY;
  1039. DCUINT32 dwDaclLength;
  1040. PACL pDacl = NULL;
  1041. OSVERSIONINFO ver;
  1042. HRESULT hr;
  1043. #endif
  1044. /************************************************************************/
  1045. /* Open a single trace file. First of all we attempt to open the file */
  1046. /* with read and write access, and shared read and write access. The */
  1047. /* OPEN_ALWAYS flag ensures that the file is created if it does not */
  1048. /* already exist. We pass NULL for the security attributes and */
  1049. /* template parameters (4 and 7). */
  1050. /************************************************************************/
  1051. trchFileObjects[fileNum] = CreateFile(trcpConfig->fileNames[fileNum],
  1052. GENERIC_READ | GENERIC_WRITE,
  1053. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1054. NULL,
  1055. #ifndef OS_WINCE
  1056. OPEN_ALWAYS,
  1057. #else
  1058. CREATE_ALWAYS,
  1059. #endif
  1060. FILE_ATTRIBUTE_NORMAL,
  1061. NULL);
  1062. /************************************************************************/
  1063. /* Check that the handle returned by CreateFile is valid. For some */
  1064. /* peculiar reason it does return NULL if it fails - instead it returns */
  1065. /* -1 (INVALID_HANDLE_VALUE). */
  1066. /************************************************************************/
  1067. if (INVALID_HANDLE_VALUE == trchFileObjects[fileNum])
  1068. {
  1069. TRCDebugOutput(_T("Failed to open trace file.\n"));
  1070. rc = TRC_RC_CREATE_FILE_FAILED;
  1071. DC_QUIT;
  1072. }
  1073. /************************************************************************/
  1074. /* Now check whether the file existed before the call to CreateFile. */
  1075. /* If it did then GetLastError returns ERROR_ALREADY_EXISTS (even */
  1076. /* though the function has succeeded). */
  1077. /************************************************************************/
  1078. if (0 == GetLastError())
  1079. {
  1080. /********************************************************************/
  1081. /* If the file did not exist before the call, GetLastError returns */
  1082. /* zero. In this case we want to fill the file with spaces. */
  1083. /********************************************************************/
  1084. blankFile = TRUE;
  1085. /********************************************************************/
  1086. /* We have just created the file - so would expect to need to set */
  1087. /* the security info to allow all accesses. However, a) all works */
  1088. /* just fine without it, b) the attempt to set the security stuff */
  1089. /* fails if inserted here. So we'll just go along happily without. */
  1090. /********************************************************************/
  1091. }
  1092. #ifdef OS_WINCE
  1093. SetFilePointer(trchFileObjects[fileNum],
  1094. 0,
  1095. NULL,
  1096. FILE_END);
  1097. #else
  1098. /************************************************************************/
  1099. /* Make sure that the end of the file is correctly set. The file may */
  1100. /* be of any size when we open it, but we need it to be */
  1101. /* <trcpConfig->maxFileSize> bytes long. */
  1102. /************************************************************************/
  1103. SetFilePointer(trchFileObjects[fileNum],
  1104. trcpConfig->maxFileSize,
  1105. NULL,
  1106. FILE_BEGIN);
  1107. SetEndOfFile(trchFileObjects[fileNum]);
  1108. /************************************************************************/
  1109. /* Generate the file mapping object name. This is used in */
  1110. /* CreateFileMapping. */
  1111. /************************************************************************/
  1112. hr = StringCchPrintf(objectName,
  1113. SIZE_TCHARS(objectName),
  1114. TRC_TRACE_FILE_NAME _T("%hu"), fileNum);
  1115. if (FAILED(hr)) {
  1116. DC_QUIT;
  1117. }
  1118. /************************************************************************/
  1119. /* Now create the file mapping object. Again ignore security */
  1120. /* attributes (parameter 2) and set the high order 32 bits of the */
  1121. /* object size to 0 (see Win32 SDK for more information). */
  1122. /* */
  1123. /* Create the file mapping object using a NULL Dacl so it works for all */
  1124. /* contexts. */
  1125. /************************************************************************/
  1126. ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1127. GetVersionEx(&ver);
  1128. if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  1129. /************************************************************************/
  1130. /* Get the SID for the Everyone group */
  1131. /************************************************************************/
  1132. if (!AllocateAndInitializeSid (
  1133. &sidEveryoneAuthority, // pIdentifierAuthority
  1134. 1, // count of subauthorities
  1135. SECURITY_WORLD_RID, // subauthority 0
  1136. 0, 0, 0, 0, 0, 0, 0, // subauthorities n
  1137. &psidEveryone)) { // pointer to pointer to SID
  1138. rc = TRC_RC_MAP_VIEW_FAILED;
  1139. OutputDebugString(_T("AllocateAndInitializeSid failed.\n"));
  1140. DC_QUIT;
  1141. }
  1142. /************************************************************************/
  1143. /* Allocate the Dacl */
  1144. /************************************************************************/
  1145. dwDaclLength = sizeof(ACL);
  1146. dwDaclLength += (sizeof(ACCESS_DENIED_ACE) - sizeof(DWORD)) +
  1147. GetLengthSid(psidEveryone);
  1148. dwDaclLength += (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) +
  1149. GetLengthSid(psidEveryone);
  1150. pDacl = (PACL)LocalAlloc(LMEM_FIXED, dwDaclLength);
  1151. if (pDacl == NULL) {
  1152. OutputDebugString(_T("Can't allocate Dacl.\n"));
  1153. rc = TRC_RC_MAP_VIEW_FAILED;
  1154. DC_QUIT;
  1155. }
  1156. /************************************************************************/
  1157. /* Initialize it. */
  1158. /************************************************************************/
  1159. if (!InitializeAcl(pDacl, dwDaclLength, ACL_REVISION)) {
  1160. rc = TRC_RC_MAP_VIEW_FAILED;
  1161. OutputDebugString(_T("InitializeAcl failed.\n"));
  1162. DC_QUIT;
  1163. }
  1164. /************************************************************************/
  1165. /* Allow all access */
  1166. /************************************************************************/
  1167. if (!AddAccessAllowedAce(
  1168. pDacl,
  1169. ACL_REVISION,
  1170. GENERIC_ALL,
  1171. psidEveryone)) {
  1172. rc = TRC_RC_MAP_VIEW_FAILED;
  1173. OutputDebugString(_T("AddAccessAllowedAce failed.\n"));
  1174. DC_QUIT;
  1175. }
  1176. /************************************************************************/
  1177. /* Block Write-DACL Access */
  1178. /************************************************************************/
  1179. if (!AddAccessDeniedAce(
  1180. pDacl,
  1181. ACL_REVISION,
  1182. WRITE_DAC,
  1183. psidEveryone)) {
  1184. rc = TRC_RC_MAP_VIEW_FAILED;
  1185. OutputDebugString(_T("AddAccessDeniedAceEx failed.\n"));
  1186. DC_QUIT;
  1187. }
  1188. /************************************************************************/
  1189. /* Create the File Mapping
  1190. /************************************************************************/
  1191. InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
  1192. SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE);
  1193. sa.lpSecurityDescriptor = &sd;
  1194. trchMappingObjects[fileNum] = CreateFileMapping(trchFileObjects[fileNum],
  1195. &sa,
  1196. PAGE_READWRITE,
  1197. 0,
  1198. trcpConfig->maxFileSize,
  1199. objectName);
  1200. }
  1201. else {
  1202. trchMappingObjects[fileNum] = CreateFileMapping(trchFileObjects[fileNum],
  1203. NULL,
  1204. PAGE_READWRITE,
  1205. 0,
  1206. trcpConfig->maxFileSize,
  1207. objectName);
  1208. }
  1209. /************************************************************************/
  1210. /* Check that we succeeded in creating the file mapping object. */
  1211. /* CreateFileMapping returns NULL if it fails. */
  1212. /************************************************************************/
  1213. if (NULL == trchMappingObjects[fileNum])
  1214. {
  1215. TRCDebugOutput(_T("Failed to map trace file.\n"));
  1216. rc = TRC_RC_CREATE_MAPPING_FAILED;
  1217. DC_QUIT;
  1218. }
  1219. /************************************************************************/
  1220. /* Now map a view of the file. Set the low and high order offsets to */
  1221. /* zero (parameters 3 and 4). */
  1222. /************************************************************************/
  1223. trcpFiles[fileNum] = (PDCTCHAR)MapViewOfFile(trchMappingObjects[fileNum],
  1224. FILE_MAP_ALL_ACCESS,
  1225. 0,
  1226. 0,
  1227. trcpConfig->maxFileSize);
  1228. /************************************************************************/
  1229. /* Check that we mapped a view of the file. */
  1230. /************************************************************************/
  1231. if (NULL == trcpFiles[fileNum])
  1232. {
  1233. TRCDebugOutput(_T("Failed to map view of trace file.\n"));
  1234. rc = TRC_RC_MAP_VIEW_FAILED;
  1235. DC_QUIT;
  1236. }
  1237. /************************************************************************/
  1238. /* Finally check to see if we need to blank this file. */
  1239. /************************************************************************/
  1240. if (blankFile)
  1241. {
  1242. TRCBlankFile(fileNum);
  1243. }
  1244. #endif
  1245. DC_EXIT_POINT:
  1246. /************************************************************************/
  1247. /* If the return code is non-zero then we need to perform some tidying */
  1248. /* up. */
  1249. /************************************************************************/
  1250. if (0 != rc)
  1251. {
  1252. #ifndef OS_WINCE
  1253. /********************************************************************/
  1254. /* Check whether we need to free the handle to the file mapping */
  1255. /* object. */
  1256. /********************************************************************/
  1257. if (NULL != trchMappingObjects[fileNum])
  1258. {
  1259. CloseHandle(trchMappingObjects[fileNum]);
  1260. trchMappingObjects[fileNum] = NULL;
  1261. }
  1262. #endif
  1263. /********************************************************************/
  1264. /* Check whether we need to free the handle to the file object. */
  1265. /********************************************************************/
  1266. if (NULL != trchFileObjects[fileNum])
  1267. {
  1268. CloseHandle(trchFileObjects[fileNum]);
  1269. trchFileObjects[fileNum] = NULL;
  1270. }
  1271. }
  1272. return(rc);
  1273. } /* TRCOpenSingleFile */
  1274. /****************************************************************************/
  1275. /* FUNCTION: TRCOutputToFile(...) */
  1276. /* */
  1277. /* DESCRIPTION: */
  1278. /* ============ */
  1279. /* This function writes a string to the trace file. It is used to trace */
  1280. /* both normal trace lines and stack trace lines. */
  1281. /* */
  1282. /* PARAMETERS: */
  1283. /* =========== */
  1284. /* pText : a pointer to the trace text string. */
  1285. /* length : length of the string. */
  1286. /* traceLevel : the current trace level. */
  1287. /* */
  1288. /* RETURNS: */
  1289. /* ======== */
  1290. /* Nothing. */
  1291. /* */
  1292. /****************************************************************************/
  1293. DCVOID DCINTERNAL TRCOutputToFile(PDCTCHAR pText,
  1294. DCUINT length,
  1295. DCUINT traceLevel)
  1296. {
  1297. #ifndef OS_WINCE
  1298. PDCUINT8 pFilePos;
  1299. /************************************************************************/
  1300. /* Make sure we have a trace file with enough free space. */
  1301. /************************************************************************/
  1302. TRCMaybeSwapFile(length);
  1303. /************************************************************************/
  1304. /* We can now write out the trace line. */
  1305. /************************************************************************/
  1306. pFilePos = (PDCUINT8)trcpFiles[trcpSharedData->trcIndicator] +
  1307. trcpSharedData->trcOffset;
  1308. DC_MEMCPY(pFilePos, pText, length);
  1309. /************************************************************************/
  1310. /* Check if we should flush this line to disk immediately. If this is */
  1311. /* an error or higher level trace then flush to disk regardless. */
  1312. /************************************************************************/
  1313. if ((TRUE == TEST_FLAG(trcpConfig->flags, TRC_OPT_FLUSH_ON_TRACE)) ||
  1314. (traceLevel >= TRC_LEVEL_ERR))
  1315. {
  1316. FlushViewOfFile(pFilePos, length);
  1317. }
  1318. /************************************************************************/
  1319. /* Finally update the offset. */
  1320. /************************************************************************/
  1321. trcpSharedData->trcOffset += length;
  1322. #else
  1323. DWORD dwRet;
  1324. WriteFile(trchFileObjects[0], pText, length, &dwRet, NULL);
  1325. #endif
  1326. DC_EXIT_POINT:
  1327. return;
  1328. } /* TRCOutputToFile */
  1329. /****************************************************************************/
  1330. /* FUNCTION: TRCReadEntry(...) */
  1331. /* */
  1332. /* DESCRIPTION: */
  1333. /* ============ */
  1334. /* Read an entry from the given section of the registry. */
  1335. /* */
  1336. /* PARAMETERS: */
  1337. /* =========== */
  1338. /* topLevelKey : one of: */
  1339. /* - HKEY_CURRENT_USER */
  1340. /* - HKEY_LOCAL_MACHINE */
  1341. /* pSection : the section name to read from. The DC_REG_PREFIX */
  1342. /* string is prepended to give the full name. */
  1343. /* pEntry : the entry name to read. */
  1344. /* pBuffer : a buffer to read the entry to. */
  1345. /* bufferSize : the size of the buffer. */
  1346. /* expectedDataType : the type of data stored in the entry. */
  1347. /* */
  1348. /* RETURNS: */
  1349. /* ======== */
  1350. /* Nothing. */
  1351. /* */
  1352. /****************************************************************************/
  1353. DCUINT DCINTERNAL TRCReadEntry(HKEY topLevelKey,
  1354. PDCTCHAR pEntry,
  1355. PDCTCHAR pBuffer,
  1356. DCINT bufferSize,
  1357. DCINT32 expectedDataType)
  1358. {
  1359. LONG sysrc;
  1360. HKEY key;
  1361. DCINT32 dataType;
  1362. DCINT32 dataSize;
  1363. DCTCHAR subKey[TRC_MAX_SUBKEY];
  1364. DCBOOL keyOpen = FALSE;
  1365. DCUINT rc = 0;
  1366. HRESULT hr;
  1367. /************************************************************************/
  1368. /* Get a subkey for the value. */
  1369. /************************************************************************/
  1370. hr = StringCchCopy(subKey,
  1371. SIZE_TCHARS(subKey),
  1372. TRC_SUBKEY_NAME);
  1373. if (FAILED(hr)) {
  1374. DC_QUIT;
  1375. }
  1376. /************************************************************************/
  1377. /* Try to open the key. If the entry does not exist, RegOpenKeyEx will */
  1378. /* fail. */
  1379. /************************************************************************/
  1380. sysrc = RegOpenKeyEx(topLevelKey,
  1381. subKey,
  1382. 0, /* reserved */
  1383. KEY_ALL_ACCESS,
  1384. &key);
  1385. if (ERROR_SUCCESS != sysrc)
  1386. {
  1387. /********************************************************************/
  1388. /* Don't trace an error here since the subkey may not exist... */
  1389. /********************************************************************/
  1390. rc = TRC_RC_IO_ERROR;
  1391. DC_QUIT;
  1392. }
  1393. keyOpen = TRUE;
  1394. /************************************************************************/
  1395. /* We successfully opened the key so now try to read the value. Again */
  1396. /* it may not exist. */
  1397. /************************************************************************/
  1398. dataSize = (DCINT32)bufferSize;
  1399. sysrc = RegQueryValueEx(key,
  1400. pEntry,
  1401. 0, /* reserved */
  1402. (LPDWORD) &dataType,
  1403. (LPBYTE) pBuffer,
  1404. (LPDWORD) &dataSize);
  1405. if (sysrc != ERROR_SUCCESS)
  1406. {
  1407. rc = TRC_RC_IO_ERROR;
  1408. DC_QUIT;
  1409. }
  1410. /************************************************************************/
  1411. /* Check that the type is correct. Special case: allow REG_BINARY */
  1412. /* instead of REG_DWORD, as long as the length is 32 bits. */
  1413. /************************************************************************/
  1414. if ((dataType != expectedDataType) &&
  1415. ((dataType != REG_BINARY) ||
  1416. (expectedDataType != REG_DWORD) ||
  1417. (dataSize != 4)))
  1418. {
  1419. rc = TRC_RC_IO_ERROR;
  1420. DC_QUIT;
  1421. }
  1422. DC_EXIT_POINT:
  1423. /************************************************************************/
  1424. /* Close the key (if required). */
  1425. /************************************************************************/
  1426. if (keyOpen)
  1427. {
  1428. sysrc = RegCloseKey(key);
  1429. if (ERROR_SUCCESS != sysrc)
  1430. {
  1431. TRCDebugOutput(_T("Failed to close key.\n"));
  1432. }
  1433. }
  1434. return(rc);
  1435. } /* TRCReadEntry */
  1436. /****************************************************************************/
  1437. /* FUNCTION: TRCStackTrace(...) */
  1438. /* */
  1439. /* DESCRIPTION: */
  1440. /* ============ */
  1441. /* */
  1442. /* PARAMETERS: */
  1443. /* =========== */
  1444. /* traceLevel : the current trace level which is used to determine */
  1445. /* whether this line should be flushed to disk */
  1446. /* immediately. */
  1447. /* */
  1448. /* RETURNS: */
  1449. /* ======== */
  1450. /* Nothing. */
  1451. /* */
  1452. /****************************************************************************/
  1453. DCVOID DCINTERNAL TRCStackTrace(DCUINT traceLevel)
  1454. {
  1455. DC_IGNORE_PARAMETER(traceLevel);
  1456. #ifdef DO_STACK_TRACE
  1457. HANDLE hProcess;
  1458. HANDLE hThread;
  1459. DCBOOL sysrc;
  1460. STACKFRAME stackFrame;
  1461. DWORD machineType;
  1462. IMAGEHLP_MODULE moduleInfo;
  1463. DCINT i;
  1464. DCTCHAR formatString[TRC_FRMT_BUFFER_SIZE];
  1465. CONTEXT threadContext;
  1466. CHAR symBuffer[sizeof(IMAGEHLP_SYMBOL)+TRC_MAX_SYMNAME_SIZE];
  1467. PIMAGEHLP_SYMBOL pSymbol;
  1468. PCHAR pFuncName;
  1469. DWORD displacement = 0;
  1470. DCBOOL foundTrace = FALSE;
  1471. /************************************************************************/
  1472. /* First of all ensure that stack tracing is enabled - if it is not */
  1473. /* then just return. */
  1474. /************************************************************************/
  1475. /************************************************************************/
  1476. /* The stack trace code doesn't work for Alpha so don't bother trying. */
  1477. /************************************************************************/
  1478. #ifndef _M_ALPHA
  1479. if (!TEST_FLAG(trcpConfig->flags, TRC_OPT_STACK_TRACING))
  1480. #endif
  1481. {
  1482. DC_QUIT;
  1483. }
  1484. /************************************************************************/
  1485. /* Set <pSymbol> to point to the symbol buffer. */
  1486. /************************************************************************/
  1487. pSymbol = (PIMAGEHLP_SYMBOL) symBuffer;
  1488. /************************************************************************/
  1489. /* Zero memory structures. */
  1490. /************************************************************************/
  1491. ZeroMemory(&stackFrame, sizeof(stackFrame));
  1492. ZeroMemory(pSymbol, sizeof(IMAGEHLP_SYMBOL));
  1493. ZeroMemory(&threadContext, sizeof(CONTEXT));
  1494. /************************************************************************/
  1495. /* Initialize the symbol buffer. */
  1496. /************************************************************************/
  1497. pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  1498. pSymbol->MaxNameLength = 1024;
  1499. /************************************************************************/
  1500. /* Get handles to the current process and thread. */
  1501. /************************************************************************/
  1502. hProcess = GetCurrentProcess();
  1503. hThread = GetCurrentThread();
  1504. /************************************************************************/
  1505. /* We need to get the values of the base pointer, stack pointer and the */
  1506. /* instruction pointer. We can use <GetContextThread> to return this */
  1507. /* information - but first of all we need to set the <ContextFlags> */
  1508. /* member of the <threadContext> struture to return the control */
  1509. /* registers. */
  1510. /************************************************************************/
  1511. threadContext.ContextFlags = CONTEXT_CONTROL;
  1512. /************************************************************************/
  1513. /* Now attempt to get the thread context. */
  1514. /************************************************************************/
  1515. if (!GetThreadContext(hThread, &threadContext))
  1516. {
  1517. /********************************************************************/
  1518. /* If <GetThreadContext> failed then there is not a lot we can do */
  1519. /* so just quit. */
  1520. /********************************************************************/
  1521. TRCInternalError(_T("GetThreadContext failed.\n"));
  1522. DC_QUIT;
  1523. }
  1524. /************************************************************************/
  1525. /* Store the instruction pointer in the <stackFrame> structure. */
  1526. /************************************************************************/
  1527. stackFrame.AddrPC.Mode = AddrModeFlat;
  1528. /************************************************************************/
  1529. /* Processor dependant section. We set the image file type here and if */
  1530. /* we are running on Intel hardware we also store the stack pointer and */
  1531. /* base pointer. */
  1532. /************************************************************************/
  1533. #if defined(_M_IX86)
  1534. machineType = IMAGE_FILE_MACHINE_I386;
  1535. stackFrame.AddrPC.Offset = threadContext.Eip;
  1536. stackFrame.AddrFrame.Offset = threadContext.Ebp;
  1537. stackFrame.AddrFrame.Mode = AddrModeFlat;
  1538. stackFrame.AddrStack.Offset = threadContext.Esp;
  1539. stackFrame.AddrStack.Mode = AddrModeFlat;
  1540. #elif defined (_M_MRX000)
  1541. machineType = IMAGE_FILE_MACHINE_R4000;
  1542. #elif defined (_M_ALPHA)
  1543. machineType = IMAGE_FILE_MACHINE_ALPHA;
  1544. #elif defined (_M_PPC)
  1545. machineType = IMAGE_FILE_MACHINE_POWERPC;
  1546. #else
  1547. #error("Unknown machine type.");
  1548. #endif
  1549. /************************************************************************/
  1550. /* Now run down the stack. */
  1551. /************************************************************************/
  1552. for (i = 1; i < TRC_MAX_SIZE_STACK_TRACE; i++)
  1553. {
  1554. /********************************************************************/
  1555. /* Call <StackWalk> to start walking the stack. */
  1556. /********************************************************************/
  1557. sysrc = StackWalk(machineType,
  1558. hProcess,
  1559. hThread,
  1560. &stackFrame,
  1561. &threadContext,
  1562. NULL,
  1563. SymFunctionTableAccess,
  1564. SymGetModuleBase,
  1565. NULL);
  1566. /********************************************************************/
  1567. /* Check the return code. */
  1568. /********************************************************************/
  1569. if (FALSE == sysrc)
  1570. {
  1571. /****************************************************************/
  1572. /* Don't trace anything here as we enter here when we reach */
  1573. /* the end of the stack. */
  1574. /****************************************************************/
  1575. DC_QUIT;
  1576. }
  1577. /********************************************************************/
  1578. /* Get the module name. */
  1579. /********************************************************************/
  1580. sysrc = SymGetModuleInfo(hProcess,
  1581. stackFrame.AddrPC.Offset,
  1582. &moduleInfo);
  1583. /********************************************************************/
  1584. /* Check the return code. */
  1585. /********************************************************************/
  1586. if (FALSE == sysrc)
  1587. {
  1588. /****************************************************************/
  1589. /* Don't trace anything as we enter here when we reach the end */
  1590. /* of the stack. */
  1591. /****************************************************************/
  1592. DC_QUIT;
  1593. }
  1594. /********************************************************************/
  1595. /* When we start we are somewhere in the midst of */
  1596. /* <GetThreadContext>. Since we're only interested in the stack */
  1597. /* above the trace module then we need to skip everything until we */
  1598. /* pass the trace module. */
  1599. /* */
  1600. /* Look for the trace module name. */
  1601. /********************************************************************/
  1602. if (DC_TSTRCMPI(trcpSharedData->trcpModuleFileName,
  1603. moduleInfo.ModuleName) == 0)
  1604. {
  1605. /****************************************************************/
  1606. /* They match so set the <foundTrace> flag and the continue. */
  1607. /****************************************************************/
  1608. foundTrace = TRUE;
  1609. continue;
  1610. }
  1611. /********************************************************************/
  1612. /* We've not found the trace module yet so just continue. */
  1613. /********************************************************************/
  1614. if (!foundTrace)
  1615. {
  1616. continue;
  1617. }
  1618. /********************************************************************/
  1619. /* Now get the symbol name. */
  1620. /********************************************************************/
  1621. sysrc = SymGetSymFromAddr(hProcess,
  1622. stackFrame.AddrPC.Offset,
  1623. &displacement,
  1624. pSymbol);
  1625. /********************************************************************/
  1626. /* Check the return code. */
  1627. /********************************************************************/
  1628. if (sysrc)
  1629. {
  1630. /****************************************************************/
  1631. /* We've found some symbols so use them. */
  1632. /****************************************************************/
  1633. pFuncName = pSymbol->Name;
  1634. }
  1635. else
  1636. {
  1637. /****************************************************************/
  1638. /* No symbols available. */
  1639. /****************************************************************/
  1640. pFuncName = _T("<nosymbols>");
  1641. }
  1642. /********************************************************************/
  1643. /* Finally format the string. */
  1644. /********************************************************************/
  1645. hr = StringCchPrintf(
  1646. formatString,
  1647. SIZE_TCHARS(formatString),
  1648. _T(" ") TRC_MODL_FMT _T("!") TRC_FUNC_FMT _T(" : ") TRC_STCK_FMT_T("\r\n"),
  1649. moduleInfo.ModuleName,
  1650. trcpConfig->funcNameLength,
  1651. trcpConfig->funcNameLength,
  1652. pFuncName,
  1653. displacement,
  1654. stackFrame.AddrFrame.Offset,
  1655. stackFrame.AddrReturn.Offset,
  1656. stackFrame.Params[0],
  1657. stackFrame.Params[1],
  1658. stackFrame.Params[2],
  1659. stackFrame.Params[3]
  1660. );
  1661. if (SUCCEEDED(hr)) {
  1662. /********************************************************************/
  1663. /* Output this line of the <formatString>. */
  1664. /********************************************************************/
  1665. TRCOutput(formatString, DC_TSTRLEN(formatString), traceLevel);
  1666. }
  1667. }
  1668. DC_EXIT_POINT:
  1669. return;
  1670. #endif /* DO_STACK_TRACE */
  1671. } /* TRCStackTrace */
  1672. /****************************************************************************/
  1673. /* FUNCTION: TRCSymbolsLoad(...) */
  1674. /* */
  1675. /* DESCRIPTION: */
  1676. /* ============ */
  1677. /* Function to load symbolic debugging information. This function should */
  1678. /* only be called if the trace mutex has been obtained. */
  1679. /* */
  1680. /* PARAMETERS: */
  1681. /* =========== */
  1682. /* None. */
  1683. /* */
  1684. /* RETURNS: */
  1685. /* ======== */
  1686. /* 0 : success. */
  1687. /* TRC_SYMBOL_LOAD_FAILED : failed to load symbols. */
  1688. /* */
  1689. /****************************************************************************/
  1690. DCUINT DCINTERNAL TRCSymbolsLoad(DCVOID)
  1691. {
  1692. DCUINT rc = 0;
  1693. HANDLE hProcess;
  1694. #ifdef DO_STACK_TRACE
  1695. DWORD options;
  1696. #endif
  1697. /************************************************************************/
  1698. /* Get the current process handle. */
  1699. /************************************************************************/
  1700. hProcess = GetCurrentProcess();
  1701. /************************************************************************/
  1702. /* We're about to load symbols - so trace a line out. */
  1703. /************************************************************************/
  1704. TRCInternalTrace(TRC_SYMBOLS_LOADING_NOTIFY);
  1705. #ifdef DO_STACK_TRACE
  1706. /************************************************************************/
  1707. /* Now set the deferred symbol load option. For some peculiar reason */
  1708. /* this is not set by default. */
  1709. /************************************************************************/
  1710. options = SymGetOptions();
  1711. SymSetOptions(options | SYMOPT_DEFERRED_LOADS);
  1712. /************************************************************************/
  1713. /* Initialize the symbol handler for this process. By setting param 2 */
  1714. /* to NULL the search path for the symbols is as follows: */
  1715. /* */
  1716. /* - Current directory */
  1717. /* - Env variable _NT_SYMBOL_PATH */
  1718. /* - Env variable _NT_ALTERNATE_SYMBOL_PATH */
  1719. /* - Env variable SYSTEMROOT */
  1720. /* */
  1721. /* By setting the third parameter to TRUE we tell IMAGEHLP to enumerate */
  1722. /* the loaded modules for this process (this effectively calls */
  1723. /* <SymLoadModule> for each module). */
  1724. /************************************************************************/
  1725. /************************************************************************/
  1726. /* LAURABU: */
  1727. /* SymInitialize returns FALSE on Win95. Moreover, it makes no sense */
  1728. /* to fail to start up on either NT or Win95 just because this dll */
  1729. /* couldn't load debug symbols. Therefore don't fail. */
  1730. /************************************************************************/
  1731. if (!(SymInitialize(hProcess, NULL, TRUE)))
  1732. {
  1733. #ifdef DC_OMIT
  1734. rc = TRC_RC_SYMBOL_LOAD_FAILED;
  1735. #endif
  1736. TRCDebugOutput(_T("SymInitialize failed.\n"));
  1737. #ifdef DC_OMIT
  1738. DC_QUIT;
  1739. #endif
  1740. }
  1741. #endif
  1742. /************************************************************************/
  1743. /* Set the flag to indicate the symbols have been loaded. */
  1744. /************************************************************************/
  1745. SET_FLAG(trcProcessStatus, TRC_STATUS_SYMBOLS_LOADED);
  1746. /************************************************************************/
  1747. /* Write a status line. The assumption here is that this is done under */
  1748. /* the mutex. */
  1749. /************************************************************************/
  1750. TRCInternalTrace(TRC_SYMBOLS_LOADED_NOTIFY);
  1751. DC_EXIT_POINT:
  1752. return(rc);
  1753. } /* TRCSymbolsLoad */
  1754. /****************************************************************************/
  1755. /* FUNCTION: TRCSymbolsUnload(...) */
  1756. /* */
  1757. /* DESCRIPTION: */
  1758. /* ============ */
  1759. /* */
  1760. /* PARAMETERS: */
  1761. /* =========== */
  1762. /* None. */
  1763. /* */
  1764. /* RETURNS: */
  1765. /* ======== */
  1766. /* TRUE if successful and FALSE otherwise. */
  1767. /* */
  1768. /****************************************************************************/
  1769. DCBOOL DCINTERNAL TRCSymbolsUnload(DCVOID)
  1770. {
  1771. DCBOOL rc = TRUE;
  1772. #ifdef DO_STACK_TRACE
  1773. HANDLE hProcess;
  1774. /************************************************************************/
  1775. /* Get the current process handle. */
  1776. /************************************************************************/
  1777. hProcess = GetCurrentProcess();
  1778. /************************************************************************/
  1779. /* Cleanup the symbols. */
  1780. /************************************************************************/
  1781. rc = SymCleanup(hProcess);
  1782. /************************************************************************/
  1783. /* Check the return code. */
  1784. /************************************************************************/
  1785. if (FALSE == rc)
  1786. {
  1787. TRCDebugOutput(_T("SymCleanup failed.\n"));
  1788. DC_QUIT;
  1789. }
  1790. #endif
  1791. /************************************************************************/
  1792. /* Clear the symbols loaded flag. */
  1793. /************************************************************************/
  1794. CLEAR_FLAG(trcProcessStatus, TRC_STATUS_SYMBOLS_LOADED);
  1795. /************************************************************************/
  1796. /* Write a status line to the trace file. The assumption here is that */
  1797. /* this is done under the mutex. */
  1798. /************************************************************************/
  1799. TRCInternalTrace(TRC_SYMBOLS_UNLOAD_NOTIFY);
  1800. DC_EXIT_POINT:
  1801. return(rc);
  1802. } /* TRCSymbolsLoad */
  1803. /****************************************************************************/
  1804. /* FUNCTION: TRCWriteEntry(...) */
  1805. /* */
  1806. /* DESCRIPTION: */
  1807. /* ============ */
  1808. /* Write an entry to the given section of the registry. */
  1809. /* */
  1810. /* PARAMETERS: */
  1811. /* =========== */
  1812. /* topLevelKey : one of: */
  1813. /* - HKEY_CURRENT_USER */
  1814. /* - HKEY_LOCAL_MACHINE */
  1815. /* pEntry : the entry name to write. */
  1816. /* pData : a pointer to the data to be written. */
  1817. /* dataSize : the size of the data to be written. For strings, this */
  1818. /* should include the NULL terminator. */
  1819. /* dataType : the type of the data to be written. */
  1820. /* */
  1821. /* RETURNS: */
  1822. /* ======== */
  1823. /* 0 : success */
  1824. /* TRC_RC_IO_ERROR : I/O error. */
  1825. /* */
  1826. /****************************************************************************/
  1827. DCUINT DCINTERNAL TRCWriteEntry(HKEY topLevelKey,
  1828. PDCTCHAR pEntry,
  1829. PDCTCHAR pData,
  1830. DCINT dataSize,
  1831. DCINT32 dataType)
  1832. {
  1833. LONG sysrc;
  1834. HKEY key;
  1835. DCTCHAR subKey[TRC_MAX_SUBKEY];
  1836. DWORD disposition;
  1837. DCBOOL keyOpen = FALSE;
  1838. DCUINT rc = 0;
  1839. HRESULT hr;
  1840. /************************************************************************/
  1841. /* Get a subkey for the value. */
  1842. /************************************************************************/
  1843. hr = StringCchCopy(subKey,
  1844. SIZE_TCHARS(subKey),
  1845. TRC_SUBKEY_NAME);
  1846. if (FAILED(hr)) {
  1847. DC_QUIT;
  1848. }
  1849. /************************************************************************/
  1850. /* Try to create the key. If the entry already exists, RegCreateKeyEx */
  1851. /* will open the existing entry. */
  1852. /************************************************************************/
  1853. sysrc = RegCreateKeyEx(topLevelKey,
  1854. subKey,
  1855. 0, /* reserved */
  1856. NULL, /* class */
  1857. REG_OPTION_NON_VOLATILE,
  1858. KEY_ALL_ACCESS,
  1859. NULL, /* security attributes */
  1860. &key,
  1861. &disposition);
  1862. if (ERROR_SUCCESS != sysrc)
  1863. {
  1864. DCTCHAR output[12];
  1865. TRCDebugOutput(_T("Failed to create key failed with error "));
  1866. hr = StringCchPrintf(output, SIZE_TCHARS(output),
  1867. _T("%#lx"), GetLastError());
  1868. if (SUCCEEDED(hr)) {
  1869. TRCDebugOutput(output);
  1870. }
  1871. DC_QUIT;
  1872. }
  1873. keyOpen = TRUE;
  1874. /************************************************************************/
  1875. /* We've got the key, so set the value. */
  1876. /************************************************************************/
  1877. sysrc = RegSetValueEx(key,
  1878. pEntry,
  1879. 0, /* reserved */
  1880. dataType,
  1881. (LPBYTE) pData,
  1882. (DCINT32) dataSize);
  1883. if (ERROR_SUCCESS != sysrc)
  1884. {
  1885. DCTCHAR output[12];
  1886. TRCDebugOutput(_T("Failed to set value failed with error "));
  1887. hr = StringCchPrintf(output, SIZE_TCHARS(output),
  1888. _T("%#lx"), GetLastError());
  1889. if (SUCCEEDED(hr)) {
  1890. TRCDebugOutput(output);
  1891. }
  1892. DC_QUIT;
  1893. }
  1894. DC_EXIT_POINT:
  1895. /************************************************************************/
  1896. /* Close the key (if required) */
  1897. /************************************************************************/
  1898. if (keyOpen)
  1899. {
  1900. sysrc = RegCloseKey(key);
  1901. if (ERROR_SUCCESS != sysrc)
  1902. {
  1903. TRCDebugOutput(_T("Failed to close key.\n"));
  1904. }
  1905. }
  1906. return(rc);
  1907. } /* TRCWriteEntry */
  1908. /****************************************************************************/
  1909. /* We have our own implementation of DebugBreak that on NT checks if a */
  1910. /* debugger is present first before calling DebugBreak(). Otherwise the */
  1911. /* app will just get terminated due to an unhandled exception. */
  1912. /****************************************************************************/
  1913. typedef BOOL (WINAPI * PFN_ISDEBUGGERPRESENT)(void);
  1914. DCVOID DCINTERNAL TRCDebugBreak(DCVOID)
  1915. {
  1916. static PFN_ISDEBUGGERPRESENT s_pfnIsDebuggerPresent = NULL;
  1917. static BOOL s_fHaveWeTriedToFindIt = FALSE;
  1918. if (! s_pfnIsDebuggerPresent)
  1919. {
  1920. if (!InterlockedExchange((long *)&s_fHaveWeTriedToFindIt, TRUE))
  1921. {
  1922. /****************************************************************/
  1923. /* Try to get the proc address of "IsDebuggerPresent". Note we */
  1924. /* can just write into this variable without Interlocked stuff */
  1925. /* since dwords get written to and read from atomically. */
  1926. /****************************************************************/
  1927. #ifndef OS_WINCE
  1928. s_pfnIsDebuggerPresent = (PFN_ISDEBUGGERPRESENT)
  1929. GetProcAddress(GetModuleHandle(_T("kernel32.dll")),
  1930. "IsDebuggerPresent");
  1931. #else // OS_WINCE
  1932. HMODULE hmod;
  1933. hmod = LoadLibrary(_T("kernel32.dll"));
  1934. s_pfnIsDebuggerPresent = (PFN_ISDEBUGGERPRESENT)
  1935. GetProcAddress(hmod,
  1936. _T("IsDebuggerPresent"));
  1937. FreeLibrary(hmod);
  1938. #endif
  1939. }
  1940. }
  1941. /************************************************************************/
  1942. /* If this api doesn't exist, we are on Win95, so go ahead and call */
  1943. /* DebugBreak(). If it does, we are on NT 4, so find out if a debugger */
  1944. /* is around. If a debugger isn't there, then don't break for now */
  1945. /* since we don't have debuggers attached to most of our NT machines */
  1946. /* yet. */
  1947. /************************************************************************/
  1948. if (!s_pfnIsDebuggerPresent || (s_pfnIsDebuggerPresent()))
  1949. DebugBreak();
  1950. }