Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1038 lines
26 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: api.c
  5. //
  6. // History:
  7. // Abolade Gbadegesin July-25-1995 Created
  8. //
  9. // API entry-points for tracing dll
  10. //============================================================================
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <rtutils.h>
  16. #include <stdlib.h>
  17. #include "trace.h"
  18. //#define STRSAFE_LIB
  19. #include <strsafe.h>
  20. #define ENTER_TRACE_API(lpserver) \
  21. (((lpserver)!=NULL) && ((lpserver)->TS_StopEvent != NULL))
  22. //
  23. // called before any other functions; responsible for creating
  24. // and initializing a client structure for the caller
  25. // and notifying the server of the new client
  26. //
  27. DWORD
  28. APIENTRY
  29. TraceRegisterEx(
  30. IN LPCTSTR lpszCallerName,
  31. IN DWORD dwFlags
  32. ) {
  33. DWORD dwErr, dwClientID;
  34. LPTRACE_SERVER lpserver;
  35. LPTRACE_CLIENT lpclient, *lplpc, *lplpcstart, *lplpcend;
  36. HRESULT hrResult;
  37. if (!lpszCallerName)
  38. return INVALID_TRACEID;
  39. lpserver = GET_TRACE_SERVER();
  40. ASSERTMSG ("Could not create trace server ", lpserver!=NULL);
  41. if (!lpserver)
  42. return INVALID_TRACEID;
  43. TRACE_ACQUIRE_WRITELOCK(lpserver);
  44. //
  45. // complete the console thread event creations if not done before
  46. //
  47. if (lpserver->TS_TableEvent == NULL) {
  48. dwErr = TraceCreateServerComplete(lpserver);
  49. if (dwErr != 0) {
  50. TRACE_RELEASE_WRITELOCK(lpserver);
  51. return INVALID_TRACEID;
  52. }
  53. }
  54. lpclient = TraceFindClient(lpserver, lpszCallerName);
  55. if (lpclient != NULL) {
  56. //
  57. // client already exists
  58. //
  59. TRACE_RELEASE_WRITELOCK(lpserver);
  60. return (lpclient->TC_ClientID ^ CLIENT_SIGNATURE);
  61. }
  62. //
  63. // find an empty space
  64. //
  65. lplpcstart = lpserver->TS_ClientTable;
  66. lplpcend = lplpcstart + MAX_CLIENT_COUNT;
  67. for (lplpc = lplpcstart; lplpc < lplpcend; lplpc++) {
  68. if (*lplpc == NULL) { break; }
  69. }
  70. if (lplpc >= lplpcend) {
  71. //
  72. // no space in table
  73. //
  74. TRACE_RELEASE_WRITELOCK(lpserver);
  75. return INVALID_TRACEID;
  76. }
  77. //
  78. // create the new client and enable it
  79. //
  80. dwErr = TraceCreateClient(lplpc);
  81. if (dwErr != 0) {
  82. //
  83. // something wrong, so abort
  84. //
  85. TRACE_RELEASE_WRITELOCK(lpserver);
  86. return INVALID_TRACEID;
  87. }
  88. lpclient = *lplpc;
  89. lpclient->TC_ClientID = dwClientID = (DWORD)(lplpc - lplpcstart);
  90. hrResult = StringCchCopy(
  91. lpclient->TC_ClientName,
  92. MAX_CLIENTNAME_LENGTH, lpszCallerName
  93. );
  94. if (FAILED(hrResult))
  95. {
  96. TRACE_RELEASE_WRITELOCK(lpserver);
  97. return INVALID_TRACEID;
  98. }
  99. //
  100. // copy the client name in the other format as well
  101. // sssafe
  102. //
  103. #ifdef UNICODE
  104. if (wcstombs(
  105. lpclient->TC_ClientNameA, lpclient->TC_ClientNameW,
  106. MAX_CLIENTNAME_LENGTH //dont subtract 1
  107. ) == (size_t)-1)
  108. {
  109. TRACE_RELEASE_WRITELOCK(lpserver);
  110. return INVALID_TRACEID;
  111. }
  112. if (lpclient->TC_ClientNameA[MAX_CLIENTNAME_LENGTH-1] != '\0')
  113. {
  114. TRACE_RELEASE_WRITELOCK(lpserver);
  115. return INVALID_TRACEID;
  116. }
  117. #else
  118. if (mbstowcs(
  119. lpclient->TC_ClientNameW, lpclient->TC_ClientNameA,
  120. MAX_CLIENTNAME_LENGTH //dont subtract 1
  121. ) == (size_t)-1)
  122. {
  123. TRACE_RELEASE_WRITELOCK(lpserver);
  124. return INVALID_TRACEID;
  125. }
  126. if (lpclient->TC_ClientNameW[MAX_CLIENTNAME_LENGTH-1] != L'\0')
  127. {
  128. TRACE_RELEASE_WRITELOCK(lpserver);
  129. return INVALID_TRACEID;
  130. }
  131. #endif
  132. if ((dwFlags & TRACE_USE_FILE) || (dwFlags & TRACE_USE_CONSOLE)) {
  133. if (dwFlags & TRACE_USE_FILE) {
  134. lpclient->TC_Flags |= TRACEFLAGS_USEFILE;
  135. }
  136. if (dwFlags & TRACE_USE_CONSOLE) {
  137. lpclient->TC_Flags |= TRACEFLAGS_USECONSOLE;
  138. }
  139. }
  140. else {
  141. lpclient->TC_Flags |= TRACEFLAGS_REGCONFIG;
  142. }
  143. //
  144. // load client's configuration and open its file
  145. // and its console buffer if necessary
  146. //
  147. dwErr = TraceEnableClient(lpserver, lpclient, TRUE);
  148. if (dwErr != 0) {
  149. //
  150. // something wrong, so abort
  151. //
  152. TraceDeleteClient(lpserver, lplpc);
  153. TRACE_RELEASE_WRITELOCK(lpserver);
  154. return INVALID_TRACEID;
  155. }
  156. //
  157. // Create trace server thread if required
  158. //
  159. if (g_serverThread==NULL) {
  160. dwErr = TraceCreateServerThread(dwFlags, TRUE,TRUE); //have lock,check
  161. if (NO_ERROR != dwErr){
  162. TRACE_RELEASE_WRITELOCK(lpserver);
  163. return INVALID_TRACEID;
  164. }
  165. }
  166. TRACE_RELEASE_WRITELOCK(lpserver);
  167. //
  168. // tell server there is a new client in the table
  169. //
  170. SetEvent(lpserver->TS_TableEvent);
  171. return (dwClientID ^ CLIENT_SIGNATURE);
  172. }
  173. DWORD
  174. APIENTRY
  175. TraceDeregisterEx(
  176. IN DWORD dwTraceID,
  177. IN DWORD dwFlags
  178. );
  179. //
  180. // called to stop tracing.
  181. // frees client state and notifies server of change
  182. //
  183. DWORD
  184. APIENTRY
  185. TraceDeregister(
  186. IN DWORD dwTraceID
  187. ) {
  188. return TraceDeregisterEx(dwTraceID, 0);
  189. }
  190. DWORD
  191. APIENTRY
  192. TraceDeregisterEx(
  193. IN DWORD dwTraceID,
  194. IN DWORD dwFlags
  195. ) {
  196. DWORD dwErr;
  197. LPTRACE_CLIENT *lplpc;
  198. LPTRACE_SERVER lpserver;
  199. // check for uninitialized traceregister.
  200. if (dwTraceID == 0 || dwTraceID == INVALID_TRACEID)
  201. {
  202. ASSERT(TRUE);
  203. return ERROR_INVALID_PARAMETER;
  204. }
  205. dwTraceID ^= CLIENT_SIGNATURE;
  206. if (dwTraceID >= MAX_CLIENT_COUNT) {
  207. return ERROR_INVALID_PARAMETER;
  208. }
  209. lpserver = GET_TRACE_SERVER_NO_INIT ();
  210. if (lpserver==NULL) // rtutils being unloaded bug.
  211. return 0;
  212. if (!ENTER_TRACE_API(lpserver)) { return ERROR_CAN_NOT_COMPLETE; }
  213. //
  214. // lock the server, unless the flag says not to.
  215. //
  216. if (!(dwFlags & TRACE_NO_SYNCH)) { TRACE_ACQUIRE_WRITELOCK(lpserver); }
  217. //
  218. // get the client pointer
  219. //
  220. lplpc = lpserver->TS_ClientTable + dwTraceID;
  221. dwErr = TraceDeleteClient(lpserver, lplpc);
  222. //
  223. // reset array for client change notifications.
  224. // only used if server thread is not created
  225. //
  226. if (!g_serverThread) {
  227. SetWaitArray(lpserver);
  228. }
  229. if (!(dwFlags & TRACE_NO_SYNCH)) { TRACE_RELEASE_WRITELOCK(lpserver); }
  230. //
  231. // tell the server that a client has left
  232. //
  233. SetEvent(lpserver->TS_TableEvent);
  234. return 0;
  235. }
  236. DWORD
  237. APIENTRY
  238. TraceGetConsole(
  239. IN DWORD dwTraceID,
  240. OUT LPHANDLE lphConsole
  241. ) {
  242. LPTRACE_CLIENT lpclient;
  243. LPTRACE_SERVER lpserver;
  244. // check for uninitialized traceregister.
  245. if (dwTraceID == 0 || dwTraceID == INVALID_TRACEID)
  246. {
  247. ASSERT(TRUE);
  248. return ERROR_INVALID_PARAMETER;
  249. }
  250. dwTraceID ^= CLIENT_SIGNATURE;
  251. if (dwTraceID >= MAX_CLIENT_COUNT ||
  252. lphConsole == NULL) {
  253. return ERROR_INVALID_PARAMETER;
  254. }
  255. lpserver = GET_TRACE_SERVER_NO_INIT ();
  256. ASSERTMSG ("Server not initialized ", lpserver);
  257. if (!ENTER_TRACE_API(lpserver)) { return ERROR_CAN_NOT_COMPLETE; }
  258. *lphConsole = NULL;
  259. TRACE_ACQUIRE_READLOCK(lpserver);
  260. lpclient = lpserver->TS_ClientTable[dwTraceID];
  261. if (lpclient == NULL) {
  262. TRACE_RELEASE_READLOCK(lpserver);
  263. return ERROR_INVALID_PARAMETER;
  264. }
  265. TRACE_ACQUIRE_READLOCK(lpclient);
  266. *lphConsole = lpclient->TC_Console;
  267. TRACE_RELEASE_READLOCK(lpclient);
  268. TRACE_RELEASE_READLOCK(lpserver);
  269. return 0;
  270. }
  271. DWORD
  272. APIENTRY
  273. TracePrintf(
  274. IN DWORD dwTraceID,
  275. IN LPCTSTR lpszFormat,
  276. IN ... OPTIONAL
  277. ) {
  278. DWORD dwSize;
  279. va_list arglist;
  280. // check for uninitialized traceregister.
  281. if (dwTraceID == 0 || dwTraceID == INVALID_TRACEID)
  282. {
  283. ASSERT(TRUE);
  284. return ERROR_INVALID_PARAMETER;
  285. }
  286. dwTraceID ^= CLIENT_SIGNATURE;
  287. if (dwTraceID >= MAX_CLIENT_COUNT) {
  288. return 0;
  289. }
  290. if (lpszFormat==NULL)
  291. return 0;
  292. CREATE_SERVER_THREAD_IF_REQUIRED();
  293. va_start(arglist, lpszFormat);
  294. dwSize = TraceVprintfInternal(dwTraceID, 0, lpszFormat, arglist);
  295. va_end(arglist);
  296. return dwSize;
  297. }
  298. DWORD
  299. APIENTRY
  300. TracePrintfEx(
  301. IN DWORD dwTraceID,
  302. IN DWORD dwFlags,
  303. IN LPCTSTR lpszFormat,
  304. IN ... OPTIONAL
  305. ) {
  306. DWORD dwSize;
  307. va_list arglist;
  308. // check for uninitialized traceregister.
  309. if (dwTraceID == 0 || dwTraceID == INVALID_TRACEID)
  310. {
  311. ASSERT(TRUE);
  312. return ERROR_INVALID_PARAMETER;
  313. }
  314. dwTraceID ^= CLIENT_SIGNATURE;
  315. if (dwTraceID >= MAX_CLIENT_COUNT) {
  316. return 0;
  317. }
  318. if (lpszFormat==NULL)
  319. return 0;
  320. CREATE_SERVER_THREAD_IF_REQUIRED();
  321. va_start(arglist, lpszFormat);
  322. dwSize = TraceVprintfInternal(dwTraceID, dwFlags, lpszFormat, arglist);
  323. va_end(arglist);
  324. return dwSize;
  325. }
  326. DWORD
  327. APIENTRY
  328. TraceVprintfEx(
  329. IN DWORD dwTraceID,
  330. IN DWORD dwFlags,
  331. IN LPCTSTR lpszFormat,
  332. IN va_list arglist
  333. ) {
  334. // check for uninitialized traceregister.
  335. if (dwTraceID == 0 || dwTraceID == INVALID_TRACEID)
  336. {
  337. ASSERT(TRUE);
  338. return ERROR_INVALID_PARAMETER;
  339. }
  340. dwTraceID ^= CLIENT_SIGNATURE;
  341. if (dwTraceID >= MAX_CLIENT_COUNT) {
  342. return 0;
  343. }
  344. if (lpszFormat==NULL)
  345. return 0;
  346. CREATE_SERVER_THREAD_IF_REQUIRED();
  347. return TraceVprintfInternal(dwTraceID, dwFlags, lpszFormat, arglist);
  348. }
  349. /*
  350. Note: return 0 if error. do not return error code
  351. */
  352. DWORD
  353. TraceVprintfInternal(
  354. IN DWORD dwTraceID,
  355. IN DWORD dwFlags,
  356. IN LPCTSTR lpszFormat,
  357. IN va_list arglist
  358. ) {
  359. SYSTEMTIME st;
  360. DWORD dwThread;
  361. DWORD dwErr=NO_ERROR, dwSize=0;
  362. HRESULT hrResult=S_OK;
  363. LPTRACE_CLIENT lpclient;
  364. LPTRACE_SERVER lpserver;
  365. PTCHAR szFormat, szBuffer;
  366. BOOL bFormatBufferGlobal=FALSE, bPrintBufferGlobal = FALSE;
  367. if (lpszFormat==NULL)
  368. return 0;
  369. lpserver = GET_TRACE_SERVER_NO_INIT ();
  370. if (lpserver==NULL) // rtutils being unloaded bug.
  371. return 0;
  372. ASSERTMSG ("Server not initialized ", lpserver);
  373. if (!ENTER_TRACE_API(lpserver)) { return 0; }
  374. //
  375. // return quickly if no output will be generated;
  376. //
  377. if (dwFlags & TRACE_USE_MASK) {
  378. if (!(*(lpserver->TS_FlagsCache + dwTraceID) & (dwFlags & 0xffff0000))) {
  379. return 0;
  380. }
  381. }
  382. else {
  383. if (!*(lpserver->TS_FlagsCache + dwTraceID)) {
  384. return 0;
  385. }
  386. }
  387. TRACE_ACQUIRE_READLOCK(lpserver);
  388. lpclient = lpserver->TS_ClientTable[dwTraceID];
  389. if (lpclient == NULL) {
  390. TRACE_RELEASE_READLOCK(lpserver);
  391. return 0;
  392. }
  393. TRACE_ACQUIRE_READLOCK(lpclient);
  394. if (TRACE_CLIENT_IS_DISABLED(lpclient)) {
  395. TRACE_RELEASE_READLOCK(lpclient);
  396. TRACE_RELEASE_READLOCK(lpserver);
  397. return 0;
  398. }
  399. if (szFormat = InterlockedExchangePointer(&g_FormatBuffer, NULL))
  400. {
  401. bFormatBufferGlobal = TRUE;
  402. }
  403. else
  404. {
  405. szFormat = (PTCHAR) HeapAlloc(GetProcessHeap(), 0, DEF_PRINT_BUFSIZE);
  406. if (!szFormat) {
  407. TRACE_RELEASE_READLOCK(lpclient);
  408. TRACE_RELEASE_READLOCK(lpserver);
  409. return 0;
  410. }
  411. }
  412. if (szBuffer = InterlockedExchangePointer(&g_PrintBuffer, NULL))
  413. {
  414. bPrintBufferGlobal = TRUE;
  415. }
  416. else
  417. {
  418. szBuffer = (PTCHAR) HeapAlloc(GetProcessHeap(), 0, DEF_PRINT_BUFSIZE);
  419. if (!szBuffer) {
  420. TRACE_RELEASE_READLOCK(lpclient);
  421. TRACE_RELEASE_READLOCK(lpserver);
  422. if (!bFormatBufferGlobal)
  423. HeapFree(GetProcessHeap(), 0, szFormat);
  424. else
  425. InterlockedExchangePointer(&g_FormatBuffer, szFormat);
  426. return 0;
  427. }
  428. }
  429. //
  430. // default format for output is
  431. // \n<time>:
  432. //
  433. if (dwFlags & TRACE_NO_STDINFO) {
  434. hrResult = StringCbVPrintf(szBuffer, DEF_PRINT_BUFSIZE, lpszFormat, arglist);
  435. if (FAILED(hrResult))
  436. dwErr = HRESULT_CODE(hrResult);
  437. }
  438. else {
  439. GetLocalTime(&st);
  440. if ((dwFlags & TRACE_USE_MSEC) == 0) {
  441. if (dwFlags & TRACE_USE_DATE) {
  442. hrResult = StringCbPrintf(
  443. szFormat, DEF_PRINT_BUFSIZE,
  444. TEXT("\r\n[%03d] %02u-%02u %02u:%02u:%02u: %s"),
  445. GetCurrentThreadId(), st.wMonth, st.wDay, st.wHour,
  446. st.wMinute, st.wSecond,
  447. lpszFormat
  448. );
  449. }
  450. else {
  451. hrResult = StringCbPrintf(
  452. szFormat, DEF_PRINT_BUFSIZE,
  453. TEXT("\r\n[%03d] %02u:%02u:%02u: %s") ,
  454. GetCurrentThreadId(), st.wHour, st.wMinute, st.wSecond,
  455. lpszFormat
  456. );
  457. }
  458. }
  459. else {
  460. if (dwFlags & TRACE_USE_DATE) {
  461. hrResult = StringCbPrintf(
  462. szFormat, DEF_PRINT_BUFSIZE,
  463. TEXT("\r\n[%03d] %02u-%02u %02u:%02u:%02u:%03u: %s") ,
  464. GetCurrentThreadId(), st.wMonth, st.wDay,
  465. st.wHour, st.wMinute, st.wSecond,
  466. st.wMilliseconds, lpszFormat
  467. );
  468. }
  469. else {
  470. hrResult = StringCbPrintf(
  471. szFormat, DEF_PRINT_BUFSIZE,
  472. TEXT("\r\n[%03d] %02u:%02u:%02u:%03u: %s") ,
  473. GetCurrentThreadId(), st.wHour, st.wMinute, st.wSecond,
  474. st.wMilliseconds, lpszFormat
  475. );
  476. }
  477. }
  478. if (FAILED(hrResult))
  479. dwErr = HRESULT_CODE(hrResult);
  480. if (dwErr == NO_ERROR)
  481. {
  482. hrResult = StringCbVPrintf(szBuffer, DEF_PRINT_BUFSIZE, szFormat, arglist);
  483. if (FAILED(hrResult))
  484. dwErr = HRESULT_CODE(hrResult);
  485. }
  486. }
  487. if (dwErr == NO_ERROR)
  488. dwSize = TraceWriteOutput(lpserver, lpclient, dwFlags, szBuffer);
  489. TRACE_RELEASE_READLOCK(lpclient);
  490. TRACE_RELEASE_READLOCK(lpserver);
  491. if (bFormatBufferGlobal)
  492. {
  493. InterlockedExchangePointer(&g_FormatBuffer, szFormat);
  494. }
  495. else
  496. {
  497. HeapFree(GetProcessHeap(), 0, szFormat);
  498. }
  499. if (bPrintBufferGlobal)
  500. {
  501. InterlockedExchangePointer(&g_PrintBuffer, szBuffer);
  502. }
  503. else
  504. {
  505. HeapFree(GetProcessHeap(), 0, szBuffer);
  506. }
  507. return dwSize;
  508. }
  509. DWORD
  510. APIENTRY
  511. TracePutsEx(
  512. IN DWORD dwTraceID,
  513. IN DWORD dwFlags,
  514. IN LPCTSTR lpszString
  515. ) {
  516. SYSTEMTIME st;
  517. DWORD dwErr=NO_ERROR, dwSize;
  518. HRESULT hrResult=S_OK;
  519. LPTRACE_CLIENT lpclient;
  520. LPTRACE_SERVER lpserver;
  521. LPCTSTR lpszOutput;
  522. PTCHAR szBuffer;
  523. // check for uninitialized traceregister.
  524. if (dwTraceID == 0 || dwTraceID == INVALID_TRACEID)
  525. {
  526. ASSERT(TRUE);
  527. return ERROR_INVALID_PARAMETER;
  528. }
  529. dwTraceID ^= CLIENT_SIGNATURE;
  530. if (dwTraceID >= MAX_CLIENT_COUNT) {
  531. return 0;
  532. }
  533. if (lpszString==NULL)
  534. return 0;
  535. lpserver = GET_TRACE_SERVER_NO_INIT ();
  536. if (lpserver==NULL) // rtutils being unloaded bug.
  537. return 0;
  538. ASSERTMSG ("Server not initialized ", lpserver);
  539. if (!ENTER_TRACE_API(lpserver)) { return ERROR_CAN_NOT_COMPLETE; }
  540. CREATE_SERVER_THREAD_IF_REQUIRED();
  541. //
  542. // return quickly if no output will be generated;
  543. //
  544. if (dwFlags & TRACE_USE_MASK) {
  545. if (!(*(lpserver->TS_FlagsCache + dwTraceID) & (dwFlags & 0xffff0000))) {
  546. return 0;
  547. }
  548. }
  549. else {
  550. if (!*(lpserver->TS_FlagsCache + dwTraceID)) { return 0; }
  551. }
  552. TRACE_ACQUIRE_READLOCK(lpserver);
  553. lpclient = lpserver->TS_ClientTable[dwTraceID];
  554. if (lpclient == NULL) {
  555. TRACE_RELEASE_READLOCK(lpserver);
  556. return 0;
  557. }
  558. TRACE_ACQUIRE_READLOCK(lpclient);
  559. if (TRACE_CLIENT_IS_DISABLED(lpclient)) {
  560. TRACE_RELEASE_READLOCK(lpclient);
  561. TRACE_RELEASE_READLOCK(lpserver);
  562. return 0;
  563. }
  564. szBuffer = (PTCHAR) HeapAlloc(GetProcessHeap(), 0, DEF_PRINT_BUFSIZE);
  565. if (!szBuffer) {
  566. TRACE_RELEASE_READLOCK(lpclient);
  567. TRACE_RELEASE_READLOCK(lpserver);
  568. return ERROR_NOT_ENOUGH_MEMORY;
  569. }
  570. if (dwFlags & TRACE_NO_STDINFO) {
  571. lpszOutput = lpszString;
  572. }
  573. else {
  574. GetLocalTime(&st);
  575. if ((dwFlags & TRACE_USE_MSEC) == 0) {
  576. if (dwFlags & TRACE_USE_DATE) {
  577. hrResult = StringCbPrintf(
  578. szBuffer, DEF_PRINT_BUFSIZE,
  579. TEXT("\r\n[%03d] %02u-%02u %02u:%02u:%02u: %s") ,
  580. GetCurrentThreadId(), st.wMonth, st.wDay,
  581. st.wHour, st.wMinute, st.wSecond,
  582. lpszString
  583. );
  584. }
  585. else {
  586. hrResult = StringCbPrintf(
  587. szBuffer, DEF_PRINT_BUFSIZE,
  588. TEXT("\r\n[%03d] %02u:%02u:%02u: %s"),
  589. GetCurrentThreadId(), st.wHour, st.wMinute, st.wSecond,
  590. lpszString
  591. );
  592. }
  593. }
  594. else {
  595. if (dwFlags & TRACE_USE_DATE) {
  596. hrResult = StringCbPrintf(
  597. szBuffer, DEF_PRINT_BUFSIZE,
  598. TEXT("\r\n[%03d] %02u-%02u %02u:%02u:%02u:%03u: %s") ,
  599. GetCurrentThreadId(), st.wMonth, st.wDay,
  600. st.wHour, st.wMinute, st.wSecond,
  601. st.wMilliseconds, lpszString
  602. );
  603. }
  604. else {
  605. hrResult = StringCbPrintf(
  606. szBuffer, DEF_PRINT_BUFSIZE,
  607. TEXT("\r\n[%03d] %02u:%02u:%02u:%03u: %s"),
  608. GetCurrentThreadId(), st.wHour, st.wMinute, st.wSecond,
  609. st.wMilliseconds, lpszString
  610. );
  611. }
  612. }
  613. lpszOutput = szBuffer;
  614. }
  615. if (FAILED(hrResult))
  616. dwErr = HRESULT_CODE(hrResult);
  617. if (dwErr == NO_ERROR)
  618. {
  619. dwSize = TraceWriteOutput(lpserver, lpclient, dwFlags, lpszOutput);
  620. }
  621. HeapFree(GetProcessHeap(), 0, szBuffer);
  622. TRACE_RELEASE_READLOCK(lpclient);
  623. TRACE_RELEASE_READLOCK(lpserver);
  624. return dwErr==NO_ERROR? dwSize : 0;
  625. }
  626. DWORD
  627. APIENTRY
  628. TraceDumpEx(
  629. IN DWORD dwTraceID,
  630. IN DWORD dwFlags,
  631. IN LPBYTE lpbBytes,
  632. IN DWORD dwByteCount,
  633. IN DWORD dwGroupSize,
  634. IN BOOL bAddressPrefix,
  635. IN LPCTSTR lpszPrefix
  636. ) {
  637. SYSTEMTIME st;
  638. DWORD dwThread;
  639. LPTRACE_SERVER lpserver;
  640. LPTRACE_CLIENT lpclient;
  641. DWORD dwBytesOutput;
  642. TCHAR szPrefix[MAX_CLIENTNAME_LENGTH + 48] = TEXT("");
  643. BYTE szBuffer[BYTES_PER_DUMPLINE];
  644. DWORD dwErr = NO_ERROR;
  645. HRESULT hrResult = S_OK;
  646. // check for uninitialized traceregister.
  647. if (dwTraceID == 0 || dwTraceID == INVALID_TRACEID)
  648. {
  649. ASSERT(TRUE);
  650. return ERROR_INVALID_PARAMETER;
  651. }
  652. dwTraceID ^= CLIENT_SIGNATURE;
  653. if (dwTraceID >= MAX_CLIENT_COUNT ||
  654. lpbBytes == NULL ||
  655. dwByteCount == 0 ||
  656. (dwGroupSize != 1 && dwGroupSize != 2 && dwGroupSize != 4)
  657. ) {
  658. return ERROR_INVALID_PARAMETER;
  659. }
  660. lpserver = GET_TRACE_SERVER_NO_INIT ();
  661. if (lpserver==NULL) // rtutils being unloaded bug.
  662. return 0;
  663. ASSERTMSG ("Server not initialized ", lpserver);
  664. if (!ENTER_TRACE_API(lpserver)) { return ERROR_CAN_NOT_COMPLETE; }
  665. CREATE_SERVER_THREAD_IF_REQUIRED();
  666. //
  667. // return quickly if no output will be generated;
  668. //
  669. if (dwFlags & TRACE_USE_MASK) {
  670. if (!(*(lpserver->TS_FlagsCache + dwTraceID) & (dwFlags & 0xffff0000))) {
  671. return 0;
  672. }
  673. }
  674. else {
  675. if (!*(lpserver->TS_FlagsCache + dwTraceID)) { return 0; }
  676. }
  677. TRACE_ACQUIRE_READLOCK(lpserver);
  678. lpclient = lpserver->TS_ClientTable[dwTraceID];
  679. if (lpclient == NULL) {
  680. TRACE_RELEASE_READLOCK(lpserver);
  681. return 0;
  682. }
  683. TRACE_ACQUIRE_READLOCK(lpclient);
  684. if (TRACE_CLIENT_IS_DISABLED(lpclient)) {
  685. TRACE_RELEASE_READLOCK(lpclient);
  686. TRACE_RELEASE_READLOCK(lpserver);
  687. return 0;
  688. }
  689. dwBytesOutput = 0;
  690. if ((dwFlags & TRACE_NO_STDINFO) == 0) {
  691. GetLocalTime(&st);
  692. if ((dwFlags & TRACE_USE_MSEC) == 0) {
  693. hrResult = StringCchPrintf(
  694. szPrefix, MAX_CLIENTNAME_LENGTH + 48,
  695. TEXT("[%03d] %02u:%02u:%02u: "),
  696. GetCurrentThreadId(), st.wHour, st.wMinute, st.wSecond
  697. );
  698. }
  699. else {
  700. hrResult = StringCchPrintf(
  701. szPrefix, MAX_CLIENTNAME_LENGTH + 48,
  702. TEXT("[%03d] %02u:%02u:%02u:%03u: "),
  703. GetCurrentThreadId(), st.wHour, st.wMinute, st.wSecond,
  704. st.wMilliseconds
  705. );
  706. }
  707. if (FAILED(hrResult))
  708. {
  709. TRACE_RELEASE_READLOCK(lpclient);
  710. TRACE_RELEASE_READLOCK(lpserver);
  711. return 0;
  712. }
  713. }
  714. if (lpszPrefix != NULL) {
  715. hrResult = StringCchCat(szPrefix, MAX_CLIENTNAME_LENGTH + 48, lpszPrefix);
  716. if (FAILED(hrResult))
  717. {
  718. TRACE_RELEASE_READLOCK(lpclient);
  719. TRACE_RELEASE_READLOCK(lpserver);
  720. return 0;
  721. }
  722. }
  723. //
  724. // see if the start of the byte buffer is not aligned correctly
  725. // on a DWORD boundary
  726. //
  727. if ((ULONG_PTR)lpbBytes & (dwGroupSize - 1)) {
  728. DWORD dwPad;
  729. //
  730. // it is, so first dump the leading bytes:
  731. // get size of misalignment, and make certain
  732. // misalignment size isn't greater than total size
  733. //
  734. dwPad = (DWORD) ((ULONG_PTR)lpbBytes & (dwGroupSize - 1));
  735. dwPad = (dwPad > dwByteCount) ? dwByteCount : dwPad;
  736. //
  737. // copy the misaligned bytes into the buffer
  738. //
  739. ZeroMemory(szBuffer, BYTES_PER_DUMPLINE);
  740. CopyMemory(szBuffer + (BYTES_PER_DUMPLINE - dwPad), lpbBytes, dwPad);
  741. //
  742. // now dump the line, but give the helper function a pointer
  743. // to the byte buffer passed in as an argument
  744. // to print as the prefix (actually, give it the place
  745. // in the real byte buffer that it would be dumping from
  746. // if things weren't misaligned
  747. //
  748. dwBytesOutput +=
  749. TraceDumpLine(
  750. lpserver, lpclient, dwFlags, szBuffer, BYTES_PER_DUMPLINE, dwGroupSize,
  751. bAddressPrefix,
  752. (LPBYTE) ((ULONG_PTR)lpbBytes - (BYTES_PER_DUMPLINE - dwPad)), szPrefix
  753. );
  754. (ULONG_PTR)lpbBytes += dwPad;
  755. dwByteCount -= dwPad;
  756. }
  757. //
  758. // now loop through until we can't print out any more
  759. //
  760. while (dwByteCount > 0) {
  761. //
  762. // there is a line or more left in the buffer
  763. // no special processing needed
  764. //
  765. if (dwByteCount >= BYTES_PER_DUMPLINE) {
  766. dwBytesOutput +=
  767. TraceDumpLine(
  768. lpserver, lpclient, dwFlags, lpbBytes, BYTES_PER_DUMPLINE,
  769. dwGroupSize,
  770. bAddressPrefix, lpbBytes, szPrefix
  771. );
  772. lpbBytes += BYTES_PER_DUMPLINE;
  773. dwByteCount -= BYTES_PER_DUMPLINE;
  774. }
  775. else {
  776. //
  777. // for the last line, copy the stuff to a buffer and then
  778. // print that buffer's contents, passing the argument buffer
  779. // as the address to use as a prefix
  780. //
  781. ZeroMemory(szBuffer, BYTES_PER_DUMPLINE);
  782. CopyMemory(szBuffer, lpbBytes, dwByteCount);
  783. dwBytesOutput +=
  784. TraceDumpLine(
  785. lpserver, lpclient, dwFlags, szBuffer, BYTES_PER_DUMPLINE,
  786. dwGroupSize, bAddressPrefix, lpbBytes, szPrefix
  787. );
  788. lpbBytes += BYTES_PER_DUMPLINE;
  789. dwByteCount = 0;
  790. }
  791. }
  792. TRACE_RELEASE_READLOCK(lpclient);
  793. TRACE_RELEASE_READLOCK(lpserver);
  794. return dwBytesOutput;
  795. }