6#pragma comment(lib, "Advapi32.lib")
11#ifndef INVALID_PROCESSTRACE_HANDLE
12#define INVALID_PROCESSTRACE_HANDLE ((TRACEHANDLE)INVALID_HANDLE_VALUE)
21 TRACEHANDLE session_handle;
23 TRACEHANDLE trace_handle;
27 etw_event_callback_t callback;
31 EVENT_TRACE_PROPERTIES *properties;
33 wchar_t *session_name_w;
42static void zero_bytes(
void *ptr,
size_t size)
44 unsigned char *p = (
unsigned char *)ptr;
46 for (i = 0; i < size; i++)
56static int parse_guid(
const char *str, GUID *guid)
61 if (str == NULL || guid == NULL)
67 "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x",
68 &d[0], &d[1], &d[2], &d[3], &d[4],
69 &d[5], &d[6], &d[7], &d[8], &d[9], &d[10]);
75 guid->Data1 = (ULONG)d[0];
76 guid->Data2 = (USHORT)d[1];
77 guid->Data3 = (USHORT)d[2];
78 guid->Data4[0] = (UCHAR)d[3];
79 guid->Data4[1] = (UCHAR)d[4];
80 guid->Data4[2] = (UCHAR)d[5];
81 guid->Data4[3] = (UCHAR)d[6];
82 guid->Data4[4] = (UCHAR)d[7];
83 guid->Data4[5] = (UCHAR)d[8];
84 guid->Data4[6] = (UCHAR)d[9];
85 guid->Data4[7] = (UCHAR)d[10];
92static int guid_equal(
const GUID *a,
const GUID *b)
94 return a->Data1 == b->Data1 &&
95 a->Data2 == b->Data2 &&
96 a->Data3 == b->Data3 &&
97 a->Data4[0] == b->Data4[0] &&
98 a->Data4[1] == b->Data4[1] &&
99 a->Data4[2] == b->Data4[2] &&
100 a->Data4[3] == b->Data4[3] &&
101 a->Data4[4] == b->Data4[4] &&
102 a->Data4[5] == b->Data4[5] &&
103 a->Data4[6] == b->Data4[6] &&
104 a->Data4[7] == b->Data4[7];
113static VOID WINAPI event_record_callback(PEVENT_RECORD pEvent)
115 etw_session_t *session;
124 session = (etw_session_t *)pEvent->UserContext;
125 if (session == NULL || session->callback == NULL)
131 if (!guid_equal(&pEvent->EventHeader.ProviderId, &session->provider_guid))
136 level = pEvent->EventHeader.EventDescriptor.Level;
139 if (pEvent->UserData != NULL && pEvent->UserDataLength > 0)
141 message = (
const char *)pEvent->UserData;
144 session->callback(level, message, session->context);
150static DWORD WINAPI trace_thread_proc(LPVOID param)
152 etw_session_t *session = (etw_session_t *)param;
154 ProcessTrace(&session->trace_handle, 1, NULL, NULL);
161static void set_status(
int *out_status,
int value)
163 if (out_status != NULL)
169int TRACE_ETW_UTIL_API
170 etw_session_check_access(
void)
172 static const wchar_t probe_name[] = L
"EtwUtil_AccessProbe";
174 EVENT_TRACE_PROPERTIES *props;
175 TRACEHANDLE handle = 0;
179 props_size =
sizeof(EVENT_TRACE_PROPERTIES)
180 +
sizeof(probe_name);
181 props = (EVENT_TRACE_PROPERTIES *)malloc(props_size);
184 return ETW_SESSION_ERR_SYSTEM;
187 zero_bytes(props, props_size);
188 props->Wnode.BufferSize = (ULONG)props_size;
189 props->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
190 props->Wnode.ClientContext = 1;
191 props->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
192 props->LoggerNameOffset =
sizeof(EVENT_TRACE_PROPERTIES);
194 status = StartTraceW(&handle, probe_name, props);
196 if (status == ERROR_SUCCESS)
198 ControlTraceW(handle, NULL, props, EVENT_TRACE_CONTROL_STOP);
199 result = ETW_SESSION_OK;
201 else if (status == ERROR_ACCESS_DENIED)
203 result = ETW_SESSION_ERR_ACCESS;
207 result = ETW_SESSION_ERR_SYSTEM;
214etw_session_t *TRACE_ETW_UTIL_API
215 etw_session_start(
const char *session_name,
216 const char *provider_guid_str,
217 etw_event_callback_t callback,
221 etw_session_t *session = NULL;
226 ENABLE_TRACE_PARAMETERS etp = {0};
228 if (session_name == NULL || provider_guid_str == NULL || callback == NULL)
230 set_status(out_status, ETW_SESSION_ERR_PARAM);
234 if (parse_guid(provider_guid_str, &provider_guid) != 0)
236 set_status(out_status, ETW_SESSION_ERR_PARAM);
241 name_len_w = MultiByteToWideChar(CP_UTF8, 0, session_name, -1, NULL, 0);
244 set_status(out_status, ETW_SESSION_ERR_PARAM);
248 session = (etw_session_t *)malloc(
sizeof(etw_session_t));
251 set_status(out_status, ETW_SESSION_ERR_SYSTEM);
255 zero_bytes(session,
sizeof(etw_session_t));
256 session->callback = callback;
257 session->context = context;
258 session->session_handle = 0;
259 session->trace_handle = INVALID_PROCESSTRACE_HANDLE;
260 session->thread_handle = NULL;
261 session->properties = NULL;
262 session->session_name_w = NULL;
263 session->provider_guid = provider_guid;
266 session->session_name_w = (
wchar_t *)malloc((
size_t)name_len_w *
sizeof(
wchar_t));
267 if (session->session_name_w == NULL)
269 set_status(out_status, ETW_SESSION_ERR_SYSTEM);
272 MultiByteToWideChar(CP_UTF8, 0, session_name, -1,
273 session->session_name_w, name_len_w);
276 props_size =
sizeof(EVENT_TRACE_PROPERTIES) + ((
size_t)name_len_w *
sizeof(
wchar_t));
277 session->properties = (EVENT_TRACE_PROPERTIES *)malloc(props_size);
278 if (session->properties == NULL)
280 set_status(out_status, ETW_SESSION_ERR_SYSTEM);
285 zero_bytes(session->properties, props_size);
286 session->properties->Wnode.BufferSize = (ULONG)props_size;
287 session->properties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
288 session->properties->Wnode.ClientContext = 1;
289 session->properties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
290 session->properties->LoggerNameOffset =
sizeof(EVENT_TRACE_PROPERTIES);
291 session->properties->FlushTimer = 1;
293 status = StartTraceW(&session->session_handle,
294 session->session_name_w,
295 session->properties);
297 if (status == ERROR_ACCESS_DENIED)
299 session->session_handle = 0;
300 set_status(out_status, ETW_SESSION_ERR_ACCESS);
304 if (status != ERROR_SUCCESS)
306 session->session_handle = 0;
307 set_status(out_status, ETW_SESSION_ERR_SYSTEM);
312 etp.Version = ENABLE_TRACE_PARAMETERS_VERSION_2;
313 status = EnableTraceEx2(session->session_handle,
315 EVENT_CONTROL_CODE_ENABLE_PROVIDER,
317 0xFFFFFFFFFFFFFFFF, 0, 0, &etp);
318 if (status != ERROR_SUCCESS)
320 set_status(out_status, ETW_SESSION_ERR_SYSTEM);
326 EVENT_TRACE_LOGFILEW trace_logfile = {0};
327 trace_logfile.LoggerName = session->session_name_w;
328 trace_logfile.ProcessTraceMode =
329 PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;
330 trace_logfile.EventRecordCallback = event_record_callback;
331 trace_logfile.Context = session;
333 session->trace_handle = OpenTraceW(&trace_logfile);
335 if (session->trace_handle == INVALID_PROCESSTRACE_HANDLE)
337 set_status(out_status, ETW_SESSION_ERR_SYSTEM);
341 session->thread_handle = CreateThread(
342 NULL, 0, trace_thread_proc, session, 0, NULL);
343 if (session->thread_handle == NULL)
345 set_status(out_status, ETW_SESSION_ERR_SYSTEM);
349 set_status(out_status, ETW_SESSION_OK);
355 if (session->trace_handle != INVALID_PROCESSTRACE_HANDLE)
357 CloseTrace(session->trace_handle);
359 if (session->session_handle != 0)
361 ControlTraceW(session->session_handle, NULL,
362 session->properties, EVENT_TRACE_CONTROL_STOP);
364 free(session->session_name_w);
365 free(session->properties);
371void TRACE_ETW_UTIL_API
372 etw_session_stop(etw_session_t *session)
380 if (session->session_handle != 0 && session->properties != NULL)
382 ControlTraceW(session->session_handle, NULL,
383 session->properties, EVENT_TRACE_CONTROL_STOP);
387 if (session->thread_handle != NULL)
389 WaitForSingleObject(session->thread_handle, INFINITE);
390 CloseHandle(session->thread_handle);
394 if (session->trace_handle != INVALID_PROCESSTRACE_HANDLE)
396 CloseTrace(session->trace_handle);
399 free(session->session_name_w);
400 free(session->properties);
ETW (Event Tracing for Windows) ヘルパーライブラリ。