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.

682 lines
19 KiB

  1. #define _UNICODE
  2. #define UNICODE
  3. #include <nt.h>
  4. #include <ntrtl.h>
  5. #include <nturtl.h>
  6. #include <windows.h>
  7. #include <stdio.h>
  8. #pragma warning(disable: 4201) // error C4201: nonstandard extension used : nameless struct/union
  9. #include <wmistr.h>
  10. #include <evntrace.h>
  11. #include <guiddef.h>
  12. #define REG_TRACE_REGKEY TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Tracing")
  13. #define REG_TRACE_ENABLED TEXT("EnableTracing")
  14. #define REG_TRACE_LOG_FILE_NAME TEXT("LogFileName")
  15. #define REG_TRACE_LOG_SESSION_NAME TEXT("LogSessionName")
  16. #define REG_TRACE_LOG_BUFFER_SIZE TEXT("BufferSize")
  17. #define REG_TRACE_LOG_MIN_BUFFERS TEXT("MinBuffers")
  18. #define REG_TRACE_LOG_MAX_BUFFERS TEXT("MaxBuffers")
  19. #define REG_TRACE_LOG_MAX_FILESIZE TEXT("MaxFileSize")
  20. #define REG_TRACE_LOG_MAX_HISTORY TEXT("MaxHistorySize")
  21. #define REG_TRACE_LOG_MAX_BACKUPS TEXT("MaxBackups")
  22. #define REG_TRACE_ACTIVE TEXT("Active")
  23. #define REG_TRACE_CONTROL TEXT("ControlFlags")
  24. #define REG_TRACE_LEVEL TEXT("Level")
  25. #define REG_TRACE_GUID TEXT("Guid")
  26. #include "wmlum.h"
  27. #ifndef ARRAYSIZE
  28. #define ARRAYSIZE(x) (sizeof(x)/sizeof(*(x)))
  29. #endif
  30. VOID RegisterIfNecessary(LPWSTR KeyName, LPCGUID Guid);
  31. WMILIBPRINTFUNC WmiLibPrint = 0;
  32. #define NT_LOGGER L"NT Kernel Logger"
  33. VOID
  34. MyDbgPrint(
  35. UINT Level,
  36. PCHAR FormatString,
  37. ...
  38. )
  39. /*++
  40. Routine Description:
  41. Prints a message to the debugger or console, as appropriate.
  42. Arguments:
  43. String - The initial message string to print.
  44. Any FormatMessage-compatible arguments to be inserted in the
  45. ErrorMessage before it is logged.
  46. Return Value:
  47. None.
  48. --*/
  49. {
  50. CHAR Buffer[256];
  51. DWORD Bytes;
  52. va_list ArgList;
  53. if (WmiLibPrint == NULL) {
  54. return;
  55. }
  56. va_start(ArgList, FormatString);
  57. Bytes = FormatMessageA(FORMAT_MESSAGE_FROM_STRING,
  58. FormatString,
  59. 0,
  60. 0,
  61. Buffer,
  62. sizeof(Buffer) / sizeof(CHAR),
  63. &ArgList);
  64. va_end(ArgList);
  65. if (Bytes != 0) {
  66. (*WmiLibPrint)(Level, Buffer);
  67. }
  68. }
  69. UINT HexVal(int ch) { return isdigit(ch) ? ch - '0' : ch - 'a' + 10; }
  70. UINT Hex(LPWSTR s, int n)
  71. {
  72. UINT res = 0;
  73. while(n--) { res = res * 16 + HexVal(*s++); }
  74. return res;
  75. }
  76. VOID
  77. GuidFromStr(
  78. IN LPWSTR str,
  79. OUT LPGUID guid)
  80. {
  81. guid->Data1 = Hex(str + 0, 8);
  82. guid->Data2 = (USHORT)Hex(str + 9, 4);
  83. guid->Data3 = (USHORT)Hex(str + 14, 4);
  84. guid->Data4[0] = (UCHAR) Hex(str + 19, 2);
  85. guid->Data4[1] = (UCHAR) Hex(str + 21, 2);
  86. guid->Data4[2] = (UCHAR) Hex(str + 24, 2);
  87. guid->Data4[3] = (UCHAR) Hex(str + 26, 2);
  88. guid->Data4[4] = (UCHAR) Hex(str + 28, 2);
  89. guid->Data4[5] = (UCHAR) Hex(str + 30, 2);
  90. guid->Data4[6] = (UCHAR) Hex(str + 32, 2);
  91. guid->Data4[7] = (UCHAR) Hex(str + 34, 2);
  92. }
  93. typedef struct _INHERITED_DATA {
  94. BOOL Active;
  95. ULONG ControlFlags;
  96. ULONG LogLevel;
  97. ULONG Reserved;
  98. TRACEHANDLE Logger;
  99. GUID Guid;
  100. BOOL GuidDefined;
  101. } INHERITED_DATA, *PINHERITED_DATA;
  102. VOID
  103. ReadCommonData(
  104. IN HKEY hk,
  105. IN OUT PINHERITED_DATA data
  106. )
  107. {
  108. ULONG ulTemp;
  109. ULONG dwSize;
  110. WCHAR szGuid[16 * 3 + 1];
  111. dwSize = sizeof(ulTemp);
  112. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_ACTIVE,
  113. NULL, NULL, (BYTE *) &ulTemp, &dwSize))
  114. {
  115. data->Active = ulTemp;
  116. }
  117. dwSize = sizeof(ulTemp);
  118. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_CONTROL,
  119. NULL, NULL,
  120. (BYTE *) &ulTemp, &dwSize))
  121. {
  122. data->ControlFlags = ulTemp;
  123. }
  124. dwSize = sizeof(ulTemp);
  125. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_LEVEL,
  126. NULL, NULL,
  127. (BYTE *) &ulTemp,
  128. &dwSize))
  129. {
  130. data->LogLevel = ulTemp;
  131. }
  132. dwSize = sizeof(szGuid);
  133. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_GUID,
  134. NULL, NULL,
  135. (BYTE *) &szGuid,
  136. &dwSize))
  137. {
  138. GuidFromStr(szGuid, &data->Guid);
  139. data->GuidDefined = TRUE;
  140. }
  141. return;
  142. }
  143. typedef struct _FULL_LOGGER_INFO {
  144. EVENT_TRACE_PROPERTIES LoggerInfo;
  145. WCHAR logFileName[MAX_PATH + 512];
  146. WCHAR logSessionName[MAX_PATH + 512];
  147. ULONG MaxHistorySize;
  148. ULONG MaxBackups;
  149. } FULL_LOGGER_INFO, *PFULL_LOGGER_INFO;
  150. GUID MySystemTraceControlGuid = { /* 9e814aad-3204-11d2-9a82-006008a86939 */
  151. 0x9e814aad,
  152. 0x3204,
  153. 0x11d2,
  154. {0x9a, 0x82, 0x00, 0x60, 0x08, 0xa8, 0x69, 0x39}
  155. };
  156. VOID
  157. ReadLoggerInfo(
  158. IN HKEY hk,
  159. OUT PTRACEHANDLE Logger)
  160. {
  161. FULL_LOGGER_INFO x;
  162. WCHAR tmpName[MAX_PATH + 512];
  163. WCHAR tmpName2[MAX_PATH + 512];
  164. ULONG ulTemp;
  165. ULONG dwReadSize = sizeof(ulTemp);
  166. ULONG status;
  167. SYSTEMTIME localTime;
  168. BOOL success;
  169. RtlZeroMemory(&x.LoggerInfo, sizeof(x));
  170. x.LoggerInfo.Wnode.BufferSize = sizeof(x);
  171. x.LoggerInfo.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  172. x.LoggerInfo.LogFileNameOffset = (ULONG)((ULONG_PTR)x.logFileName - (ULONG_PTR)&x);
  173. x.LoggerInfo.LoggerNameOffset = (ULONG)((ULONG_PTR)x.logSessionName - (ULONG_PTR)&x);
  174. x.LoggerInfo.LogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR;
  175. //
  176. // If the key describes a logger,
  177. // it should have at least LOG_SESSION_NAME value
  178. //
  179. dwReadSize = sizeof(x.logSessionName);
  180. status = RegQueryValueEx(hk, REG_TRACE_LOG_SESSION_NAME,
  181. NULL, NULL,
  182. (BYTE *) &x.logSessionName, &dwReadSize);
  183. if (status != ERROR_SUCCESS) {
  184. return;
  185. }
  186. if ( wcscmp(x.logSessionName, NT_LOGGER) == 0) {
  187. MyDbgPrint(3,"[WMILIB] Enabling system tracing\n",
  188. x.logSessionName,
  189. x.LoggerInfo.Wnode.HistoricalContext);
  190. x.LoggerInfo.Wnode.Guid = MySystemTraceControlGuid;
  191. x.LoggerInfo.EnableFlags |=
  192. EVENT_TRACE_FLAG_PROCESS |
  193. EVENT_TRACE_FLAG_THREAD |
  194. EVENT_TRACE_FLAG_DISK_IO |
  195. EVENT_TRACE_FLAG_NETWORK_TCPIP |
  196. EVENT_TRACE_FLAG_REGISTRY;
  197. }
  198. // Let's query, whether there is a logger with this name
  199. status = QueryTrace(0, x.logSessionName, &x.LoggerInfo);
  200. if (ERROR_SUCCESS == status) {
  201. MyDbgPrint(1,"[WMILIB] Query successful Logger %1!ws! %2!08X!:%3!08X!\n",
  202. x.logSessionName,
  203. x.LoggerInfo.Wnode.HistoricalContext);
  204. *Logger = x.LoggerInfo.Wnode.HistoricalContext;
  205. return;
  206. }
  207. if (ERROR_WMI_INSTANCE_NOT_FOUND != status) {
  208. MyDbgPrint(1,"[WMILIB] Query of %1!ws! failed %2!d!\n",
  209. x.logSessionName, status);
  210. }
  211. // There is no logger runing
  212. // First, We will query logFileName value into tmpName variable
  213. // and then expand it into logFileName
  214. dwReadSize = sizeof(tmpName);
  215. status = RegQueryValueEx(hk, REG_TRACE_LOG_FILE_NAME,
  216. NULL, NULL,
  217. (BYTE *) &tmpName, &dwReadSize);
  218. if (status != ERROR_SUCCESS) {
  219. // If there is no logFileName, then this node doesn't describe
  220. // a logger. Bail out.
  221. MyDbgPrint(1,"[WMILIB] Cannot read log file name, status %1!d!\n", status);
  222. return;
  223. }
  224. dwReadSize = ExpandEnvironmentStrings(tmpName, x.logFileName, ARRAYSIZE(x.logFileName) );
  225. if (dwReadSize == 0 || dwReadSize > ARRAYSIZE(x.logFileName)) {
  226. MyDbgPrint(1,"[WMILIB] Expansion of %1!ws! failed, return value %2!d!\n", tmpName, dwReadSize);
  227. CopyMemory(x.logFileName, tmpName, sizeof(x.logFileName));
  228. }
  229. MyDbgPrint(3,"[WMILIB] FileName %1!S!\n", x.logFileName);
  230. MyDbgPrint(3,"[WMILIB] Session %1!S!\n", x.logSessionName);
  231. dwReadSize = sizeof(ulTemp);
  232. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_LOG_BUFFER_SIZE,
  233. NULL, NULL,
  234. (BYTE *) &ulTemp, &dwReadSize))
  235. x.LoggerInfo.BufferSize = ulTemp;
  236. dwReadSize = sizeof(ulTemp);
  237. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_LOG_MIN_BUFFERS,
  238. NULL, NULL,
  239. (BYTE *) &ulTemp, &dwReadSize))
  240. x.LoggerInfo.MinimumBuffers = ulTemp;
  241. dwReadSize = sizeof(ulTemp);
  242. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_LOG_MAX_BUFFERS,
  243. NULL, NULL,
  244. (BYTE *) &ulTemp, &dwReadSize))
  245. x.LoggerInfo.MaximumBuffers = ulTemp;
  246. dwReadSize = sizeof(ulTemp);
  247. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_LOG_MAX_FILESIZE,
  248. NULL, NULL,
  249. (BYTE *) &ulTemp, &dwReadSize))
  250. x.LoggerInfo.MaximumFileSize = ulTemp;
  251. x.MaxHistorySize = 4 * x.LoggerInfo.MaximumFileSize;
  252. dwReadSize = sizeof(ulTemp);
  253. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_LOG_MAX_HISTORY,
  254. NULL, NULL,
  255. (BYTE *) &ulTemp, &dwReadSize))
  256. x.MaxHistorySize = ulTemp;
  257. dwReadSize = sizeof(ulTemp);
  258. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_LOG_MAX_BACKUPS,
  259. NULL, NULL,
  260. (BYTE *) &ulTemp, &dwReadSize))
  261. x.MaxBackups = ulTemp;
  262. if (x.MaxBackups == 0) {
  263. // We need to check whether the file already exist and rename it //
  264. GetLocalTime(&localTime);
  265. _snwprintf(tmpName, ARRAYSIZE(tmpName),
  266. L"%1ws.%04d%02d%02d%02d%02d%02d",
  267. x.logFileName,
  268. localTime.wYear,localTime.wMonth,localTime.wDay,
  269. localTime.wHour,localTime.wMinute,localTime.wSecond);
  270. success = MoveFile(x.logFileName, tmpName);
  271. if (!success) {
  272. status = GetLastError();
  273. } else {
  274. status = ERROR_SUCCESS;
  275. }
  276. MyDbgPrint(3,"[WMILIB] Rename %1!ws! => %2!ws!, status %3!d!\n",
  277. x.logFileName, tmpName, status);
  278. } else {
  279. int i;
  280. for (i = x.MaxBackups; i >= 1; --i) {
  281. _snwprintf(tmpName2, ARRAYSIZE(tmpName),
  282. L"%1ws.%03d",
  283. x.logFileName, i);
  284. if (i == 1) {
  285. wcscpy(tmpName, x.logFileName);
  286. } else {
  287. _snwprintf(tmpName, ARRAYSIZE(tmpName),
  288. L"%1ws.%03d",
  289. x.logFileName, i-1);
  290. }
  291. success = MoveFileEx(tmpName, tmpName2, MOVEFILE_REPLACE_EXISTING);
  292. if (!success) {
  293. status = GetLastError();
  294. } else {
  295. status = ERROR_SUCCESS;
  296. }
  297. MyDbgPrint(3,"[WMILIB] Rename %1!ws! => %2!ws!, status %3!d!\n",
  298. tmpName, tmpName2, status);
  299. }
  300. }
  301. status = StartTrace(Logger, x.logSessionName, &x.LoggerInfo);
  302. *Logger = x.LoggerInfo.Wnode.HistoricalContext;
  303. MyDbgPrint(1,"[WMILIB] Logger %1!ws! started %3!08X!:%4!08X! %2!d!\n",
  304. x.logSessionName, status, *Logger);
  305. }
  306. WCHAR szModuleName[MAX_PATH+500];
  307. ULONG
  308. InitWmiInternal(
  309. IN HKEY Dir OPTIONAL, // if 0, then current ...
  310. IN LPWSTR ProductName,
  311. IN PINHERITED_DATA InheritedData OPTIONAL
  312. )
  313. {
  314. ULONG status;
  315. INHERITED_DATA data;
  316. HKEY CloseMe = 0;
  317. HKEY hk = 0;
  318. //ULONG ulTemp;
  319. //ULONG dwReadSize = sizeof(ulTemp);
  320. DWORD dwSizeOfModuleName;
  321. DWORD dwIndex;
  322. MyDbgPrint(2, "[WMILIB] Init %1!ws!\n", ProductName);
  323. if (InheritedData) {
  324. data = *InheritedData;
  325. } else {
  326. ZeroMemory(&data, sizeof(data));
  327. }
  328. data.GuidDefined = FALSE;
  329. if (!Dir) {
  330. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  331. REG_TRACE_REGKEY,
  332. 0,
  333. KEY_READ,
  334. &CloseMe);
  335. if (status != ERROR_SUCCESS) {
  336. MyDbgPrint(1,"[WMILIB] Failed to open Trace Key, %1!d!\n", status);
  337. goto exit_gracefully;
  338. }
  339. Dir = CloseMe;
  340. }
  341. status = RegOpenKeyEx(Dir,
  342. ProductName,
  343. 0,
  344. KEY_READ,
  345. &hk);
  346. if (status != ERROR_SUCCESS) {
  347. MyDbgPrint(1,"[WMILIB] Failed to open %1!ws! subkey, %2!d!\n", ProductName, status);
  348. goto exit_gracefully;
  349. }
  350. ReadLoggerInfo(hk, &data.Logger);
  351. ReadCommonData(hk, &data);
  352. if (!data.Active) {
  353. MyDbgPrint(1,"[WMILIB] Tracing is not active for %1!ws!\n", ProductName);
  354. goto exit_gracefully;
  355. }
  356. if (data.GuidDefined) {
  357. // First, try to find its in the map. //
  358. // If it is there, we need to register this Guid //
  359. RegisterIfNecessary(ProductName, &data.Guid);
  360. // We can try to start tracing //
  361. if (data.Logger) {
  362. status = EnableTrace(data.Active,
  363. data.ControlFlags,
  364. data.LogLevel,
  365. &data.Guid,
  366. data.Logger);
  367. MyDbgPrint(1,"[WMILIB] Enable=%1!d! %2!ws!, status %3!d!\n", data.
  368. Active, ProductName, status);
  369. }
  370. }
  371. dwSizeOfModuleName = sizeof(szModuleName);
  372. dwIndex = 0;
  373. while (ERROR_SUCCESS == (status = RegEnumKeyEx(hk, dwIndex,
  374. szModuleName,
  375. &dwSizeOfModuleName,
  376. NULL, NULL, NULL, NULL)))
  377. {
  378. InitWmiInternal(hk, szModuleName, &data);
  379. dwSizeOfModuleName = sizeof(szModuleName);
  380. ++dwIndex;
  381. }
  382. if (ERROR_NO_MORE_ITEMS == status) {
  383. status = ERROR_SUCCESS;
  384. }
  385. exit_gracefully:
  386. if (CloseMe) {
  387. RegCloseKey(CloseMe);
  388. }
  389. if (hk) {
  390. RegCloseKey(hk);
  391. }
  392. return status;
  393. }
  394. ULONG
  395. InitWmi(
  396. IN LPWSTR ProductName
  397. )
  398. {
  399. MyDbgPrint(1, "[WMILIB] Initialize %1!ws!\n", ProductName);
  400. return InitWmiInternal(0, ProductName, 0);
  401. }
  402. #pragma warning(disable: 4512) // error C4512: 'blah-blah-blah' : assignment operator could not be generated
  403. #pragma warning(disable: 4100) // '_P' : unreferenced formal parameter
  404. #include <xmemory>
  405. #pragma warning(default: 4100)
  406. #include <map>
  407. //#include <xstring>
  408. struct wless {
  409. bool operator() (LPCWSTR a, LPCWSTR b) const { return lstrcmpW(a,b) < 0; }
  410. };
  411. typedef std::map<LPCWSTR, PWMILIB_REG_STRUCT, wless > WIDE_STRING_MAP;
  412. WIDE_STRING_MAP* map;
  413. PWMILIB_REG_STRUCT head;
  414. ULONG
  415. WmilibControlCallback(
  416. IN WMIDPREQUESTCODE RequestCode,
  417. IN PVOID Context,
  418. IN OUT ULONG *InOutBufferSize,
  419. IN OUT PVOID Buffer
  420. )
  421. {
  422. PWMILIB_REG_STRUCT Ctx = (PWMILIB_REG_STRUCT)Context;
  423. ULONG Status = ERROR_SUCCESS;
  424. switch (RequestCode)
  425. {
  426. case WMI_ENABLE_EVENTS:
  427. {
  428. Ctx->LoggerHandle = GetTraceLoggerHandle( Buffer );
  429. Ctx->EnableLevel = GetTraceEnableLevel(Ctx->LoggerHandle);
  430. Ctx->EnableFlags = GetTraceEnableFlags(Ctx->LoggerHandle);
  431. MyDbgPrint(3, "[WMILIB] WMI_ENABLE_EVENTS Ctx 0x%1!08X! Flags %2!X! Lev %3!d! Logger %4!08X!:%5!08X!\n",
  432. Ctx, Ctx->EnableFlags, Ctx->EnableLevel, Ctx->LoggerHandle);
  433. break;
  434. }
  435. case WMI_DISABLE_EVENTS:
  436. {
  437. Ctx->LoggerHandle = 0;
  438. Ctx->EnableFlags = 0;
  439. Ctx->EnableLevel = 0;
  440. MyDbgPrint(3, "[WMILIB] WMI_DISABLE_EVENTS Ctx 0x%1!08X!\n", Ctx);
  441. break;
  442. }
  443. default:
  444. {
  445. Status = ERROR_INVALID_PARAMETER;
  446. break;
  447. }
  448. }
  449. *InOutBufferSize = 0;
  450. return(Status);
  451. }
  452. VOID RegisterIfNecessary(
  453. LPWSTR KeyName,
  454. LPCGUID Guid)
  455. {
  456. WIDE_STRING_MAP::iterator i = map->find(KeyName);
  457. if ( i == map->end() ) {
  458. MyDbgPrint(2, "[WMILIB] map: %1!ws!, not found\n", KeyName);
  459. return; // Not found //
  460. }
  461. MyDbgPrint(3, "[WMILIB] map[%1!ws!]=0x%2!08X!\n", i->first, i->second);
  462. TRACE_GUID_REGISTRATION Reg;
  463. Reg.Guid = Guid;
  464. Reg.RegHandle = 0;
  465. ULONG status = RegisterTraceGuids(
  466. WmilibControlCallback,
  467. i->second, // Context for the callback
  468. Guid, // Control Guid
  469. 1, // # of dummies
  470. &Reg, // dummy trace guid
  471. 0, //ImagePath,
  472. 0, //ResourceName,
  473. &i->second->RegistrationHandle
  474. );
  475. if (status == ERROR_SUCCESS) {
  476. i->second->Next = head;
  477. head = i->second;
  478. } else {
  479. MyDbgPrint(1, "[WMILIB] Failed to register %1!ws!, status %2!d!\n", KeyName, status);
  480. }
  481. }
  482. ULONG
  483. WmlInitialize(
  484. IN LPWSTR ProductName,
  485. IN WMILIBPRINTFUNC PrintFunc,
  486. OUT WMILIB_REG_HANDLE* Head,
  487. ... // Pairs: LPWSTR CtrlGuidName, Corresponding WMILIB_REG_STRUCT
  488. )
  489. {
  490. WIDE_STRING_MAP map;
  491. LPWSTR str;
  492. va_list ap;
  493. WmiLibPrint = PrintFunc;
  494. *Head = 0;
  495. ::head = 0;
  496. ::map = &map;
  497. va_start(ap, Head);
  498. while(0 != (str = va_arg(ap, LPWSTR)) ) {
  499. map[ str ] = va_arg(ap, PWMILIB_REG_STRUCT);
  500. }
  501. va_end(ap);
  502. ULONG status = InitWmiInternal(0, ProductName, 0);
  503. *Head = ::head;
  504. return status;
  505. }
  506. VOID
  507. WmlUninitialize(
  508. IN PWMILIB_REG_STRUCT head
  509. )
  510. {
  511. while (head) {
  512. MyDbgPrint(3,"[WMILIB] Unregister 0x%1!08X!\n", head);
  513. UnregisterTraceGuids(head->RegistrationHandle);
  514. head = head->Next;
  515. }
  516. }
  517. #define WMILIB_USER_MODE
  518. typedef struct _TRACE_BUFFER {
  519. union {
  520. EVENT_TRACE_HEADER Trace;
  521. WNODE_HEADER Wnode;
  522. };
  523. MOF_FIELD MofFields[MAX_MOF_FIELDS + 1];
  524. } TRACE_BUFFER, *PTRACE_BUFFER;
  525. //////////////////////////////////////////////////////////////////////
  526. // 0 | Size | ProviderId | 0 |Size.HT.Mk | Typ.Lev.Version|
  527. // 2 | L o g g e r H a n d l e | 2 | T h r e a d I d |
  528. // 4 | T i m e S t a m p | 4 | T i m e S t a m p |
  529. // 6 | G U I D L o w | 6 | GUID Ptr / Guid L o w |
  530. // 8 | G U I D H I g h | 8 | G U I D H i g h |
  531. // 10 | ClientCtx | Flags | 10 |KernelTime | UserTime |
  532. //////////////////////////////////////////////////////////////////////
  533. ULONG
  534. WmlTrace(
  535. IN UINT Type,
  536. IN LPCGUID TraceGuid,
  537. IN TRACEHANDLE LoggerHandle,
  538. ... // Pairs: Address, Length
  539. )
  540. {
  541. TRACE_BUFFER TraceBuffer;
  542. ((PULONG)&TraceBuffer)[1] = Type;
  543. #ifndef WMILIB_USER_MODE
  544. TraceBuffer.Wnode.HistoricalContext = LoggerHandle;
  545. #endif
  546. TraceBuffer.Trace.Guid = *TraceGuid;
  547. TraceBuffer.Wnode.Flags =
  548. WNODE_FLAG_USE_MOF_PTR | // MOF data are dereferenced
  549. WNODE_FLAG_TRACED_GUID; // Trace Event, not a WMI event
  550. {
  551. PMOF_FIELD ptr = TraceBuffer.MofFields;
  552. va_list ap;
  553. va_start(ap, LoggerHandle);
  554. do {
  555. if ( 0 == (ptr->Length = (ULONG)va_arg (ap, size_t)) ) {
  556. break;
  557. }
  558. ptr->DataPtr = (ULONGLONG)va_arg(ap, PVOID);
  559. } while ( ++ptr < &TraceBuffer.MofFields[MAX_MOF_FIELDS] );
  560. va_end(ap);
  561. TraceBuffer.Wnode.BufferSize = (ULONG) ((ULONG_PTR)ptr - (ULONG_PTR)&TraceBuffer);
  562. }
  563. #ifdef WMILIB_USER_MODE
  564. ULONG status = TraceEvent( LoggerHandle, &TraceBuffer.Trace);
  565. if (status != ERROR_SUCCESS) {
  566. // Need to count failures and report them during unintialize or ...//
  567. }
  568. #else
  569. IoWMIWriteEvent(&TraceBuffer);
  570. #endif
  571. return ERROR_SUCCESS;
  572. }