winlog 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3482 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT license.
3
+
4
+ #pragma once
5
+ #include <windows.h>
6
+ #include <evntprov.h>
7
+ #include <stdlib.h> // byteswap
8
+
9
+ namespace tld
10
+ {
11
+ #pragma region Public interface
12
+
13
+ /*
14
+ GENERAL:
15
+
16
+ - This implementation of manifest-free ETW supports more functionality
17
+ than the implementation in TraceLoggingProvider.h, but it also has
18
+ higher runtime costs. This implementation is intended for use only when
19
+ the set of events is not known at compile-time. For example,
20
+ TraceLoggingDynamic.h might be used to implement a library providing
21
+ manifest-free ETW to a scripting language like JavaScript or Perl.
22
+ - This header is not intended for direct use by developers adding events
23
+ to their code. There is no way to make an optimal solution that
24
+ works for all of the intended target users. Instead, this header
25
+ provides various pieces that you can build upon to create a user-friendly
26
+ implementation of manifest-free ETW tailored for a specific scenario.
27
+
28
+ HIGH-LEVEL API:
29
+
30
+ The high-level API provides an easy way to get up and running with
31
+ TraceLogging ETW events.
32
+
33
+ Contents:
34
+ - Class: tld::Provider
35
+ - Class: tld::Event
36
+ - Class: tld::EventBuilder
37
+ - Enum: tld::Type
38
+
39
+ Basic usage:
40
+ - Create a Provider object.
41
+ - Check provider.IsEnabled(level, keyword) so that you don't do the
42
+ remaining steps if nobody is listening for your event.
43
+ - Create an Event<std::vector<BYTE>> object.
44
+ - Add fields definitions (metadata) and values (data) using methods on
45
+ Event. (You are responsible for making sure that the metadata you add
46
+ matches the data you add -- the Event object does not validate this.)
47
+ - Some methods on the Event object return EventBuilder objects, which are
48
+ used to build the fields of nested structures. Event inherits from
49
+ EventBuilder, so if you write a function that accepts an EventBuilder&,
50
+ it will also accept an Event&.
51
+ - Once you've added all data and metadata, call event.Write() to send the
52
+ event to ETW.
53
+
54
+ LOW-LEVEL API:
55
+
56
+ The low-level API provides components that you can mix and match to build
57
+ your own solution when the high-level components don't precisely meet your
58
+ needs. For example, you might use the high-level Provider class to manage
59
+ your REGHANDLE and the ETW callbacks, but you might use
60
+ EventMetadataBuilder and EventDataBuilder directly instead of using Event
61
+ so that you can cache event definitions.
62
+
63
+ Contents:
64
+ - Function: tld::RegisterProvider
65
+ - Function: tld::UnregisterProvider
66
+ - Function: tld::GetGuidForName
67
+ - Function: tld::SetInformation
68
+ - Class: tld::ProviderMetadataBuilder
69
+ - Class: tld::EventMetadataBuilder
70
+ - Class: tld::EventDataBuilder
71
+ - Struct: tld::EventDescriptor
72
+ - Class: tld::ByteArrayWrapper
73
+ - Enum: tld::InType
74
+ - Enum: tld::OutType
75
+ - Enum: tld::ProviderTraitType
76
+ - Function: tld::WriteEvent
77
+ - Function: tld::WriteEventEx
78
+ - Function: tld::PushBackAsUtf8
79
+ - Function: tld::MakeType
80
+ - Macro: TLD_HAVE_EVENT_SET_INFORMATION
81
+ - Macro: TLD_HAVE_EVENT_WRITE_EX
82
+
83
+ Notes:
84
+ - EventDataDescCreate is a native ETW API from <evntprov.h>. It is not
85
+ part of this API, but you may want to use it to initialize
86
+ EVENT_DATA_DESCRIPTOR structures instead of doing it directly.
87
+ - If you directly initialize your EVENT_DATA_DESCRIPTOR structures instead
88
+ of using EventDataDescCreate, be sure to properly initialize the
89
+ EVENT_DATA_DESCRIPTOR.Reserved field (e.g. by setting it to 0).
90
+ Initializing the Reserved field is NOT optional. (EventDataDescCreate
91
+ does correctly initialize the Reserved field.)
92
+ - When the API asks for a byte-buffer, you can use std::vector<BYTE> or
93
+ another similar type. If you don't want to use a vector, the provided
94
+ ByteArrayWrapper type allows you to use your own allocation strategy for
95
+ the buffer.
96
+ - By default, TraceLogging events have Id=0 and Version=0, indicating
97
+ that the event does not have an assigned Id. However, events can have
98
+ Id and Version assigned (typically assigned manually). If you don't want
99
+ to manage event IDs, set both Id and Version to 0. If you do assign
100
+ IDs to your events, the Id must be non-zero and there should be a
101
+ one-to-one mapping between {provider.Id + event.Id + event.Version} and
102
+ {event metadata}. In other words, any event with a given non-zero
103
+ Id+Version combination must always have exactly the same event metadata.
104
+ (Note to decoders: this can be used as an optimization, but do not rely
105
+ on providers to follow this rule.)
106
+ - TraceLogging events default to channel 11 (WINEVENT_CHANNEL_TRACELOGGING).
107
+ This channel has no effect other than to mark the event as TraceLogging-
108
+ compatible. Other channels can be used, but channels other than 11 will
109
+ only work if the provider is running on a version of Windows that
110
+ understands TraceLogging (Windows 7sp1 with latest updates, Windows 8.1
111
+ with latest updates, Windows 10, or later). If your provider is running
112
+ on a version of Windows that does not understand TraceLogging and you use
113
+ a channel other than 11, the resulting events will not decode correctly.
114
+
115
+ Low-level provider management:
116
+ - Use tld::ProviderMetadataBuilder to build a provider metadata blob.
117
+ - If you don't have a specific provider GUID already selected, use
118
+ tld::GetGuidForName to compute your provider GUID.
119
+ - Use tld::RegisterProvider to open the REGHANDLE.
120
+ - Use the REGHANDLE in calls to tld::WriteEvent.
121
+ - Use tld::UnregisterProvider to close the REGHANDLE.
122
+
123
+ Low-level event management:
124
+ - Use tld::EventMetadataBuilder to build an event metadata blob.
125
+ - Use tld::Type values to define field types, or use tld::MakeType to
126
+ combine tld::InType and tld::OutType to make tld::Type values.
127
+ - Use tld::EventDataBuilder to build an event data blob.
128
+ - Create an EVENT_DESCRIPTOR for your event.
129
+ - Optionally use the tld::EventDescriptor wrapper class to simplify
130
+ initialization of EVENT_DESCRIPTOR structures.
131
+ - Allocate an array of EVENT_DATA_DESCRIPTORs. Size should be two more
132
+ than you need for your event payload (the first two are reserved for the
133
+ provider and event metadata).
134
+ - Use EventDataDescCreate to fill in the data descriptor array (skipping
135
+ the first two) to reference your event payload data.
136
+ - Use tld::WriteEvent to write your event.
137
+ */
138
+
139
+ /*
140
+ class Provider (high-level API):
141
+
142
+ Manages an ETW REGHANDLE and the provider metadata blob.
143
+ - Constructor creates the provider metadata blob and registers the provider.
144
+ Note that this includes configuring ETW callbacks.
145
+ - Destructor unregisters the provider and frees the metadata blob.
146
+ - IsEnabled APIs provide efficient checks for whether an event needs to be
147
+ written.
148
+ - Write APIs call WriteEvent, automatically providing the correct REGHANDLE
149
+ and provider metadata blobs.
150
+
151
+ Typical usage:
152
+
153
+ tld::Provider provider("ProviderName", ...);
154
+ if (provider.IsEnabled(eventLevel, eventKeyword))
155
+ {
156
+ Event event(provider, szEventName, eventLevel, eventKeyword);
157
+ (add fields definitions and values);
158
+ event.Write();
159
+ }
160
+
161
+ It is not a problem to call provider.Write without checking
162
+ provider.IsEnabled(...), but it is much more efficient to check
163
+ provider.IsEnabled(...) so that you can skip the process of preparing and
164
+ writing the event when the event is not enabled.
165
+ */
166
+ class Provider;
167
+
168
+ /*
169
+ class Event (high-level API):
170
+
171
+ Manages the data and metadata for an event. You create an Event object,
172
+ set properties, add field definitions, add field values, and then Write
173
+ the event.
174
+
175
+ ByteVectorTy will usually be std::vector<BYTE>, though other similar
176
+ types could be used instead.
177
+
178
+ Typical usage:
179
+
180
+ if (provider.IsEnabled(eventLevel, eventKeyword))
181
+ {
182
+ Event event(provider, szEventName, eventLevel, eventKeyword);
183
+ (add fields definitions and values);
184
+ event.Write();
185
+ }
186
+
187
+ You can reuse an Event object by calling event.Reset(...), which might
188
+ reduce heap allocation overhead.
189
+ */
190
+ template<class ByteVectorTy>
191
+ class Event;
192
+
193
+ /*
194
+ class EventBuilder (high-level API):
195
+
196
+ This class exposes an interface for adding field metadata/data to an event.
197
+ The Event class inherits from EventBuilder so that it can expose this
198
+ interface. In addition, each call to eventBuilder.AddStruct(...) returns a
199
+ new EventBuilder that can be used to add fields to a nested structure.
200
+ You won't directly create instances of this type. Instead, you'll use
201
+ instances returned by event.AddStruct or eventBuilder.AddStruct.
202
+
203
+ You can use EventBuilder& as the type of a parameter to a function and
204
+ then pass either an Event or an EventBuilder to that function, allowing
205
+ for recursive processing of event fields.
206
+
207
+ Note that order is important but not checked when using multiple Event or
208
+ EventBuilder objects. Fields are always added to the end of the overall
209
+ event, regardless of which Event or EventBuilder you use to add the field.
210
+ The separate Event and EventBuilder objects are used for the sole purpose
211
+ of tracking the number of fields in each struct.
212
+
213
+ Assume that you have obtained EventBuilder object b from object a, i.e.
214
+ EventBuilder b = a.AddStruct(...). You must complete all operations using
215
+ b before resuming any operations using a. If this rule is not followed,
216
+ structures will not nest correctly.
217
+ */
218
+ template<class ByteVectorTy>
219
+ class EventBuilder;
220
+
221
+ /*
222
+ enum Type (high-level API and low-level API):
223
+
224
+ Types for event fields, corresponding to a combination of TDH_INTYPE and
225
+ TDH_OUTTYPE values. The Type enumeration contains predefined combinations
226
+ of InType and OutType that are defined by winmeta.xml and supported by
227
+ decoders such as TDH and xperf.
228
+
229
+ Advanced use: It is possible to create other Type values by combining
230
+ values from the InType and OutType enumerations using the tld::MakeType
231
+ function (valid Type values consist of one InType combined with one
232
+ OutType). However, custom combinations not already present in the Type
233
+ enumeration are unlikely to be recognized by xperf or other decoders,
234
+ and will usually end up being decoded as if they used OutTypeDefault.
235
+
236
+ When providing payload for a field, the payload data must match the InType.
237
+ Payload is always packed tightly with no alignment or padding.
238
+
239
+ ****
240
+
241
+ How to pack single values:
242
+
243
+ Primitive values (int, GUID) are packed directly. Just reserve
244
+ sizeof(value) bytes in the buffer, then memcpy the value into the buffer.
245
+ Note that there should be no alignment or padding between items -- the
246
+ payload is always tightly-packed.
247
+
248
+ NUL-terminated strings are also simply memcpy'ed into the buffer. Be sure
249
+ to include the NUL termination when reserving space and copying the value.
250
+ There is no way to represent NULL. The encoding helpers in this header
251
+ treat a NULL string the same as an empty string, i.e.
252
+ AddString((char*)NULL) is the same as AddString("").
253
+
254
+ Binary, CountedString, and CountedAnsiString scalars are all encoded as a
255
+ UINT16 byte-count followed by the string data. In this case, no NUL
256
+ termination should be included. Remember that the size is a byte count,
257
+ not a character count.
258
+
259
+ ****
260
+
261
+ How to pack arrays:
262
+
263
+ Assume you have a function Pack(payloadVec, item) that correctly appends an
264
+ item to the end of payloadVec.
265
+
266
+ Packing a variable-length array of N items is done by appending the UINT16
267
+ value of N to payloadVec, followed by calling Pack(...) N times.
268
+
269
+ Packing a constant-length array of N items is done by calling Pack(...) N
270
+ times. The value of N is encoded in the metadata (it was provided in the
271
+ field's declaration) so it does not need to be provided in the payload.
272
+
273
+ Note: while this header allows you to create arrays of anything, you
274
+ should avoid creating arrays of InTypeBinary as they will not decode
275
+ correctly. (It is ok to create an array of nested structures where fields
276
+ in the structure have InTypeBinary.)
277
+ */
278
+ enum Type : UINT16;
279
+
280
+ /*
281
+ Used for composing Type values.
282
+ Normally you'll use a precomposed Type... value, but you can compose a
283
+ custom Type... value by combining a value from InType with a value from
284
+ OutType using MakeType.
285
+
286
+ The InType tells the pipeline how to encode the field's payload (primarily
287
+ how to determine payload size). In addition, each InType has an implicit
288
+ default formatting behavior that will be used if not overridden by an
289
+ OutType.
290
+
291
+ The comments for each InType value indicate the payload encoding rules and
292
+ the OutTypes that are most likely to be usable with this InType.
293
+ */
294
+ enum InType : UINT8;
295
+
296
+ /*
297
+ Used for composing Type values.
298
+ Normally you'll use a precomposed Type... value, but you can compose a
299
+ custom Type... value by combining a value from InType with a value from
300
+ OutType using MakeType.
301
+
302
+ The OutType gives the pipeline a formatting hint that the trace consumer
303
+ may use to override the InType's default formatting behavior. If no
304
+ OutType is specified (i.e. if OutTypeDefault is used) or if the trace
305
+ consumer does not recognize the specified InType+OutType combination, the
306
+ trace consumer will typically perform default formatting based solely on
307
+ InType.
308
+
309
+ The valid combinations of InType + OutType are defined in the Windows SDK
310
+ in winmeta.xml (each inType has a list of valid outType under it).
311
+ */
312
+ enum OutType : UINT8;
313
+
314
+ /*
315
+ enum ProviderTraitType (low-level API):
316
+
317
+ The type of a provider trait. Used when building up provider metadata.
318
+ */
319
+ enum ProviderTraitType : UINT8;
320
+
321
+ /*
322
+ macro TLD_HAVE_EVENT_SET_INFORMATION (low-level API):
323
+
324
+ Configuration macro for controlling the behavior of SetInformation.
325
+
326
+ Not all versions of Windows support the EventSetInformation API.
327
+ TraceLogging requires EventSetInformation for full functionality, but can
328
+ operate in a degraded mode without it. The tld::SetInformation wrapper
329
+ provides default behavior that works well in most cases, but may not meet
330
+ the needs of all users. The configuration macros can be used to control how
331
+ the tld::SetInformation function invokes the EventSetInformation API. Note
332
+ that tld::SetInformation is called automatically by the Provider class's
333
+ constructor to register the provider's traits with ETW.
334
+
335
+ When TLD_HAVE_EVENT_SET_INFORMATION is not defined and WINVER < 0x0602:
336
+ SetInformation uses GetModuleHandleExW+GetProcAddress to find the
337
+ EventSetInformation function. If found, SetInformation calls it and
338
+ returns whatever EventSetInformation returns. Otherwise, SetInformation
339
+ returns an error.
340
+
341
+ When TLD_HAVE_EVENT_SET_INFORMATION is not defined and WINVER >= 0x0602:
342
+ SetInformation directly calls the EventSetInformation(...) function and
343
+ returns whatever EventSetInformation returns.
344
+
345
+ If you set TLD_HAVE_EVENT_SET_INFORMATION:
346
+ - If TLD_HAVE_EVENT_SET_INFORMATION == 0, SetInformation always returns an
347
+ error (does not attempt to call EventSetInformation).
348
+ - If TLD_HAVE_EVENT_SET_INFORMATION == 1, SetInformation calls
349
+ EventSetInformation directly.
350
+ - If TLD_HAVE_EVENT_SET_INFORMATION == 2, SetInformation locates
351
+ EventSetInformation via GetProcAddress, calls it if found, or returns an
352
+ error if not found.
353
+ */
354
+ #ifndef TLD_HAVE_EVENT_SET_INFORMATION
355
+ #if WINVER < 0x0602 // If targeting Windows before Windows 8
356
+ #define TLD_HAVE_EVENT_SET_INFORMATION 2 // Find "EventSetInformation" via GetModuleHandleExW/GetProcAddress
357
+ #else
358
+ #define TLD_HAVE_EVENT_SET_INFORMATION 1 // Directly invoke EventSetInformation(...)
359
+ #endif
360
+ #endif // TLD_HAVE_EVENT_SET_INFORMATION
361
+
362
+ /*
363
+ macro TLD_HAVE_EVENT_WRITE_EX (low-level API):
364
+
365
+ Configuration macro for enabling/disabling WriteEventEx, WriteEx.
366
+
367
+ If TLD_HAVE_EVENT_WRITE_EX is not defined and WINVER < 0x0601, or
368
+ if TLD_HAVE_EVENT_WRITE_EX is defined as 0,
369
+ then the WriteEventEx, WriteEx, and related APIs will not be available.
370
+
371
+ If TLD_HAVE_EVENT_WRITE_EX is not defined and WINVER >= 0x0601, or
372
+ if TLD_HAVE_EVENT_WRITE_EX is defined as 1,
373
+ then the WriteEventEx, WriteEx, and related APIs will be available.
374
+ */
375
+ #ifndef TLD_HAVE_EVENT_WRITE_EX
376
+ #if WINVER < 0x0601 // If targeting Windows before Windows 7
377
+ #define TLD_HAVE_EVENT_WRITE_EX 0
378
+ #else
379
+ #define TLD_HAVE_EVENT_WRITE_EX 1
380
+ #endif
381
+ #endif // TLD_HAVE_EVENT_WRITE_EX
382
+
383
+
384
+ /*
385
+ class ProviderMetadataBuilder (low-level API):
386
+
387
+ Helper for building the provider metadata blob.
388
+ The type provided for ByteBufferTy must behave like a std::vector<BYTE>.
389
+
390
+ Example usage:
391
+
392
+ std::vector<BYTE> byteVector;
393
+ tld::ProviderMetadataBuilder<std::vector<BYTE>> builder(byteVector);
394
+ builder.Begin(szProviderName); // Note: calls byteVector.clear().
395
+ if (builder.End()) // Returns false if the metadata is too large.
396
+ {
397
+ // byteVector now contains a valid provider metadata blob.
398
+ }
399
+ */
400
+ template<class ByteBufferTy>
401
+ class ProviderMetadataBuilder;
402
+
403
+ /*
404
+ class EventMetadataBuilder (low-level API):
405
+
406
+ Helper for building the event metadata blob, including field definitions.
407
+ The type provided for ByteBufferTy must behave like a std::vector<BYTE>.
408
+
409
+ Example usage:
410
+
411
+ std::vector<BYTE> byteVector;
412
+ tld::EventMetadataBuilder<std::vector<BYTE>> builder(byteVector);
413
+ builder.Begin(eventName); // Note: calls byteVector.clear().
414
+ builder.AddField("Field1", TypeBOOL32); // top-level field
415
+ auto struct1 = builder.AddStruct("Struct1");
416
+ struct1.AddField("Nested1", TypeINT32) // nested field
417
+ struct1.AddField("Nested2", TypeANSISTRING); // nested field
418
+ if (builder.End()) // Returns false if the metadata is too large.
419
+ {
420
+ // byteVector now contains a valid event metadata blob.
421
+ }
422
+ */
423
+ template<class ByteBufferTy>
424
+ class EventMetadataBuilder;
425
+
426
+ /*
427
+ class EventDataBuilder (low-level API):
428
+
429
+ Helpers for adding event data to an event data blob.
430
+ The type provided for ByteBufferTy must behave like a std::vector<BYTE>.
431
+ */
432
+ template<class ByteBufferTy>
433
+ class EventDataBuilder;
434
+
435
+ /*
436
+ class EventDescriptor (low-level API):
437
+
438
+ Derives from EVENT_DESCRIPTOR. Adds convenient constructor and Reset
439
+ members. Contains an event's Id/Version/Level/Opcode/Task/Keyword
440
+ settings. Use of this class is optional: you can use this class if you
441
+ want to use the constructor or Reset methods, or you can use
442
+ EVENT_DESCRIPTOR directly if you don't need the convenience methods.
443
+ */
444
+ struct EventDescriptor;
445
+
446
+ /*
447
+ class ByteArrayWrapper (low-level API):
448
+
449
+ Adapter that allows a regular BYTE array (stack-allocated or
450
+ manually-allocated) to be used as the buffer in MetadataBuilder
451
+ operations. If the underlying BYTE array is too small, or if no array is
452
+ provided at all, this adapter will stop writing data beyond the end of the
453
+ array, but will continue to "accept" data (and will increment it size
454
+ member accordingly). This allows you to determine the size of the required
455
+ array so that the operation can be retried with a correctly-sized array.
456
+
457
+ Example usage:
458
+
459
+ // Create a wrapper with a default (0-length) buffer.
460
+ tld::ByteArrayWrapper wrapper;
461
+
462
+ // Create a metadata builder attached to the wrapper.
463
+ tld::ProviderMetadataBuilder<tld::ByteArrayWrapper> builder(wrapper);
464
+
465
+ // Determine the size needed for provider metadata.
466
+ builder.Begin(providerName);
467
+ builder.End();
468
+
469
+ // Allocate a real buffer and reset the wrapper to use it.
470
+ BYTE* pBuffer = new BYTE[wrapper.size()];
471
+ wrapper.reset(pBuffer, wrapper.size());
472
+
473
+ // Redo the operation with the real buffer.
474
+ builder.Begin(providerName);
475
+ if (builder.End())
476
+ {
477
+ // pBuffer now contains a valid provider metadata blob.
478
+ }
479
+ */
480
+ class ByteArrayWrapper;
481
+
482
+ /*
483
+ function RegisterProvider (low-level API):
484
+
485
+ Calls EventRegister. If EventRegister succeeds, calls EventSetInformation
486
+ to register your provider traits with ETW. Use this instead of calling
487
+ EventRegister directly to ensure that your provider traits are properly
488
+ registered.
489
+ */
490
+ inline HRESULT RegisterProvider(
491
+ _Out_ REGHANDLE* phProvider,
492
+ _In_ GUID const* pProviderId,
493
+ _In_count_x_((UINT16*)pProviderMetadata) UINT8 const* pProviderMetadata,
494
+ _In_opt_ PENABLECALLBACK pEnableCallback = 0,
495
+ _In_opt_ void* pEnableCallbackContext = 0);
496
+
497
+ /*
498
+ function UnregisterProvider (low-level API):
499
+
500
+ Calls EventUnregister.
501
+ */
502
+ inline HRESULT UnregisterProvider(
503
+ REGHANDLE hProvider);
504
+
505
+ /*
506
+ function WriteEvent (low-level API):
507
+
508
+ Calls EventWriteTransfer. You must provide 2 more data descriptors than
509
+ are required for your data. The first two elements in pDataDescriptors
510
+ will be used for provider and event metadata. The actual payload (if any)
511
+ is expected to be in the remaining elements of pDataDescriptors.
512
+
513
+ Example usage:
514
+
515
+ tld::EventDescriptor eventDescriptor(
516
+ level,
517
+ opcode,
518
+ task,
519
+ keyword);
520
+ EVENT_DATA_DESCRIPTOR pDataDescriptors[cFields + 2];
521
+ for (int i = 0; i < cFields; i++)
522
+ {
523
+ EventDataDescCreate(&pDataDescriptors[i + 2], ...);
524
+ }
525
+ tld::WriteEvent(
526
+ hProvider,
527
+ eventDescriptor,
528
+ pProviderMetadata,
529
+ pEventMetadata,
530
+ cFields + 2,
531
+ pDataDescriptors);
532
+ */
533
+ inline HRESULT WriteEvent(
534
+ _In_ REGHANDLE hProvider,
535
+ _In_ EVENT_DESCRIPTOR const& eventDescriptor,
536
+ _In_count_x_((UINT16*)pProviderMetadata) UINT8 const* pProviderMetadata,
537
+ _In_count_x_((UINT16*)pEventMetadata) UINT8 const* pEventMetadata,
538
+ _In_range_(2, 128) ULONG cDataDescriptors,
539
+ _Inout_count_(cDataDescriptors) EVENT_DATA_DESCRIPTOR* pDataDescriptors,
540
+ _In_opt_ GUID const* pActivityId = 0,
541
+ _In_opt_ GUID const* pRelatedActivityId = 0);
542
+
543
+ #if TLD_HAVE_EVENT_WRITE_EX == 1
544
+
545
+ /*
546
+ function WriteEventEx (low-level API):
547
+ Calls EventWriteEx. Otherwise works like the WriteEvent function.
548
+ */
549
+ inline HRESULT WriteEventEx(
550
+ _In_ REGHANDLE hProvider,
551
+ _In_ EVENT_DESCRIPTOR const& eventDescriptor,
552
+ _In_count_x_((UINT16*)pProviderMetadata) UINT8 const* pProviderMetadata,
553
+ _In_count_x_((UINT16*)pEventMetadata) UINT8 const* pEventMetadata,
554
+ _In_range_(2, 128) ULONG cDataDescriptors,
555
+ _Inout_count_(cDataDescriptors) EVENT_DATA_DESCRIPTOR* pDataDescriptors,
556
+ ULONG64 filter = 0,
557
+ ULONG flags = 0,
558
+ _In_opt_ GUID const* pActivityId = 0,
559
+ _In_opt_ GUID const* pRelatedActivityId = 0);
560
+
561
+ #endif // TLD_HAVE_EVENT_WRITE_EX
562
+
563
+ /*
564
+ function SetInformation (low-level API):
565
+
566
+ Wrapper for ETW API EventSetInformation.
567
+ If TraceLoggingDynamic.h was compiled to require Win8 or later (as
568
+ determined by WINVER), this directly calls EventSetInformation. Otherwise,
569
+ this attempts to dynamically load the EventSetInformation API via
570
+ GetModuleHandleExW.
571
+
572
+ The behavior of this function (e.g. to override the WINVER check) can be
573
+ adjusted by setting the TLD_HAVE_EVENT_SET_INFORMATION macro as described
574
+ above.
575
+ */
576
+ inline HRESULT SetInformation(
577
+ _In_ REGHANDLE hProvider,
578
+ EVENT_INFO_CLASS informationClass,
579
+ _In_reads_bytes_opt_(cbInformation) void* pbInformation,
580
+ ULONG cbInformation);
581
+
582
+ /*
583
+ function GetGuidForName (low-level API):
584
+
585
+ Hashes a provider name to generate a GUID. Uses the same GUID generation
586
+ algorithm as System.Diagnostics.Tracing.EventSource (from .NET),
587
+ Windows.Foundation.Diagnostics.LoggingChannel (from Windows Runtime),
588
+ and Windows SDK tools like tracelog and traceview.
589
+ */
590
+ inline GUID GetGuidForName(
591
+ _In_z_ char const* szUtf8Name);
592
+
593
+ /*
594
+ function GetGuidForName (low-level API):
595
+
596
+ Hashes a provider name to generate a GUID. Uses the same GUID generation
597
+ algorithm as System.Diagnostics.Tracing.EventSource (from .NET),
598
+ Windows.Foundation.Diagnostics.LoggingChannel (from Windows Runtime),
599
+ and Windows SDK tools like tracelog and traceview.
600
+ */
601
+ inline GUID GetGuidForName(
602
+ _In_z_ wchar_t const* szUtf16Name);
603
+
604
+ /*
605
+ function PushBackAsUtf8 (low-level API):
606
+
607
+ Transcodes a NUL-terminated UTF-16LE string to a NUL-terminated UTF-8
608
+ string. Intended for use when appending provider/event/field names to
609
+ metadata buffers.
610
+ */
611
+ template<class ByteBufferTy>
612
+ void PushBackAsUtf8(
613
+ ByteBufferTy& buffer,
614
+ _In_z_ wchar_t const* szUtf16);
615
+
616
+ #pragma endregion
617
+
618
+ namespace detail
619
+ {
620
+ #pragma region Internal macros
621
+
622
+ #define _tld_MAKE_TYPE(inType, outType) \
623
+ static_cast<::tld::Type>((inType) | (static_cast<int>(outType) << 8))
624
+
625
+ #ifndef TLD_DEBUG
626
+ #if (DBG || defined(DEBUG) || defined(_DEBUG)) && !defined(NDEBUG)
627
+ #define TLD_DEBUG 1
628
+ #else // DBG
629
+ #define TLD_DEBUG 0
630
+ #endif // DBG
631
+ #endif // TLD_DEBUG
632
+
633
+ #ifndef _tld_ASSERT
634
+ #if TLD_DEBUG
635
+ #define _tld_ASSERT(exp, str) ((void)(!(exp) ? (__annotation(L"Debug", L"AssertFail", L"TraceLogging: " #exp L" : " str), DbgRaiseAssertionFailure(), 0) : 0))
636
+ #else // TLD_DEBUG
637
+ #define _tld_ASSERT(exp, str) ((void)0)
638
+ #endif // TLD_DEBUG
639
+ #endif // _tld_ASSERT
640
+
641
+ #pragma endregion
642
+
643
+ #pragma region MetadataBuilderBase
644
+
645
+ template<class ByteBufferTy>
646
+ class MetadataBuilderBase
647
+ {
648
+ ByteBufferTy& m_buffer;
649
+
650
+ MetadataBuilderBase(MetadataBuilderBase const&); // = delete
651
+ void operator=(MetadataBuilderBase const&); // = delete
652
+
653
+ protected:
654
+
655
+ explicit MetadataBuilderBase(ByteBufferTy& buffer)
656
+ : m_buffer(buffer)
657
+ {
658
+ return;
659
+ }
660
+
661
+ void BaseBegin()
662
+ {
663
+ m_buffer.clear();
664
+ AddU16(0); // Metadata size filled in by BaseEnd
665
+ }
666
+
667
+ bool BaseEnd()
668
+ {
669
+ auto size = m_buffer.size();
670
+ _tld_ASSERT(2 <= size, "Begin was not called");
671
+ SetU16(0, static_cast<UINT16>(size));
672
+ return size < 32768;
673
+ }
674
+
675
+ void AddBytes(
676
+ _In_reads_bytes_(cb) void const* p,
677
+ unsigned cb)
678
+ {
679
+ auto pb = static_cast<UINT8 const*>(p);
680
+ for (unsigned i = 0; i != cb; i++)
681
+ {
682
+ m_buffer.push_back(pb[i]);
683
+ }
684
+ }
685
+
686
+ void AddString(
687
+ _In_z_ char const* szUtf8)
688
+ {
689
+ for (unsigned i = 0;; i++)
690
+ {
691
+ m_buffer.push_back(szUtf8[i]);
692
+ if (szUtf8[i] == 0)
693
+ {
694
+ break;
695
+ }
696
+ }
697
+ }
698
+
699
+ void AddString(
700
+ _In_z_ wchar_t const* szUtf16)
701
+ {
702
+ PushBackAsUtf8(m_buffer, szUtf16);
703
+ }
704
+
705
+ void AddU8(
706
+ UINT8 val)
707
+ {
708
+ m_buffer.push_back(val);;
709
+ }
710
+
711
+ void AddU16(
712
+ UINT16 val)
713
+ {
714
+ m_buffer.push_back(static_cast<UINT8>(val));
715
+ m_buffer.push_back(static_cast<UINT8>(val >> 8));
716
+ }
717
+
718
+ UINT32 GetBookmark()
719
+ {
720
+ return static_cast<UINT32>(m_buffer.size());
721
+ }
722
+
723
+ void SetU8(
724
+ UINT32 bookmark,
725
+ UINT8 val)
726
+ {
727
+ _tld_ASSERT(bookmark < m_buffer.size(), "bookmark out of range");
728
+ m_buffer[bookmark] = val;
729
+ }
730
+
731
+ void SetU16(
732
+ UINT32 bookmark,
733
+ UINT16 val)
734
+ {
735
+ _tld_ASSERT(1 <= bookmark + 1, "bookmark out of range");
736
+ SetU8(bookmark + 0, static_cast<UINT8>(val));
737
+ SetU8(bookmark + 1, static_cast<UINT8>(val >> 8));
738
+ }
739
+
740
+ void IncrementU7(
741
+ UINT32 bookmark)
742
+ {
743
+ _tld_ASSERT(bookmark < m_buffer.size(), "bookmark out of range");
744
+ UINT8 result;
745
+ result = ++m_buffer[bookmark];
746
+ _tld_ASSERT((result & 0x7f) != 0, "too many fields in struct");
747
+ }
748
+
749
+ public:
750
+
751
+ ByteBufferTy& GetBuffer()
752
+ {
753
+ return m_buffer;
754
+ }
755
+
756
+ ByteBufferTy const& GetBuffer() const
757
+ {
758
+ return m_buffer;
759
+ }
760
+ };
761
+
762
+ #pragma endregion
763
+
764
+ #pragma region Sha1ForNonSecretPurposes
765
+
766
+ /*
767
+ Implements the SHA1 hashing algorithm. Note that this implementation
768
+ is for hashing public information. Do not use this code to hash
769
+ private data, as this implementation does not take any steps to avoid
770
+ information disclosure (i.e. does not scrub its buffers).
771
+ */
772
+ class Sha1ForNonSecretPurposes
773
+ {
774
+ Sha1ForNonSecretPurposes(Sha1ForNonSecretPurposes const&); // = delete
775
+ void operator=(Sha1ForNonSecretPurposes const&); // = delete
776
+
777
+ UINT64 m_length; // Total message length in bits
778
+ unsigned m_pos; // Length of current chunk in bytes
779
+ UINT32 m_results[5];
780
+ UINT32 m_w[80]; // Workspace
781
+
782
+ public:
783
+
784
+ Sha1ForNonSecretPurposes()
785
+ : m_length()
786
+ , m_pos()
787
+ {
788
+ m_results[0] = 0x67452301;
789
+ m_results[1] = 0xEFCDAB89;
790
+ m_results[2] = 0x98BADCFE;
791
+ m_results[3] = 0x10325476;
792
+ m_results[4] = 0xC3D2E1F0;
793
+ }
794
+
795
+ void Append(
796
+ _In_reads_bytes_(cbInput) void const* pInput,
797
+ unsigned cbInput)
798
+ {
799
+ for (unsigned i = 0; i != cbInput; i++)
800
+ {
801
+ Append(static_cast<UINT8 const*>(pInput)[i]);
802
+ }
803
+ }
804
+
805
+ void Append(UINT8 input)
806
+ {
807
+ reinterpret_cast<UINT8*>(m_w)[m_pos++] = input;
808
+ if (64 == m_pos)
809
+ {
810
+ Drain();
811
+ }
812
+ }
813
+
814
+ _Ret_bytecount_(20) UINT8* Finish()
815
+ {
816
+ UINT64 totalBitCount = m_length + 8 * m_pos;
817
+ Append(0x80);
818
+ while (m_pos != 56)
819
+ {
820
+ Append(0x00);
821
+ }
822
+
823
+ *reinterpret_cast<UINT64*>(m_w + 14) = _byteswap_uint64(totalBitCount);
824
+ Drain();
825
+
826
+ for (unsigned i = 0; i != 5; i++)
827
+ {
828
+ m_results[i] = _byteswap_ulong(m_results[i]);
829
+ }
830
+
831
+ return reinterpret_cast<UINT8*>(m_results);
832
+ }
833
+
834
+ private:
835
+
836
+ void Drain()
837
+ {
838
+ for (unsigned i = 0; i != 16; i++)
839
+ {
840
+ m_w[i] = _byteswap_ulong(m_w[i]);
841
+ }
842
+
843
+ for (unsigned i = 16; i != 80; i++)
844
+ {
845
+ m_w[i] = _rotl((m_w[i - 3] ^ m_w[i - 8] ^ m_w[i - 14] ^ m_w[i - 16]), 1);
846
+ }
847
+
848
+ UINT32 a = m_results[0];
849
+ UINT32 b = m_results[1];
850
+ UINT32 c = m_results[2];
851
+ UINT32 d = m_results[3];
852
+ UINT32 e = m_results[4];
853
+
854
+ for (unsigned i = 0; i != 20; i++)
855
+ {
856
+ UINT32 const k = 0x5A827999;
857
+ UINT32 f = (b & c) | ((~b) & d);
858
+ UINT32 temp = _rotl(a, 5) + f + e + k + m_w[i]; e = d; d = c; c = _rotl(b, 30); b = a; a = temp;
859
+ }
860
+
861
+ for (unsigned i = 20; i != 40; i++)
862
+ {
863
+ const UINT32 k = 0x6ED9EBA1;
864
+ UINT32 f = b ^ c ^ d;
865
+ UINT32 temp = _rotl(a, 5) + f + e + k + m_w[i]; e = d; d = c; c = _rotl(b, 30); b = a; a = temp;
866
+ }
867
+
868
+ for (unsigned i = 40; i != 60; i++)
869
+ {
870
+ const UINT32 k = 0x8F1BBCDC;
871
+ UINT32 f = (b & c) | (b & d) | (c & d);
872
+ UINT32 temp = _rotl(a, 5) + f + e + k + m_w[i]; e = d; d = c; c = _rotl(b, 30); b = a; a = temp;
873
+ }
874
+
875
+ for (unsigned i = 60; i != 80; i++)
876
+ {
877
+ const UINT32 k = 0xCA62C1D6;
878
+ UINT32 f = b ^ c ^ d;
879
+ UINT32 temp = _rotl(a, 5) + f + e + k + m_w[i]; e = d; d = c; c = _rotl(b, 30); b = a; a = temp;
880
+ }
881
+
882
+ m_results[0] += a;
883
+ m_results[1] += b;
884
+ m_results[2] += c;
885
+ m_results[3] += d;
886
+ m_results[4] += e;
887
+
888
+ m_length += 512; // 64 bytes == 512 bits
889
+ m_pos = 0;
890
+ }
891
+ };
892
+
893
+ #pragma endregion
894
+
895
+ #pragma region CopyUtfCodePoint
896
+
897
+ /*
898
+ Transcodes one code point from UTF-8 to UTF-16LE.
899
+
900
+ Note that this function requires the input buffer to be
901
+ nul-terminated. This function may try to read several bytes from the
902
+ input buffer, and the nul-termination is required to ensure that it
903
+ doesn't read off the end of the valid buffer when decoding what
904
+ appears to be a multi-byte code point.
905
+
906
+ The UTF-8 validation is very permissive -- anything that is not valid
907
+ UTF-8 is treated as if it were ISO-8859-1 (i.e. the BYTE value is cast
908
+ to wchar_t and assumed to be a valid Unicode code point). This usually
909
+ works well - it has a reasonable probability of doing what the
910
+ developer expects even when the input is CP1252/Latin1 instead of
911
+ UTF-8, and doesn't fail too badly when it doesn't do what the
912
+ developer expects.
913
+
914
+ pchUtf16Output:
915
+ Buffer that receives a single code point, encoded in UTF-16-LE as one
916
+ or two 16-bit wchar_t values.
917
+
918
+ pszUtf8Input:
919
+ Pointer into a nul-terminated UTF-8 byte sequence. On entry, this
920
+ points to the next char to be consumed. This function will advance the
921
+ pointer past the consumed data.
922
+
923
+ returns:
924
+ The number of 16-bit wchar_t values added to pchUtf16Output (one or
925
+ two).
926
+ */
927
+ static unsigned CopyUtfCodePoint(
928
+ _Out_writes_to_(2, return) wchar_t* pchUtf16Output,
929
+ char const*& pszUtf8Input)
930
+ {
931
+ unsigned cchOutput = 1;
932
+ unsigned ch = static_cast<unsigned char>(*pszUtf8Input);
933
+ pszUtf8Input += 1;
934
+ if (ch <= 0xbf)
935
+ {
936
+ // 0x01..0x7f: ASCII - pass through.
937
+ // 0x80..0xbf: Invalid - pass through.
938
+ }
939
+ else if ((pszUtf8Input[0] & 0xc0) != 0x80)
940
+ {
941
+ // Invalid trail byte - pass through.
942
+ }
943
+ else if (ch <= 0xdf)
944
+ {
945
+ // 0xc0..0xdf: Two-byte encoding for 0x0080..0x07ff.
946
+ unsigned ch2 = ((ch & 0x1f) << 6)
947
+ | (pszUtf8Input[0] & 0x3f);
948
+ if (0x0080 <= ch2)
949
+ {
950
+ ch = ch2;
951
+ pszUtf8Input += 1;
952
+ }
953
+ }
954
+ else if ((pszUtf8Input[1] & 0xc0) != 0x80)
955
+ {
956
+ // Invalid trail byte - pass through.
957
+ }
958
+ else if (ch <= 0xef)
959
+ {
960
+ // 0xe0..0xef: Three-byte encoding for 0x0800..0xffff.
961
+ unsigned ch2 = ((ch & 0x0f) << 12)
962
+ | ((pszUtf8Input[0] & 0x3f) << 6)
963
+ | (pszUtf8Input[1] & 0x3f);
964
+ if (0x0800 <= ch2)
965
+ {
966
+ ch = ch2;
967
+ pszUtf8Input += 2;
968
+ }
969
+ }
970
+ else if ((pszUtf8Input[2] & 0xc0) != 0x80)
971
+ {
972
+ // Invalid trail byte - pass through.
973
+ }
974
+ else if (ch <= 0xf4)
975
+ {
976
+ // 0xf0..0xf4: Four-byte encoding for 0x010000..0x10ffff.
977
+ unsigned ch2 = ((ch & 0x07) << 18)
978
+ | ((pszUtf8Input[0] & 0x3f) << 12)
979
+ | ((pszUtf8Input[1] & 0x3f) << 6)
980
+ | (pszUtf8Input[2] & 0x3f);
981
+ ch2 -= 0x10000;
982
+ if (ch2 <= 0xfffff)
983
+ {
984
+ // Decode into surrogate pair (2 wchar_t units)
985
+ pchUtf16Output[1] = static_cast<wchar_t>(0xdc00 | (ch2 & 0x3ff));
986
+ ch = 0xd800 | (ch2 >> 10);
987
+ pszUtf8Input += 3;
988
+ cchOutput = 2;
989
+ }
990
+ }
991
+
992
+ pchUtf16Output[0] = static_cast<wchar_t>(ch);
993
+ return cchOutput;
994
+ }
995
+
996
+ /*
997
+ Copies one code point of UTF-16LE data.
998
+
999
+ Note that this function requires the input buffer to be
1000
+ nul-terminated. This function may try to read several words from the
1001
+ input buffer, and the nul-termination is required to ensure that it
1002
+ doesn't read off the end of the valid buffer when copying what appears
1003
+ to be a surrogate pair.
1004
+
1005
+ pchUtf16Output:
1006
+ Buffer that receives a single code point, encoded in UTF-16-LE as one
1007
+ or two 16-bit wchar_t values.
1008
+
1009
+ pszUtf16Input:
1010
+ Pointer into a nul-terminated UTF-16-LE wchar_t sequence. On entry,
1011
+ this points to the next wchar_t to be consumed. This function will
1012
+ advance the pointer past the consumed data.
1013
+
1014
+ returns:
1015
+ The number of 16-bit wchar_t values added to pchUtf16Output (one or
1016
+ two).
1017
+ */
1018
+ static unsigned CopyUtfCodePoint(
1019
+ _Out_writes_to_(2, return) wchar_t* pchUtf16Output,
1020
+ wchar_t const*& pszUtf16Input)
1021
+ {
1022
+ unsigned cchOutput = 1;
1023
+ wchar_t ch = *pszUtf16Input;
1024
+ pszUtf16Input += 1;
1025
+ if (0xd800 <= ch && ch < 0xdc00 &&
1026
+ 0xdc00 <= *pszUtf16Input && *pszUtf16Input < 0xe000)
1027
+ {
1028
+ pchUtf16Output[1] = *pszUtf16Input;
1029
+ pszUtf16Input += 1;
1030
+ cchOutput = 2;
1031
+ }
1032
+ pchUtf16Output[0] = ch;
1033
+ return cchOutput;
1034
+ }
1035
+
1036
+ #pragma endregion
1037
+
1038
+ #pragma region GetGuidForNameImpl
1039
+
1040
+ __declspec(selectany) extern UINT32 const NamespaceValue[] = {
1041
+ 0xB22D2C48, 0xC84790C3, 0x151AF887, 0xFB30C1Bf
1042
+ };
1043
+
1044
+ template<class CharTy>
1045
+ GUID GetGuidForNameImpl(
1046
+ _In_z_ CharTy const* szUtfName)
1047
+ {
1048
+ /*
1049
+ Algorithm:
1050
+ szNameUpperBE = ByteSwap(ToUpper(szName));
1051
+ hash = SHA1(namespaceBytes + szNameUpperBE); // Does not include zero-termination in hash.
1052
+ hash[7] = (hash[7] & 0x0F) | 0x50;
1053
+ guid = First16Bytes(hash);
1054
+ */
1055
+
1056
+ WCHAR buffer[16];
1057
+ unsigned const cchBuffer = ARRAYSIZE(buffer);
1058
+ Sha1ForNonSecretPurposes sha1;
1059
+
1060
+ sha1.Append(NamespaceValue, sizeof(NamespaceValue));
1061
+ if (szUtfName[0] != 0)
1062
+ {
1063
+ CharTy const* pszName = szUtfName;
1064
+ unsigned iBuffer = 0;
1065
+ for (;;)
1066
+ {
1067
+ // CopyUtfCodePoint may add up to 2 wchar_t units to buffer.
1068
+ iBuffer += CopyUtfCodePoint(buffer + iBuffer, pszName);
1069
+ _tld_ASSERT(iBuffer <= cchBuffer, "buffer overflow");
1070
+
1071
+ bool const bDone = *pszName == 0;
1072
+ if (bDone || cchBuffer - 1 <= iBuffer)
1073
+ {
1074
+ #pragma warning(suppress: 26035) // string is counted, not nul-terminated.
1075
+ LCMapStringEx(
1076
+ LOCALE_NAME_INVARIANT,
1077
+ LCMAP_UPPERCASE | LCMAP_BYTEREV,
1078
+ buffer,
1079
+ iBuffer,
1080
+ buffer,
1081
+ iBuffer,
1082
+ NULL,
1083
+ NULL,
1084
+ 0);
1085
+ sha1.Append(buffer, iBuffer * 2);
1086
+
1087
+ if (bDone)
1088
+ {
1089
+ break;
1090
+ }
1091
+
1092
+ iBuffer = 0;
1093
+ }
1094
+ }
1095
+ }
1096
+
1097
+ UINT8* pSha1 = sha1.Finish();
1098
+
1099
+ // Set high 4 bits of octet 7 to 5, as per RFC 4122
1100
+ pSha1[7] = (pSha1[7] & 0x0f) | 0x50;
1101
+
1102
+ return *reinterpret_cast<GUID*>(pSha1);
1103
+ }
1104
+
1105
+ #pragma endregion
1106
+ }
1107
+ // namespace detail
1108
+
1109
+ #pragma region Enumerations
1110
+
1111
+ enum InType : UINT8
1112
+ {
1113
+ /*
1114
+ Invalid InType.
1115
+ */
1116
+ InTypeNull = 0,
1117
+
1118
+ /*
1119
+ A nul-terminated CHAR16 string.
1120
+ Useful OutTypes: Xml, Json.
1121
+ */
1122
+ InTypeUnicodeString,
1123
+
1124
+ /*
1125
+ A nul-terminated MBCS string.
1126
+ Useful OutTypes: Xml, Json, Utf8.
1127
+ */
1128
+ InTypeAnsiString,
1129
+
1130
+ /*
1131
+ INT8.
1132
+ Useful OutTypes: String (interprets the value as a CHAR8).
1133
+ */
1134
+ InTypeInt8,
1135
+
1136
+ /*
1137
+ UINT8.
1138
+ Useful OutTypes: String, Boolean, Hex.
1139
+ */
1140
+ InTypeUInt8,
1141
+
1142
+ /*
1143
+ INT16.
1144
+ */
1145
+ InTypeInt16,
1146
+
1147
+ /*
1148
+ UINT16.
1149
+ Useful OutTypes: String, Hex, Port.
1150
+ */
1151
+ InTypeUInt16,
1152
+
1153
+ /*
1154
+ INT32.
1155
+ Useful OutTypes: HResult.
1156
+ */
1157
+ InTypeInt32,
1158
+
1159
+ /*
1160
+ UINT32.
1161
+ Useful OutTypes: Pid, Tid, IPv4, Win32Error, NTStatus, CodePointer.
1162
+ */
1163
+ InTypeUInt32,
1164
+
1165
+ /*
1166
+ INT64.
1167
+ */
1168
+ InTypeInt64,
1169
+
1170
+ /*
1171
+ UINT64.
1172
+ Useful OutTypes: CodePointer.
1173
+ */
1174
+ InTypeUInt64,
1175
+
1176
+ /*
1177
+ FLOAT.
1178
+ */
1179
+ InTypeFloat,
1180
+
1181
+ /*
1182
+ DOUBLE.
1183
+ */
1184
+ InTypeDouble,
1185
+
1186
+ /*
1187
+ BOOL.
1188
+ */
1189
+ InTypeBool32,
1190
+
1191
+ /*
1192
+ UINT16 byte-count followed by binary data.
1193
+ Useful OutTypes: IPv6, SocketAddress, Pkcs7WithTypeInfo.
1194
+ Arrays of InTypeBinary are not supported. (No error will be reported,
1195
+ but most decoding tools will be unable to decode them).
1196
+ */
1197
+ InTypeBinary,
1198
+
1199
+ /*
1200
+ GUID.
1201
+ */
1202
+ InTypeGuid,
1203
+
1204
+ /*
1205
+ Not supported. Use InTypePointer. (No error will be reported,
1206
+ but most decoding tools will be unable to decode them).
1207
+ */
1208
+ InTypePointer_PlatformSpecific,
1209
+
1210
+ /*
1211
+ FILETIME.
1212
+ Useful OutTypes: DateTimeCultureInsensitive, DateTimeUtc.
1213
+ */
1214
+ InTypeFileTime,
1215
+
1216
+ /*
1217
+ SYSTEMTIME.
1218
+ Useful OutTypes: DateTimeCultureInsensitive, DateTimeUtc.
1219
+ */
1220
+ InTypeSystemTime,
1221
+
1222
+ /*
1223
+ SID. Size is determined from the number of subauthorities.
1224
+ */
1225
+ InTypeSid,
1226
+
1227
+ /*
1228
+ INT32.
1229
+ Useful OutTypes: Win32Error, NTStatus, CodePointer.
1230
+ */
1231
+ InTypeHexInt32,
1232
+
1233
+ /*
1234
+ INT64.
1235
+ Useful OutTypes: CodePointer.
1236
+ */
1237
+ InTypeHexInt64,
1238
+
1239
+ /*
1240
+ UINT16 byte-count followed by UTF-16 data.
1241
+ Useful OutTypes: Xml, Json.
1242
+ */
1243
+ InTypeCountedString,
1244
+
1245
+ /*
1246
+ UINT16 byte-count followed by MBCS data.
1247
+ Useful OutTypes: Xml, Json, Utf8.
1248
+ */
1249
+ InTypeCountedAnsiString,
1250
+
1251
+ /*
1252
+ This field has no value by itself, but it causes the decoder to treat
1253
+ the next N fields as part of this field. The value of N is taken from
1254
+ the field's OutType. N should not be 0.
1255
+
1256
+ Note that it is valid to have an array of structs. The array length
1257
+ will apply to the entire group of fields contained in the array.
1258
+
1259
+ The Struct type is special. Do not use it directly. Use helper APIs to
1260
+ create nested structures.
1261
+ */
1262
+ InTypeStruct,
1263
+
1264
+ /*
1265
+ UINT16 byte-count followed by binary data.
1266
+ Useful OutTypes: IPv6, SocketAddress, Pkcs7WithTypeInfo.
1267
+
1268
+ This is the same as InTypeBinary except:
1269
+ - Newer type code. Decoding support added in Windows 2018 Fall Update.
1270
+ - Decodes without the synthesized "FieldName.Length" fields.
1271
+ - Array of InTypeCountedBinary is supported.
1272
+ */
1273
+ InTypeCountedBinary,
1274
+
1275
+ /*
1276
+ INT_PTR.
1277
+ InTypeIntPtr is an alias for either InTypeInt32 or InTypeInt64.
1278
+ */
1279
+ InTypeIntPtr = sizeof(void*) == 8 ? InTypeInt64 : InTypeInt32,
1280
+
1281
+ /*
1282
+ UINT_PTR.
1283
+ InTypeUIntPtr is an alias for either InTypeUInt32 or InTypeUInt64.
1284
+ */
1285
+ InTypeUIntPtr = sizeof(void*) == 8 ? InTypeUInt64 : InTypeUInt32,
1286
+
1287
+ /*
1288
+ LPVOID.
1289
+ InTypePointer is an alias for either InTypeHexInt32 or InTypeHexInt64.
1290
+ */
1291
+ InTypePointer = sizeof(void*) == 8 ? InTypeHexInt64 : InTypeHexInt32,
1292
+
1293
+ /*
1294
+ InType must fit in 5 bits.
1295
+ */
1296
+ InTypeMask = 31
1297
+ };
1298
+
1299
+ enum OutType : UINT8
1300
+ {
1301
+ OutTypeDefault = 0x00, // Field formatted based on InType.
1302
+ OutTypeNoPrint = 0x01, // Ignored by most decoders.
1303
+ OutTypeString = 0x02, // Use with Int8, UInt8, UInt16.
1304
+ OutTypeBoolean = 0x03, // Use with UInt8.
1305
+ OutTypeHex = 0x04, // Use with UInt8, UInt16.
1306
+ OutTypePid = 0x05, // Use with UInt32.
1307
+ OutTypeTid = 0x06, // Use with UInt32.
1308
+ OutTypePort = 0x07, // Use with UInt16.
1309
+ OutTypeIPv4 = 0x08, // Use with UInt32.
1310
+ OutTypeIPv6 = 0x09, // Use with Binary, CountedBinary.
1311
+ OutTypeSocketAddress = 0x0a,// Use with Binary, CountedBinary.
1312
+ OutTypeXml = 0x0b, // Use with String types.
1313
+ OutTypeJson = 0x0c, // Use with String types.
1314
+ OutTypeWin32Error = 0x0d,// Use with UInt32, HexInt32.
1315
+ OutTypeNTStatus = 0x0e, // Use with UInt32, HexInt32.
1316
+ OutTypeHResult = 0x0f, // Use with Int32.
1317
+ OutTypeFileTime = 0x10,
1318
+ OutTypeSigned = 0x11,
1319
+ OutTypeUnsigned = 0x12,
1320
+ OutTypeDateTimeCultureInsensitive = 0x21, // Use with FileTime, SystemTime.
1321
+ OutTypeUtf8 = 0x23, // Use with AnsiString, CountedAnsiString.
1322
+ OutTypePkcs7WithTypeInfo = 0x24, // Use with Binary, CountedBinary.
1323
+ OutTypeCodePointer = 0x25, // Use with UInt32, UInt64, HexInt32, HexInt64.
1324
+ OutTypeDateTimeUtc = 0x26, // Use with FileTime, SystemTime.
1325
+ OutTypeMask = 0x7f // OutType must fit into 7 bits.
1326
+ };
1327
+
1328
+ enum Type : UINT16
1329
+ {
1330
+ /*
1331
+ Invalid type.
1332
+ */
1333
+ TypeNone = InTypeNull,
1334
+
1335
+ /*
1336
+ Encoding assumes 0-terminated CHAR16 string.
1337
+ Formatting treats as UTF-16LE string.
1338
+ */
1339
+ TypeUtf16String = InTypeUnicodeString,
1340
+
1341
+ /*
1342
+ Encoding assumes nul-terminated CHAR16 string.
1343
+ Formatting treats as UTF-16LE XML.
1344
+ */
1345
+ TypeUtf16Xml = _tld_MAKE_TYPE(InTypeUnicodeString, OutTypeXml),
1346
+
1347
+ /*
1348
+ Encoding assumes nul-terminated CHAR16 string.
1349
+ Formatting treats as UTF-16LE JSON.
1350
+ */
1351
+ TypeUtf16Json = _tld_MAKE_TYPE(InTypeUnicodeString, OutTypeJson),
1352
+
1353
+ /*
1354
+ Encoding assumes 0-terminated CHAR8 string.
1355
+ Formatting treats as MBCS string.
1356
+ */
1357
+ TypeMbcsString = InTypeAnsiString,
1358
+
1359
+ /*
1360
+ Encoding assumes nul-terminated CHAR8 string.
1361
+ Formatting treats as UTF-8 XML.
1362
+ */
1363
+ TypeMbcsXml = _tld_MAKE_TYPE(InTypeAnsiString, OutTypeXml),
1364
+
1365
+ /*
1366
+ Encoding assumes nul-terminated CHAR8 string.
1367
+ Formatting treats as UTF-8 JSON.
1368
+ */
1369
+ TypeMbcsJson = _tld_MAKE_TYPE(InTypeAnsiString, OutTypeJson),
1370
+
1371
+ /*
1372
+ Encoding assumes nul-terminated CHAR8 string.
1373
+ Formatting treats as UTF-8 string.
1374
+ */
1375
+ TypeUtf8String = _tld_MAKE_TYPE(InTypeAnsiString, OutTypeUtf8),
1376
+
1377
+ /*
1378
+ Encoding assumes 1-byte value.
1379
+ Formatting treats as signed integer.
1380
+ */
1381
+ TypeInt8 = InTypeInt8,
1382
+
1383
+ /*
1384
+ Encoding assumes 1-byte value.
1385
+ Formatting treats as unsigned integer.
1386
+ */
1387
+ TypeUInt8 = InTypeUInt8,
1388
+
1389
+ /*
1390
+ Encoding assumes 1-byte value.
1391
+ Formatting treats as hexadecimal unsigned integer.
1392
+ */
1393
+ TypeHexInt8 = _tld_MAKE_TYPE(InTypeUInt8, OutTypeHex),
1394
+
1395
+ /*
1396
+ Encoding assumes 1-byte value.
1397
+ Formatting treats as ANSI character.
1398
+ */
1399
+ TypeChar8 = _tld_MAKE_TYPE(InTypeUInt8, OutTypeString),
1400
+
1401
+ /*
1402
+ Encoding assumes 1-byte value.
1403
+ Formatting treats as Boolean.
1404
+ */
1405
+ TypeBool8 = _tld_MAKE_TYPE(InTypeUInt8, OutTypeBoolean),
1406
+
1407
+ /*
1408
+ Encoding assumes 2-byte value.
1409
+ Formatting treats as signed integer.
1410
+ */
1411
+ TypeInt16 = InTypeInt16,
1412
+
1413
+ /*
1414
+ Encoding assumes 2-byte value.
1415
+ Formatting treats as unsigned integer.
1416
+ */
1417
+ TypeUInt16 = InTypeUInt16,
1418
+
1419
+ /*
1420
+ Encoding assumes 2-byte value.
1421
+ Formatting treats as big-endian IP port(s).
1422
+ */
1423
+ TypePort = _tld_MAKE_TYPE(InTypeUInt16, OutTypePort),
1424
+
1425
+ /*
1426
+ Encoding assumes 2-byte value.
1427
+ Formatting treats as hexadecimal unsigned integer.
1428
+ */
1429
+ TypeHexInt16 = _tld_MAKE_TYPE(InTypeUInt16, OutTypeHex),
1430
+
1431
+ /*
1432
+ Encoding assumes 2-byte value.
1433
+ Formatting treats as UTF-16LE character.
1434
+ */
1435
+ TypeChar16 = _tld_MAKE_TYPE(InTypeUInt16, OutTypeString),
1436
+
1437
+ /*
1438
+ Encoding assumes 4-byte value.
1439
+ Formatting treats as signed integer.
1440
+ */
1441
+ TypeInt32 = InTypeInt32,
1442
+
1443
+ /*
1444
+ Encoding assumes 4-byte value.
1445
+ Formatting treats as HRESULT(s).
1446
+ */
1447
+ TypeHResult = _tld_MAKE_TYPE(InTypeInt32, OutTypeHResult),
1448
+
1449
+ /*
1450
+ Encoding assumes 4-byte value.
1451
+ Formatting treats as unsigned integer.
1452
+ */
1453
+ TypeUInt32 = InTypeUInt32,
1454
+
1455
+ /*
1456
+ Encoding assumes 4-byte value.
1457
+ Formatting treats as process identifier.
1458
+ */
1459
+ TypePid = _tld_MAKE_TYPE(InTypeUInt32, OutTypePid),
1460
+
1461
+ /*
1462
+ Encoding assumes 4-byte value.
1463
+ Formatting treats as thread identifier.
1464
+ */
1465
+ TypeTid = _tld_MAKE_TYPE(InTypeUInt32, OutTypeTid),
1466
+
1467
+ /*
1468
+ Encoding assumes 4-byte value.
1469
+ Formatting treats as IPv4 address.
1470
+ */
1471
+ TypeIPv4 = _tld_MAKE_TYPE(InTypeUInt32, OutTypeIPv4),
1472
+
1473
+ /*
1474
+ Encoding assumes 4-byte value.
1475
+ Formatting treats as Win32 error(s).
1476
+ */
1477
+ TypeWin32Error = _tld_MAKE_TYPE(InTypeUInt32, OutTypeWin32Error),
1478
+
1479
+ /*
1480
+ Encoding assumes 4-byte value.
1481
+ Formatting treats as NTSTATUS(s).
1482
+ */
1483
+ TypeNTStatus = _tld_MAKE_TYPE(InTypeUInt32, OutTypeNTStatus),
1484
+
1485
+ /*
1486
+ Encoding assumes 8-byte value.
1487
+ Formatting treats as signed integer.
1488
+ */
1489
+ TypeInt64 = InTypeInt64,
1490
+
1491
+ /*
1492
+ Encoding assumes 8-byte value.
1493
+ Formatting treats as unsigned integer.
1494
+ */
1495
+ TypeUInt64 = InTypeUInt64,
1496
+
1497
+ /*
1498
+ Encoding assumes 4-byte value.
1499
+ Formatting treats as Float32.
1500
+ */
1501
+ TypeFloat = InTypeFloat,
1502
+
1503
+ /*
1504
+ Encoding assumes 8-byte value.
1505
+ Formatting treats as Float64.
1506
+ */
1507
+ TypeDouble = InTypeDouble,
1508
+
1509
+ /*
1510
+ Encoding assumes 4-byte value.
1511
+ Formatting treats as Boolean.
1512
+ */
1513
+ TypeBool32 = InTypeBool32,
1514
+
1515
+ /*
1516
+ Encoding assumes 2-byte length followed by binary data.
1517
+ Formatting treats as binary blob.
1518
+ Arrays of TypeBinary are not supported. (No error will be reported,
1519
+ but most decoding tools will be unable to decode them.)
1520
+ */
1521
+ TypeBinary = InTypeBinary,
1522
+
1523
+ /*
1524
+ Encoding assumes 2-byte length followed by binary data.
1525
+ Formatting treats as IPv6 address.
1526
+ Arrays of TypeIPv6 are not supported. (No error will be reported,
1527
+ but most decoding tools will be unable to decode them.)
1528
+ */
1529
+ TypeIPv6 = _tld_MAKE_TYPE(InTypeBinary, OutTypeIPv6),
1530
+
1531
+ /*
1532
+ Encoding assumes 2-byte length followed by binary data.
1533
+ Formatting treats as SOCKADDR.
1534
+ Arrays of TypeSocketAddress are not supported. (No error will be
1535
+ reported, but most decoding tools will be unable to decode them.)
1536
+ */
1537
+ TypeSocketAddress = _tld_MAKE_TYPE(InTypeBinary, OutTypeSocketAddress),
1538
+
1539
+ /*
1540
+ Encoding assumes 16-byte value.
1541
+ Formatting treats as GUID.
1542
+ */
1543
+ TypeGuid = InTypeGuid,
1544
+
1545
+ /*
1546
+ Encoding assumes pointer-sized value.
1547
+ Formatting treats as signed integer.
1548
+ Note: the value of this enum is different on 32-bit and 64-bit systems.
1549
+ This is an alias for TypeInt32 when compiled for a 32-bit target.
1550
+ This is an alias for TypeInt64 when compiled for a 64-bit target.
1551
+ */
1552
+ TypeIntPtr = InTypeIntPtr,
1553
+
1554
+ /*
1555
+ Encoding assumes pointer-sized value.
1556
+ Formatting treats as unsigned integer.
1557
+ Note: the value of this enum is different on 32-bit and 64-bit systems.
1558
+ This is an alias for TypeUInt32 when compiled for a 32-bit target.
1559
+ This is an alias for TypeUInt64 when compiled for a 64-bit target.
1560
+ */
1561
+ TypeUIntPtr = InTypeUIntPtr,
1562
+
1563
+ /*
1564
+ Encoding assumes pointer-sized value.
1565
+ Formatting treats as hexadecimal unsigned integer.
1566
+ Note: the value of this enum is different on 32-bit and 64-bit systems.
1567
+ This is an alias for TypeHexInt32 when compiled for a 32-bit target.
1568
+ This is an alias for TypeHexInt64 when compiled for a 64-bit target.
1569
+ */
1570
+ TypePointer = InTypePointer,
1571
+
1572
+ /*
1573
+ Encoding assumes pointer-sized value.
1574
+ Formatting treats as code pointer.
1575
+ Note: the value of this enum is different on 32-bit and 64-bit systems.
1576
+ This is a subtype of TypeHexInt32 when compiled for a 32-bit target.
1577
+ This is a subtype of TypeHexInt64 when compiled for a 64-bit target.
1578
+ */
1579
+ TypeCodePointer = _tld_MAKE_TYPE(InTypePointer, OutTypeCodePointer),
1580
+
1581
+ /*
1582
+ Encoding assumes 8-byte value.
1583
+ Formatting treats as FILETIME.
1584
+ */
1585
+ TypeFileTime = InTypeFileTime,
1586
+
1587
+ /*
1588
+ Encoding assumes 16-byte value.
1589
+ Formatting treats as SYSTEMTIME.
1590
+ */
1591
+ TypeSystemTime = InTypeSystemTime,
1592
+
1593
+ /*
1594
+ Encoding assumes 16-byte value.
1595
+ Formatting treats as UTC SYSTEMTIME.
1596
+ */
1597
+ TypeSystemTimeUtc = _tld_MAKE_TYPE(InTypeSystemTime, OutTypeDateTimeUtc),
1598
+
1599
+ /*
1600
+ Encoding assumes SID. Length is determined from number of subauthorities.
1601
+ Formatting treats as a SID.
1602
+ */
1603
+ TypeSid = InTypeSid,
1604
+
1605
+ /*
1606
+ Encoding assumes 4-byte value.
1607
+ Formatting treats as hexadecimal unsigned integer.
1608
+ */
1609
+ TypeHexInt32 = InTypeHexInt32,
1610
+
1611
+ /*
1612
+ Encoding assumes 8-byte value.
1613
+ Formatting treats as hexadecimal unsigned integer.
1614
+ */
1615
+ TypeHexInt64 = InTypeHexInt64,
1616
+
1617
+ /*
1618
+ Encoding assumes 2-byte bytecount followed by CHAR16 data.
1619
+ Formatting treats as UTF-16LE string.
1620
+ */
1621
+ TypeCountedUtf16String = InTypeCountedString,
1622
+
1623
+ /*
1624
+ Encoding assumes 2-byte bytecount followed by CHAR16 data.
1625
+ Formatting treats as UTF-16LE XML.
1626
+ */
1627
+ TypeCountedUtf16Xml = _tld_MAKE_TYPE(InTypeCountedString, OutTypeXml),
1628
+
1629
+ /*
1630
+ Encoding assumes 2-byte bytecount followed by CHAR16 data.
1631
+ Formatting treats as UTF-16LE JSON.
1632
+ */
1633
+ TypeCountedUtf16Json = _tld_MAKE_TYPE(InTypeCountedString, OutTypeJson),
1634
+
1635
+ /*
1636
+ Encoding assumes 2-byte bytecount followed by CHAR8 data.
1637
+ Formatting treats as MBCS string.
1638
+ */
1639
+ TypeCountedMbcsString = InTypeCountedAnsiString,
1640
+
1641
+ /*
1642
+ Encoding assumes 2-byte bytecount followed by CHAR8 data.
1643
+ Formatting treats as UTF-8 XML.
1644
+ */
1645
+ TypeCountedMbcsXml = _tld_MAKE_TYPE(InTypeCountedAnsiString, OutTypeXml),
1646
+
1647
+ /*
1648
+ Encoding assumes 2-byte bytecount followed by CHAR8 data.
1649
+ Formatting treats as UTF-8 JSON.
1650
+ */
1651
+ TypeCountedMbcsJson = _tld_MAKE_TYPE(InTypeCountedAnsiString, OutTypeJson),
1652
+
1653
+ /*
1654
+ Encoding assumes 2-byte bytecount followed by CHAR8 data.
1655
+ Formatting treats as UTF-8 string.
1656
+ */
1657
+ TypeCountedUtf8String = _tld_MAKE_TYPE(InTypeCountedAnsiString, OutTypeUtf8),
1658
+
1659
+ /*
1660
+ Encoding assumes 2-byte length followed by binary data.
1661
+ Formatting treats as binary blob.
1662
+ Newer type code. Decoding support added in Windows 2018 Fall Update.
1663
+ */
1664
+ TypeCountedBinary = InTypeCountedBinary,
1665
+
1666
+ /*
1667
+ Encoding assumes 2-byte length followed by binary data.
1668
+ Formatting treats as IPv6 address.
1669
+ Newer type code. Decoding support added in Windows 2018 Fall Update.
1670
+ */
1671
+ TypeCountedIPv6 = _tld_MAKE_TYPE(InTypeCountedBinary, OutTypeIPv6),
1672
+
1673
+ /*
1674
+ Encoding assumes 2-byte length followed by binary data.
1675
+ Formatting treats as SOCKADDR.
1676
+ Newer type code. Decoding support added in Windows 2018 Fall Update.
1677
+ */
1678
+ TypeCountedSocketAddress = _tld_MAKE_TYPE(InTypeCountedBinary, OutTypeSocketAddress),
1679
+ };
1680
+
1681
+ enum ProviderTraitType : UINT8
1682
+ {
1683
+ ProviderTraitNone = 0, // Invalid value
1684
+ ProviderTraitGroupGuid = 1 // Data is the group GUID.
1685
+ };
1686
+
1687
+ #pragma endregion
1688
+
1689
+ #pragma region EventDescriptor
1690
+
1691
+ /*
1692
+ Simple wrapper around the ETW EVENT_DESCRIPTOR structure.
1693
+ Provides a constructor to make initialization easier.
1694
+ Can be used anywhere an EVENT_DESCRIPTOR is required.
1695
+
1696
+ Notes:
1697
+ - Channel defaults to 11 (WINEVENT_CHANNEL_TRACELOGGING). Other channels
1698
+ will only work if the provider is running on a TraceLogging-enabled OS
1699
+ (Windows 10 or later, or Windows 7 sp1 with updates, or Windows 8.1 with
1700
+ updates). If the provider is running on an earlier version of Windows and
1701
+ you use a channel other than 11, the events will not decode correctly.
1702
+ - If you are not assigning unique Ids for your events, set both Id and
1703
+ Version to 0.
1704
+ */
1705
+ struct EventDescriptor
1706
+ : EVENT_DESCRIPTOR
1707
+ {
1708
+ explicit EventDescriptor(
1709
+ UCHAR level = 5, // 5 = WINEVENT_LEVEL_VERBOSE
1710
+ ULONGLONG keyword = 0, // 0 = no keyword
1711
+ UCHAR opcode = 0, // 0 = WINEVENT_OPCODE_INFO
1712
+ USHORT task = 0) // 0 = WINEVENT_TASK_NONE
1713
+ {
1714
+ Reset(level, keyword, opcode, task);
1715
+ }
1716
+
1717
+ void Reset(
1718
+ UCHAR level = 5, // 5 = WINEVENT_LEVEL_VERBOSE
1719
+ ULONGLONG keyword = 0, // 0 = no keyword
1720
+ UCHAR opcode = 0, // 0 = WINEVENT_OPCODE_INFO
1721
+ USHORT task = 0) // 0 = WINEVENT_TASK_NONE
1722
+ {
1723
+ Id = 0;
1724
+ Version = 0;
1725
+ Channel = 11; // WINEVENT_CHANNEL_TRACELOGGING
1726
+ Level = level;
1727
+ Opcode = opcode;
1728
+ Task = task;
1729
+ Keyword = keyword;
1730
+ }
1731
+ };
1732
+
1733
+ #pragma endregion
1734
+
1735
+ #pragma region Support functions
1736
+
1737
+ #pragma warning(push)
1738
+ #pragma warning(disable: 26018) // PREfast: Potential read overflow. (Analysis is incorrect.)
1739
+
1740
+ template<class ByteBufferTy>
1741
+ void PushBackAsUtf8(
1742
+ ByteBufferTy& buffer,
1743
+ _In_z_ wchar_t const* szUtf16)
1744
+ {
1745
+ for (unsigned i = 0;; i++)
1746
+ {
1747
+ unsigned ch = szUtf16[i];
1748
+ if (ch < 0x80)
1749
+ {
1750
+ buffer.push_back(static_cast<UINT8>(ch));
1751
+ if (ch == 0)
1752
+ {
1753
+ break;
1754
+ }
1755
+ }
1756
+ else if (ch < 0x800)
1757
+ {
1758
+ buffer.push_back(static_cast<UINT8>(((ch >> 6)) | 0xc0));
1759
+ buffer.push_back(static_cast<UINT8>(((ch)& 0x3f) | 0x80));
1760
+ }
1761
+ else if (
1762
+ 0xd800 <= ch && ch < 0xdc00 &&
1763
+ 0xdc00 <= szUtf16[i + 1] && szUtf16[i + 1] < 0xe000)
1764
+ {
1765
+ // Decode surrogate pair.
1766
+ ++i;
1767
+ ch = 0x010000 + (((ch - 0xd800) << 10) | (szUtf16[i] - 0xdc00));
1768
+ buffer.push_back(static_cast<UINT8>(((ch >> 18)) | 0xf0));
1769
+ buffer.push_back(static_cast<UINT8>(((ch >> 12) & 0x3f) | 0x80));
1770
+ buffer.push_back(static_cast<UINT8>(((ch >> 6) & 0x3f) | 0x80));
1771
+ buffer.push_back(static_cast<UINT8>(((ch)& 0x3f) | 0x80));
1772
+ }
1773
+ else
1774
+ {
1775
+ buffer.push_back(static_cast<UINT8>(((ch >> 12)) | 0xe0));
1776
+ buffer.push_back(static_cast<UINT8>(((ch >> 6) & 0x3f) | 0x80));
1777
+ buffer.push_back(static_cast<UINT8>(((ch)& 0x3f) | 0x80));
1778
+ }
1779
+ }
1780
+ }
1781
+
1782
+ #pragma warning(pop)
1783
+
1784
+ inline ::tld::Type MakeType(
1785
+ ::tld::InType inType,
1786
+ ::tld::OutType outType)
1787
+ {
1788
+ return _tld_MAKE_TYPE(inType & InTypeMask, outType & OutTypeMask);
1789
+ }
1790
+
1791
+ _Use_decl_annotations_
1792
+ inline GUID GetGuidForName(
1793
+ wchar_t const* szUtf16Name)
1794
+ {
1795
+ return ::tld::detail::GetGuidForNameImpl(szUtf16Name);
1796
+ }
1797
+
1798
+ _Use_decl_annotations_
1799
+ inline GUID GetGuidForName(
1800
+ char const* szUtf8Name)
1801
+ {
1802
+ return ::tld::detail::GetGuidForNameImpl(szUtf8Name);
1803
+ }
1804
+
1805
+ inline HRESULT RegisterProvider(
1806
+ _Out_ REGHANDLE* phProvider,
1807
+ _In_ GUID const* pProviderId,
1808
+ _In_count_x_((UINT16*)pProviderMetadata) UINT8 const* pProviderMetadata,
1809
+ _In_opt_ PENABLECALLBACK pEnableCallback,
1810
+ _In_opt_ void* pEnableCallbackContext)
1811
+ {
1812
+ HRESULT hr;
1813
+ REGHANDLE hProvider = 0;
1814
+ ULONG status = ::EventRegister(
1815
+ pProviderId,
1816
+ pEnableCallback,
1817
+ pEnableCallbackContext,
1818
+ &hProvider);
1819
+ if (status == 0)
1820
+ {
1821
+ auto cbMetadata = *reinterpret_cast<UINT16 const*>(pProviderMetadata);
1822
+ status = tld::SetInformation(
1823
+ hProvider,
1824
+ static_cast<EVENT_INFO_CLASS>(2), // EventProviderSetTraits
1825
+ const_cast<UINT8*>(pProviderMetadata),
1826
+ cbMetadata);
1827
+ hr = S_OK; // Ignore any failures from SetInformation.
1828
+ }
1829
+ else
1830
+ {
1831
+ hr = HRESULT_FROM_WIN32(status);
1832
+ }
1833
+
1834
+ *phProvider = hProvider;
1835
+ return hr;
1836
+ }
1837
+
1838
+ inline HRESULT UnregisterProvider(
1839
+ REGHANDLE hProvider)
1840
+ {
1841
+ ULONG status = ::EventUnregister(hProvider);
1842
+ return HRESULT_FROM_WIN32(status);
1843
+ }
1844
+
1845
+ _Use_decl_annotations_
1846
+ inline HRESULT SetInformation(
1847
+ REGHANDLE hProvider,
1848
+ EVENT_INFO_CLASS informationClass,
1849
+ void* pvInformation,
1850
+ ULONG cbInformation)
1851
+ {
1852
+ ULONG status;
1853
+
1854
+ #if TLD_HAVE_EVENT_SET_INFORMATION == 1
1855
+
1856
+ #pragma warning(suppress: 6387) // It's ok for pvInformation to be null if cbInformation is 0.
1857
+ status = ::EventSetInformation(
1858
+ hProvider,
1859
+ informationClass,
1860
+ pvInformation,
1861
+ cbInformation);
1862
+
1863
+ #elif TLD_HAVE_EVENT_SET_INFORMATION == 2
1864
+
1865
+ HMODULE hEventing;
1866
+ status = ERROR_NOT_SUPPORTED;
1867
+ if (GetModuleHandleExW(0, L"api-ms-win-eventing-provider-l1-1-0", &hEventing) ||
1868
+ GetModuleHandleExW(0, L"advapi32.dll", &hEventing))
1869
+ {
1870
+ typedef ULONG(WINAPI* PFEventSetInformation)(
1871
+ _In_ REGHANDLE RegHandle,
1872
+ _In_ EVENT_INFO_CLASS InformationClass,
1873
+ _In_reads_bytes_opt_(InformationLength) PVOID EventInformation,
1874
+ _In_ ULONG InformationLength);
1875
+ PFEventSetInformation pfEventSetInformation =
1876
+ (PFEventSetInformation)GetProcAddress(hEventing, "EventSetInformation");
1877
+ if (pfEventSetInformation)
1878
+ {
1879
+ status = pfEventSetInformation(
1880
+ hProvider,
1881
+ informationClass,
1882
+ pvInformation,
1883
+ cbInformation);
1884
+ }
1885
+
1886
+ FreeLibrary(hEventing);
1887
+ }
1888
+
1889
+ #else // TLD_HAVE_EVENT_SET_INFORMATION == 0
1890
+
1891
+ (void)hProvider;
1892
+ (void)informationClass;
1893
+ (void)pvInformation;
1894
+ (void)cbInformation;
1895
+
1896
+ status = ERROR_NOT_SUPPORTED;
1897
+
1898
+ #endif // TLD_HAVE_EVENT_SET_INFORMATION
1899
+
1900
+ return HRESULT_FROM_WIN32(status);
1901
+ }
1902
+
1903
+ _Use_decl_annotations_
1904
+ inline HRESULT WriteEvent(
1905
+ REGHANDLE hProvider,
1906
+ EVENT_DESCRIPTOR const& eventDescriptor,
1907
+ UINT8 const* pProviderMetadata,
1908
+ UINT8 const* pEventMetadata,
1909
+ ULONG cDataDescriptors,
1910
+ EVENT_DATA_DESCRIPTOR* pDataDescriptors,
1911
+ LPCGUID pActivityId,
1912
+ LPCGUID pRelatedActivityId)
1913
+ {
1914
+ _tld_ASSERT(3 <= *(UINT16*)pProviderMetadata, "Invalid provider metadata.");
1915
+ _tld_ASSERT(4 <= *(UINT16*)pEventMetadata, "Invalid event metadata.");
1916
+ pDataDescriptors[0].Ptr = (ULONG_PTR)pProviderMetadata;
1917
+ pDataDescriptors[0].Size = *(UINT16*)pProviderMetadata;
1918
+ pDataDescriptors[0].Reserved = 2; // Descriptor contains provider metadata.
1919
+ pDataDescriptors[1].Ptr = (ULONG_PTR)pEventMetadata;
1920
+ pDataDescriptors[1].Size = *(UINT16*)pEventMetadata;
1921
+ pDataDescriptors[1].Reserved = 1; // Descriptor contains event metadata.
1922
+ ULONG status = ::EventWriteTransfer(
1923
+ hProvider,
1924
+ &eventDescriptor,
1925
+ pActivityId,
1926
+ pRelatedActivityId,
1927
+ cDataDescriptors,
1928
+ pDataDescriptors);
1929
+ return HRESULT_FROM_WIN32(status);
1930
+ }
1931
+
1932
+ #if TLD_HAVE_EVENT_WRITE_EX == 1
1933
+
1934
+ _Use_decl_annotations_
1935
+ inline HRESULT WriteEventEx(
1936
+ REGHANDLE hProvider,
1937
+ EVENT_DESCRIPTOR const& eventDescriptor,
1938
+ UINT8 const* pProviderMetadata,
1939
+ UINT8 const* pEventMetadata,
1940
+ ULONG cDataDescriptors,
1941
+ EVENT_DATA_DESCRIPTOR* pDataDescriptors,
1942
+ ULONG64 filter,
1943
+ ULONG flags,
1944
+ GUID const* pActivityId,
1945
+ GUID const* pRelatedActivityId)
1946
+ {
1947
+ _tld_ASSERT(3 <= *(UINT16*)pProviderMetadata, "Invalid provider metadata.");
1948
+ _tld_ASSERT(4 <= *(UINT16*)pEventMetadata, "Invalid event metadata.");
1949
+ pDataDescriptors[0].Ptr = (ULONG_PTR)pProviderMetadata;
1950
+ pDataDescriptors[0].Size = *(UINT16*)pProviderMetadata;
1951
+ pDataDescriptors[0].Reserved = 2; // Descriptor contains provider metadata.
1952
+ pDataDescriptors[1].Ptr = (ULONG_PTR)pEventMetadata;
1953
+ pDataDescriptors[1].Size = *(UINT16*)pEventMetadata;
1954
+ pDataDescriptors[1].Reserved = 1; // Descriptor contains event metadata.
1955
+ ULONG status = ::EventWriteEx(
1956
+ hProvider,
1957
+ &eventDescriptor,
1958
+ filter,
1959
+ flags,
1960
+ pActivityId,
1961
+ pRelatedActivityId,
1962
+ cDataDescriptors,
1963
+ pDataDescriptors);
1964
+ return HRESULT_FROM_WIN32(status);
1965
+ }
1966
+
1967
+ #endif // TLD_HAVE_EVENT_WRITE_EX
1968
+
1969
+ #pragma endregion
1970
+
1971
+ #pragma region ByteArrayWrapper
1972
+
1973
+ class ByteArrayWrapper
1974
+ {
1975
+ UINT8* m_pb;
1976
+ UINT32 m_cbMax;
1977
+ UINT32 m_cbCur;
1978
+
1979
+ public:
1980
+
1981
+ ByteArrayWrapper()
1982
+ {
1983
+ reset();
1984
+ }
1985
+
1986
+ ByteArrayWrapper(
1987
+ _Out_writes_(cbMax) UINT8* pb,
1988
+ UINT32 cbMax)
1989
+ {
1990
+ reset(pb, cbMax);
1991
+ }
1992
+
1993
+ void reset()
1994
+ {
1995
+ m_pb = 0;
1996
+ m_cbMax = 0;
1997
+ m_cbCur = 0;
1998
+ }
1999
+
2000
+ void reset(
2001
+ _Inout_updates_bytes_(cbMax) UINT8* pb,
2002
+ UINT32 cbMax)
2003
+ {
2004
+ m_pb = pb;
2005
+ m_cbMax = cbMax;
2006
+ m_cbCur = 0;
2007
+ }
2008
+
2009
+ void clear()
2010
+ {
2011
+ m_cbCur = 0;
2012
+ }
2013
+
2014
+ UINT32 size() const
2015
+ {
2016
+ return m_cbCur;
2017
+ }
2018
+
2019
+ BYTE const& front() const
2020
+ {
2021
+ return *m_pb;
2022
+ }
2023
+
2024
+ BYTE const* data() const
2025
+ {
2026
+ return m_pb;
2027
+ }
2028
+
2029
+ UINT32 capacity() const
2030
+ {
2031
+ return m_cbMax;
2032
+ }
2033
+
2034
+ void push_back(UINT8 val)
2035
+ {
2036
+ if (m_cbCur < m_cbMax)
2037
+ {
2038
+ m_pb[m_cbCur] = val;
2039
+ }
2040
+
2041
+ m_cbCur += 1;
2042
+ }
2043
+
2044
+ UINT8& operator[](UINT32 index)
2045
+ {
2046
+ static UINT8 dummy;
2047
+ return index < m_cbMax
2048
+ ? m_pb[index]
2049
+ : dummy;
2050
+ }
2051
+ };
2052
+
2053
+ #pragma endregion
2054
+
2055
+ #pragma region ProviderMetadataBuilder
2056
+
2057
+ template<class ByteBufferTy>
2058
+ class ProviderMetadataBuilder
2059
+ : public detail::MetadataBuilderBase<ByteBufferTy>
2060
+ {
2061
+ /*
2062
+ ProviderMetadata =
2063
+ Size : UINT16; // Size counts the whole data structure, including the Size field.
2064
+ Name : Nul-terminated UTF-8.
2065
+ Traits[]: ProviderTrait (parse until you have consumed Size bytes)
2066
+
2067
+ ProviderTrait =
2068
+ TraitSize: UINT16;
2069
+ TraitType: UINT8;
2070
+ TraitData: UINT8[TraitSize - 3];
2071
+ */
2072
+
2073
+ public:
2074
+
2075
+ explicit ProviderMetadataBuilder(ByteBufferTy& buffer)
2076
+ : detail::MetadataBuilderBase<ByteBufferTy>(buffer)
2077
+ {
2078
+ return;
2079
+ }
2080
+
2081
+ template<class CharTy>
2082
+ void Begin(
2083
+ _In_z_ CharTy const* szUtfProviderName)
2084
+ {
2085
+ this->BaseBegin();
2086
+ this->AddString(szUtfProviderName);
2087
+ }
2088
+
2089
+ void AddTrait(
2090
+ ProviderTraitType type,
2091
+ _In_reads_bytes_(cbData) void const* pData,
2092
+ unsigned cbData)
2093
+ {
2094
+ this->AddU16(static_cast<UINT16>(cbData + 3));
2095
+ this->AddU8(static_cast<UINT8>(type));
2096
+ this->AddBytes(pData, cbData);
2097
+ }
2098
+
2099
+ bool End()
2100
+ {
2101
+ return this->BaseEnd();
2102
+ }
2103
+ };
2104
+
2105
+ #pragma endregion
2106
+
2107
+ #pragma region EventMetadataBuilder
2108
+
2109
+ template<class ByteBufferTy>
2110
+ class EventMetadataBuilder
2111
+ : public detail::MetadataBuilderBase<ByteBufferTy>
2112
+ {
2113
+ /*
2114
+ EventMetadata =
2115
+ Size : UINT16; // Size counts the whole data structure, including the Size field.
2116
+ Tags[] : UINT8 (read bytes until you encounter a byte with high bit unset);
2117
+ Name : Nul-terminated UTF-8;
2118
+ Fields[]: FieldMetadata (parse until you get to end of EventMetadata);
2119
+
2120
+ FieldMetadata =
2121
+ Name : Nul-terminated UTF-8.
2122
+ InMeta : UINT8.
2123
+ OutMeta : UINT8 (only present if InMeta & InMetaChain);
2124
+ Tags[] : UINT8 (only present if OutMeta & OutMetaChain, read bytes until you encounter a byte with high bit unset);
2125
+ Ccount : UINT16 (only present if InMeta & InMetaCountMask == InMetaCcount);
2126
+ CbSchema: UINT16 (only present if InMeta & InMetaCountMask == InMetaCustom);
2127
+ Schema : UINT8[CbSchema]
2128
+ */
2129
+
2130
+ static const UINT8 InMetaScalar = 0;
2131
+ static const UINT8 InMetaCcount = 32;
2132
+ static const UINT8 InMetaVcount = 64;
2133
+ static const UINT8 InMetaCustom = 96;
2134
+ static const UINT8 InMetaCountMask = 96;
2135
+ static const UINT8 InMetaChain = 128;
2136
+ static const UINT8 OutMetaChain = 128;
2137
+
2138
+ UINT32 const m_bookmark;
2139
+
2140
+ EventMetadataBuilder(
2141
+ ByteBufferTy& buffer,
2142
+ UINT32 bookmark)
2143
+ : detail::MetadataBuilderBase<ByteBufferTy>(buffer)
2144
+ , m_bookmark(bookmark)
2145
+ {
2146
+ return;
2147
+ }
2148
+
2149
+ void AddTags(UINT32 tags)
2150
+ {
2151
+ _tld_ASSERT(0 == (tags & 0xf0000000), "Tags only supports 28-bit values.");
2152
+ for (;;)
2153
+ {
2154
+ auto val = static_cast<UINT8>(tags >> 21);
2155
+ if ((tags & 0x1fffff) == 0)
2156
+ {
2157
+ this->AddU8(val & 0x7f);
2158
+ break;
2159
+ }
2160
+
2161
+ this->AddU8(val | 0x80);
2162
+ tags = tags << 7;
2163
+ }
2164
+ }
2165
+
2166
+ void AddFieldInfo(UINT8 arity, Type type, UINT32 tags)
2167
+ {
2168
+ _tld_ASSERT((type & (Type)InTypeMask) == (type & 0xff), "InType out of range");
2169
+ _tld_ASSERT((type & _tld_MAKE_TYPE(0, OutTypeMask)) == (Type)(type & 0xffffff00), "OutType out of range");
2170
+
2171
+ UINT8 inMeta = arity | static_cast<UINT8>(type);
2172
+ UINT8 outMeta = static_cast<UINT8>(type >> 8);
2173
+ if (tags != 0)
2174
+ {
2175
+ this->AddU8(static_cast<UINT8>(inMeta | InMetaChain));
2176
+ this->AddU8(static_cast<UINT8>(outMeta | OutMetaChain));
2177
+ AddTags(tags);
2178
+ }
2179
+ else if (outMeta != 0)
2180
+ {
2181
+ this->AddU8(static_cast<UINT8>(inMeta | InMetaChain));
2182
+ this->AddU8(static_cast<UINT8>(outMeta));
2183
+ }
2184
+ else
2185
+ {
2186
+ this->AddU8(inMeta);
2187
+ }
2188
+
2189
+ if (m_bookmark != 0)
2190
+ {
2191
+ this->IncrementU7(m_bookmark);
2192
+ }
2193
+ }
2194
+
2195
+ UINT32 AddStructInfo(UINT8 arity, UINT32 tags)
2196
+ {
2197
+ UINT8 inMeta = arity | InTypeStruct;
2198
+ this->AddU8(static_cast<UINT8>(inMeta | InMetaChain));
2199
+ UINT32 bookmark = this->GetBookmark();
2200
+ if (tags == 0)
2201
+ {
2202
+ this->AddU8(0);
2203
+ }
2204
+ else
2205
+ {
2206
+ this->AddU8(OutMetaChain);
2207
+ AddTags(tags);
2208
+ }
2209
+
2210
+ if (m_bookmark != 0)
2211
+ {
2212
+ this->IncrementU7(m_bookmark);
2213
+ }
2214
+
2215
+ return bookmark;
2216
+ }
2217
+
2218
+ public:
2219
+
2220
+ explicit EventMetadataBuilder(
2221
+ ByteBufferTy& buffer)
2222
+ : detail::MetadataBuilderBase<ByteBufferTy>(buffer)
2223
+ , m_bookmark(0)
2224
+ {
2225
+ return;
2226
+ }
2227
+
2228
+ EventMetadataBuilder(EventMetadataBuilder& other)
2229
+ : detail::MetadataBuilderBase<ByteBufferTy>(other.GetBuffer())
2230
+ , m_bookmark(other.m_bookmark)
2231
+ {
2232
+ return;
2233
+ }
2234
+
2235
+ EventMetadataBuilder(EventMetadataBuilder&& other)
2236
+ : detail::MetadataBuilderBase<ByteBufferTy>(other.GetBuffer())
2237
+ , m_bookmark(other.m_bookmark)
2238
+ {
2239
+ return;
2240
+ }
2241
+
2242
+ template<class CharTy>
2243
+ void Begin(
2244
+ _In_z_ CharTy const* szUtfEventName,
2245
+ UINT32 eventTags = 0)
2246
+ {
2247
+ _tld_ASSERT(m_bookmark == 0, "Must not call Begin on a struct builder");
2248
+ this->BaseBegin();
2249
+ AddTags(eventTags);
2250
+ this->AddString(szUtfEventName);
2251
+ }
2252
+
2253
+ bool End()
2254
+ {
2255
+ _tld_ASSERT(m_bookmark == 0, "Must not call End on a struct builder");
2256
+ return this->BaseEnd();
2257
+ }
2258
+
2259
+ // Note: Do not create structs with 0 fields.
2260
+ template<class CharTy>
2261
+ EventMetadataBuilder AddStruct(
2262
+ _In_z_ CharTy const* szUtfStructName,
2263
+ UINT32 fieldTags = 0)
2264
+ {
2265
+ this->AddString(szUtfStructName);
2266
+ auto bookmark = AddStructInfo(InMetaScalar, fieldTags);
2267
+ return EventMetadataBuilder(this->GetBuffer(), bookmark);
2268
+ }
2269
+
2270
+ // Note: Do not create structs with 0 fields.
2271
+ template<class CharTy>
2272
+ UINT32 AddStructRaw(
2273
+ _In_z_ CharTy const* szUtfStructName,
2274
+ UINT32 fieldTags = 0)
2275
+ {
2276
+ this->AddString(szUtfStructName);
2277
+ auto bookmark = AddStructInfo(InMetaScalar, fieldTags);
2278
+ return bookmark;
2279
+ }
2280
+
2281
+ // Note: Do not create structs with 0 fields.
2282
+ template<class CharTy>
2283
+ EventMetadataBuilder AddStructArray(
2284
+ _In_z_ CharTy const* szUtfStructName,
2285
+ UINT32 fieldTags = 0)
2286
+ {
2287
+ this->AddString(szUtfStructName);
2288
+ auto bookmark = AddStructInfo(InMetaVcount, fieldTags);
2289
+ return EventMetadataBuilder(this->GetBuffer(), bookmark);
2290
+ }
2291
+
2292
+ // Note: Do not use 0 for itemCount.
2293
+ // Note: Do not create structs with 0 fields.
2294
+ template<class CharTy>
2295
+ EventMetadataBuilder AddStructFixedArray(
2296
+ _In_z_ CharTy const* szUtfStructName,
2297
+ UINT16 itemCount,
2298
+ UINT32 fieldTags = 0)
2299
+ {
2300
+ this->AddString(szUtfStructName);
2301
+ auto bookmark = AddStructInfo(InMetaCcount, fieldTags);
2302
+ this->AddU16(itemCount);
2303
+ return EventMetadataBuilder(this->GetBuffer(), bookmark);
2304
+ }
2305
+
2306
+ template<class CharTy>
2307
+ void AddField(
2308
+ _In_z_ CharTy const* szUtfFieldName,
2309
+ Type type,
2310
+ UINT32 fieldTags = 0)
2311
+ {
2312
+ this->AddString(szUtfFieldName);
2313
+ AddFieldInfo(InMetaScalar, type, fieldTags);
2314
+ }
2315
+
2316
+ template<class CharTy>
2317
+ void AddFieldArray(
2318
+ _In_z_ CharTy const* szUtfFieldName,
2319
+ Type type,
2320
+ UINT32 fieldTags = 0)
2321
+ {
2322
+ this->AddString(szUtfFieldName);
2323
+ AddFieldInfo(InMetaVcount, type, fieldTags);
2324
+ }
2325
+
2326
+ // Note: Do not use 0 for itemCount.
2327
+ template<class CharTy>
2328
+ void AddFieldFixedArray(
2329
+ _In_z_ CharTy const* szUtfFieldName,
2330
+ UINT16 itemCount,
2331
+ Type type,
2332
+ UINT32 fieldTags = 0)
2333
+ {
2334
+ this->AddString(szUtfFieldName);
2335
+ AddFieldInfo(InMetaCcount, type, fieldTags);
2336
+ this->AddU16(itemCount);
2337
+ }
2338
+
2339
+ template<class CharTy>
2340
+ void AddFieldCustom(
2341
+ _In_z_ CharTy const* szUtfFieldName,
2342
+ _In_reads_bytes_(cbSchema) void const* pSchema,
2343
+ UINT16 cbSchema,
2344
+ Type type,
2345
+ UINT32 fieldTags = 0)
2346
+ {
2347
+ this->AddString(szUtfFieldName);
2348
+ AddFieldInfo(InMetaCustom, type, fieldTags);
2349
+ this->AddU16(cbSchema);
2350
+ auto pbSchema = static_cast<UINT8 const*>(pSchema);
2351
+ for (UINT32 i = 0; i != cbSchema; i++)
2352
+ {
2353
+ this->AddU8(pbSchema[i]);
2354
+ }
2355
+ }
2356
+ };
2357
+
2358
+ #pragma endregion
2359
+
2360
+ #pragma region EventDataBuilder
2361
+
2362
+ template<class ByteBufferTy>
2363
+ class EventDataBuilder
2364
+ {
2365
+ void operator=(EventDataBuilder const&); // = delete
2366
+ ByteBufferTy& m_buffer;
2367
+
2368
+ public:
2369
+
2370
+ explicit EventDataBuilder(ByteBufferTy& buffer)
2371
+ : m_buffer(buffer)
2372
+ {
2373
+ return;
2374
+ }
2375
+
2376
+ EventDataBuilder(EventDataBuilder& other)
2377
+ : m_buffer(other.m_buffer)
2378
+ {
2379
+ return;
2380
+ }
2381
+
2382
+ EventDataBuilder(EventDataBuilder&& other)
2383
+ : m_buffer(other.m_buffer)
2384
+ {
2385
+ return;
2386
+ }
2387
+
2388
+ ByteBufferTy& Buffer()
2389
+ {
2390
+ return m_buffer;
2391
+ }
2392
+
2393
+ ByteBufferTy const& Buffer() const
2394
+ {
2395
+ return m_buffer;
2396
+ }
2397
+
2398
+ void Clear()
2399
+ {
2400
+ m_buffer.clear();
2401
+ }
2402
+
2403
+ UINT32 Size() const
2404
+ {
2405
+ return static_cast<UINT32>(m_buffer.size());
2406
+ }
2407
+
2408
+ UINT8& operator[](UINT32 index)
2409
+ {
2410
+ return m_buffer[index];
2411
+ }
2412
+
2413
+ void AddArrayCount(UINT16 cItems)
2414
+ {
2415
+ AddBytes(&cItems, sizeof(cItems));
2416
+ }
2417
+
2418
+ /*
2419
+ Adds a value to the payload.
2420
+ Note: should only be used for blittable POD types with no padding.
2421
+ */
2422
+ template<class T>
2423
+ void AddValue(T const& value)
2424
+ {
2425
+ AddBytes(&reinterpret_cast<const char&>(value), sizeof(T));
2426
+ }
2427
+
2428
+ /*
2429
+ Adds an array of values to the payload.
2430
+ Note: should only be used for blittable POD types with no padding.
2431
+ */
2432
+ template<class T>
2433
+ void AddValues(_In_reads_(cValues) T const* pValues, unsigned cValues)
2434
+ {
2435
+ AddBytes(pValues, sizeof(T) * cValues);
2436
+ }
2437
+
2438
+ /*
2439
+ Appends an InTypeBinary or InTypeCountedBinary field to the payload.
2440
+ Compatible with: Type[Counted]Binary, Type[Counted]IPv6, Type[Counted]SocketAddress.
2441
+ */
2442
+ void AddBinary(_In_reads_bytes_(cbData) void const* pbData, UINT16 cbData)
2443
+ {
2444
+ AddBytes(&cbData, sizeof(cbData));
2445
+ AddBytes(pbData, cbData);
2446
+ }
2447
+
2448
+ /*
2449
+ Appends an InTypeCountedAnsiString field to the payload.
2450
+ Compatible with: TypeCountedMbcsString, TypeCountedMbcsXml, TypeCountedMbcsJson.
2451
+ */
2452
+ void AddCountedString(_In_reads_(cch) char const* pch, UINT16 cch)
2453
+ {
2454
+ AddBinary(pch, cch * sizeof(*pch));
2455
+ }
2456
+
2457
+ /*
2458
+ Appends an InTypeCountedString field to the payload.
2459
+ Compatible with: TypeCountedUtf16String, TypeCountedUtf16Xml, TypeCountedUtf16Json.
2460
+ */
2461
+ void AddCountedString(_In_reads_(cch) wchar_t const* pch, UINT16 cch)
2462
+ {
2463
+ AddBinary(pch, cch * sizeof(*pch));
2464
+ }
2465
+
2466
+ /*
2467
+ Appends an InTypeAnsiString field to the payload.
2468
+ Compatible with: TypeMbcsString, TypeMbcsXml, TypeMbcsJson.
2469
+ */
2470
+ void AddString(_In_z_ char const* psz)
2471
+ {
2472
+ AddBytes(psz, static_cast<unsigned>(strlen(psz) + 1));
2473
+ }
2474
+
2475
+ /*
2476
+ Appends a InTypeUnicodeString field to the payload.
2477
+ Compatible with: TypeUtf16String, TypeUtf16Xml, TypeUtf16Json
2478
+ */
2479
+ void AddString(_In_z_ wchar_t const* psz)
2480
+ {
2481
+ AddBytes(psz, static_cast<unsigned>(2 * (wcslen(psz) + 1)));
2482
+ }
2483
+
2484
+ /*
2485
+ Appends a raw byte to the payload. (Calls buffer.push_back)
2486
+ */
2487
+ void AddByte(UINT8 val)
2488
+ {
2489
+ m_buffer.push_back(val);
2490
+ }
2491
+
2492
+ /*
2493
+ Appends raw bytes to the payload. (Calls buffer.insert)
2494
+ */
2495
+ void AddBytes(_In_reads_bytes_(cbData) void const* pbData, unsigned cbData)
2496
+ {
2497
+ auto pb = static_cast<UINT8 const*>(pbData);
2498
+ m_buffer.insert(m_buffer.end(), pb + 0, pb + cbData);
2499
+ }
2500
+ };
2501
+
2502
+ #pragma endregion
2503
+
2504
+ #pragma region Provider
2505
+
2506
+ class Provider
2507
+ {
2508
+ Provider(Provider const&); // = delete
2509
+ void operator=(Provider const&); // = delete
2510
+
2511
+ UINT32 m_levelPlus1;
2512
+ HRESULT m_hrInitialization;
2513
+ ULONGLONG m_keywordsAny;
2514
+ ULONGLONG m_keywordsAll;
2515
+ REGHANDLE m_hProvider;
2516
+ UINT8 const* m_pbMetadata;
2517
+ PENABLECALLBACK m_pfCallback;
2518
+ LPVOID m_pCallbackContext;
2519
+ GUID m_id;
2520
+
2521
+ /*
2522
+ Shortest possible valid provider metadata blob:
2523
+ Size = 0x0003, Name = "", no options.
2524
+ */
2525
+ static _Ret_bytecount_(3) UINT8 const* NullMetadata()
2526
+ {
2527
+ return reinterpret_cast<UINT8 const*>("\03\0");
2528
+ }
2529
+
2530
+ static VOID NTAPI EnableCallback(
2531
+ _In_ LPCGUID pSourceId,
2532
+ _In_ ULONG callbackType,
2533
+ _In_ UCHAR level,
2534
+ _In_ ULONGLONG keywordsAny,
2535
+ _In_ ULONGLONG keywordsAll,
2536
+ _In_opt_ PEVENT_FILTER_DESCRIPTOR pFilterData,
2537
+ _Inout_opt_ PVOID pCallbackContext)
2538
+ {
2539
+ if (pCallbackContext)
2540
+ {
2541
+ Provider* pProvider = static_cast<Provider*>(pCallbackContext);
2542
+ switch (callbackType)
2543
+ {
2544
+ case 0: // EVENT_CONTROL_CODE_DISABLE_PROVIDER
2545
+ pProvider->m_levelPlus1 = 0;
2546
+ break;
2547
+ case 1: // EVENT_CONTROL_CODE_ENABLE_PROVIDER
2548
+ pProvider->m_levelPlus1 = level != 0 ? (UINT32)level + 1u : 256u;
2549
+ pProvider->m_keywordsAny = keywordsAny;
2550
+ pProvider->m_keywordsAll = keywordsAll;
2551
+ break;
2552
+ }
2553
+
2554
+ if (pProvider->m_pfCallback)
2555
+ {
2556
+ pProvider->m_pfCallback(
2557
+ pSourceId,
2558
+ callbackType,
2559
+ level,
2560
+ keywordsAny,
2561
+ keywordsAll,
2562
+ pFilterData,
2563
+ pProvider->m_pCallbackContext);
2564
+ }
2565
+ }
2566
+ }
2567
+
2568
+ _Ret_opt_bytecount_(cbMetadata)
2569
+ static UINT8* MetadataAlloc(
2570
+ UINT32 cbMetadata)
2571
+ {
2572
+ return static_cast<UINT8*>(HeapAlloc(GetProcessHeap(), 0, cbMetadata));
2573
+ }
2574
+
2575
+ static void MetadataFree(
2576
+ _Post_invalid_ UINT8* pbMetadata)
2577
+ {
2578
+ if (pbMetadata)
2579
+ {
2580
+ HeapFree(GetProcessHeap(), 0, pbMetadata);
2581
+ }
2582
+ }
2583
+
2584
+ void InitFail(
2585
+ HRESULT hr)
2586
+ {
2587
+ _tld_ASSERT(m_pbMetadata != NullMetadata(), "InitFail called with m_pbMetadata == NullMetadata()");
2588
+ MetadataFree(const_cast<UINT8*>(m_pbMetadata));
2589
+ m_hrInitialization = hr;
2590
+ m_pbMetadata = NullMetadata();
2591
+ }
2592
+
2593
+ template<class CharTy>
2594
+ void Init(
2595
+ _In_z_ CharTy const* szName,
2596
+ _In_opt_ GUID const* pGroupId)
2597
+ {
2598
+ // Already initialized: m_pfCallback, m_pCallbackContext, m_id.
2599
+ m_levelPlus1 = 0;
2600
+ m_hrInitialization = 0;
2601
+ m_keywordsAny = 0;
2602
+ m_keywordsAll = 0;
2603
+ m_hProvider = 0;
2604
+ m_pbMetadata = 0;
2605
+
2606
+ ByteArrayWrapper wrapper(0, 0);
2607
+ ProviderMetadataBuilder<ByteArrayWrapper> builder(wrapper);
2608
+ builder.Begin(szName);
2609
+ if (pGroupId)
2610
+ {
2611
+ builder.AddTrait(ProviderTraitGroupGuid, pGroupId, sizeof(GUID));
2612
+ }
2613
+ if (!builder.End())
2614
+ {
2615
+ InitFail(E_INVALIDARG); // Metadata > 64KB.
2616
+ goto Done;
2617
+ }
2618
+
2619
+ {
2620
+ UINT32 const cbMetadata = wrapper.size();
2621
+ UINT8* pbMetadata = MetadataAlloc(cbMetadata);
2622
+ if (!pbMetadata)
2623
+ {
2624
+ InitFail(E_OUTOFMEMORY);
2625
+ goto Done;
2626
+ }
2627
+
2628
+ m_pbMetadata = pbMetadata;
2629
+ wrapper.reset(pbMetadata, cbMetadata);
2630
+ builder.Begin(szName);
2631
+ if (pGroupId)
2632
+ {
2633
+ builder.AddTrait(ProviderTraitGroupGuid, pGroupId, sizeof(GUID));
2634
+ }
2635
+ if (!builder.End() || cbMetadata < wrapper.size())
2636
+ {
2637
+ InitFail(0x8000000CL); // E_CHANGED_STATE
2638
+ goto Done;
2639
+ }
2640
+
2641
+ {
2642
+ HRESULT hr = ::tld::RegisterProvider(&m_hProvider, &m_id, m_pbMetadata, &EnableCallback, this);
2643
+ if (FAILED(hr))
2644
+ {
2645
+ InitFail(hr);
2646
+ }
2647
+ }
2648
+ }
2649
+
2650
+ Done:
2651
+
2652
+ return;
2653
+ }
2654
+
2655
+ bool IsEnabledForKeywords(ULONGLONG keywords) const
2656
+ {
2657
+ return keywords == 0 || (
2658
+ (keywords & m_keywordsAny) != 0 &&
2659
+ (keywords & m_keywordsAll) == m_keywordsAll);
2660
+ }
2661
+
2662
+ public:
2663
+
2664
+ ~Provider()
2665
+ {
2666
+ EventUnregister(m_hProvider);
2667
+ if (m_pbMetadata != NullMetadata())
2668
+ {
2669
+ MetadataFree(const_cast<UINT8*>(m_pbMetadata));
2670
+ }
2671
+ }
2672
+
2673
+ Provider(
2674
+ _In_z_ wchar_t const* szUtf16Name,
2675
+ GUID const& providerId,
2676
+ _In_opt_ GUID const* pGroupId = 0,
2677
+ PENABLECALLBACK pfCallback = 0,
2678
+ LPVOID pCallbackContext = 0)
2679
+ : m_pfCallback(pfCallback)
2680
+ , m_pCallbackContext(pCallbackContext)
2681
+ , m_id(providerId)
2682
+ {
2683
+ Init(szUtf16Name, pGroupId);
2684
+ }
2685
+
2686
+ Provider(
2687
+ _In_z_ char const* szUtf8Name,
2688
+ GUID const& providerId,
2689
+ _In_opt_ GUID const* pGroupId = 0,
2690
+ PENABLECALLBACK pfCallback = 0,
2691
+ LPVOID pCallbackContext = 0)
2692
+ : m_pfCallback(pfCallback)
2693
+ , m_pCallbackContext(pCallbackContext)
2694
+ , m_id(providerId)
2695
+ {
2696
+ Init(szUtf8Name, pGroupId);
2697
+ }
2698
+
2699
+ explicit Provider(
2700
+ _In_z_ wchar_t const* szUtf16Name,
2701
+ _In_opt_ GUID const* pGroupId = 0,
2702
+ PENABLECALLBACK pfCallback = 0,
2703
+ LPVOID pCallbackContext = 0)
2704
+ : m_pfCallback(pfCallback)
2705
+ , m_pCallbackContext(pCallbackContext)
2706
+ , m_id(GetGuidForName(szUtf16Name))
2707
+ {
2708
+ Init(szUtf16Name, pGroupId);
2709
+ }
2710
+
2711
+ explicit Provider(
2712
+ _In_z_ char const* szUtf8Name,
2713
+ _In_opt_ GUID const* pGroupId = 0,
2714
+ PENABLECALLBACK pfCallback = 0,
2715
+ LPVOID pCallbackContext = 0)
2716
+ : m_pfCallback(pfCallback)
2717
+ , m_pCallbackContext(pCallbackContext)
2718
+ , m_id(GetGuidForName(szUtf8Name))
2719
+ {
2720
+ Init(szUtf8Name, pGroupId);
2721
+ }
2722
+
2723
+ HRESULT InitializationResult() const
2724
+ {
2725
+ return m_hrInitialization;
2726
+ }
2727
+
2728
+ _Ret_z_ char const* Name() const
2729
+ {
2730
+ return reinterpret_cast<char const*>(m_pbMetadata + 2);
2731
+ }
2732
+
2733
+ GUID const& Id() const
2734
+ {
2735
+ return m_id;
2736
+ }
2737
+
2738
+ _Ret_notnull_ UINT8 const* GetMetadata() const
2739
+ {
2740
+ return m_pbMetadata;
2741
+ }
2742
+
2743
+ UINT16 GetMetadataSize() const
2744
+ {
2745
+ return *reinterpret_cast<UINT16 const*>(m_pbMetadata);
2746
+ }
2747
+
2748
+ bool IsEnabled() const
2749
+ {
2750
+ return m_levelPlus1 != 0;
2751
+ }
2752
+
2753
+ bool IsEnabled(UCHAR level) const
2754
+ {
2755
+ return level < m_levelPlus1;
2756
+ }
2757
+
2758
+ bool IsEnabled(UCHAR level, ULONGLONG keyword) const
2759
+ {
2760
+ return level < m_levelPlus1 && IsEnabledForKeywords(keyword);
2761
+ }
2762
+
2763
+ HRESULT SetInformation(
2764
+ EVENT_INFO_CLASS informationClass,
2765
+ _In_reads_bytes_opt_(cbInformation) void* pbInformation,
2766
+ ULONG cbInformation
2767
+ ) const
2768
+ {
2769
+ return ::tld::SetInformation(m_hProvider, informationClass, pbInformation, cbInformation);
2770
+ }
2771
+
2772
+ HRESULT WriteGather(
2773
+ EVENT_DESCRIPTOR const& eventDescriptor,
2774
+ _In_count_x_((UINT16*)pEventMetadata) UINT8 const* pEventMetadata,
2775
+ _In_range_(2, 128) ULONG cDataDescriptors,
2776
+ _Inout_count_(cDataDescriptors) EVENT_DATA_DESCRIPTOR* pDataDescriptors,
2777
+ _In_opt_ LPCGUID pActivityId = 0,
2778
+ _In_opt_ LPCGUID pRelatedActivityId = 0
2779
+ ) const
2780
+ {
2781
+ return ::tld::WriteEvent(
2782
+ m_hProvider,
2783
+ eventDescriptor,
2784
+ m_pbMetadata,
2785
+ pEventMetadata,
2786
+ cDataDescriptors,
2787
+ pDataDescriptors,
2788
+ pActivityId,
2789
+ pRelatedActivityId);
2790
+ }
2791
+
2792
+ HRESULT Write(
2793
+ EVENT_DESCRIPTOR const& eventDescriptor,
2794
+ _In_count_x_((UINT16*)pEventMetadata) UINT8 const* pEventMetadata,
2795
+ _In_reads_bytes_(cbData) LPCVOID pbData,
2796
+ UINT32 cbData,
2797
+ _In_opt_ LPCGUID pActivityId = 0,
2798
+ _In_opt_ LPCGUID pRelatedActivityId = 0
2799
+ ) const
2800
+ {
2801
+ EVENT_DATA_DESCRIPTOR dataDesc[3];
2802
+ EventDataDescCreate(dataDesc + 2, pbData, cbData);
2803
+ return ::tld::WriteEvent(
2804
+ m_hProvider,
2805
+ eventDescriptor,
2806
+ m_pbMetadata,
2807
+ pEventMetadata,
2808
+ cbData ? 3 : 2,
2809
+ dataDesc,
2810
+ pActivityId,
2811
+ pRelatedActivityId);
2812
+ }
2813
+
2814
+ #if TLD_HAVE_EVENT_WRITE_EX == 1
2815
+
2816
+ HRESULT WriteGatherEx(
2817
+ EVENT_DESCRIPTOR const& eventDescriptor,
2818
+ _In_count_x_((UINT16*)pEventMetadata) UINT8 const* pEventMetadata,
2819
+ _In_range_(2, 128) ULONG cDataDescriptors,
2820
+ _Inout_count_(cDataDescriptors) EVENT_DATA_DESCRIPTOR* pDataDescriptors,
2821
+ ULONG64 filter,
2822
+ ULONG flags,
2823
+ _In_opt_ LPCGUID pActivityId = 0,
2824
+ _In_opt_ LPCGUID pRelatedActivityId = 0
2825
+ ) const
2826
+ {
2827
+ return ::tld::WriteEventEx(
2828
+ m_hProvider,
2829
+ eventDescriptor,
2830
+ m_pbMetadata,
2831
+ pEventMetadata,
2832
+ cDataDescriptors,
2833
+ pDataDescriptors,
2834
+ filter,
2835
+ flags,
2836
+ pActivityId,
2837
+ pRelatedActivityId);
2838
+ }
2839
+
2840
+ HRESULT WriteEx(
2841
+ EVENT_DESCRIPTOR const& eventDescriptor,
2842
+ _In_count_x_((UINT16*)pEventMetadata) UINT8 const* pEventMetadata,
2843
+ _In_reads_bytes_(cbData) LPCVOID pbData,
2844
+ UINT32 cbData,
2845
+ ULONG64 filter,
2846
+ ULONG flags,
2847
+ _In_opt_ LPCGUID pActivityId = 0,
2848
+ _In_opt_ LPCGUID pRelatedActivityId = 0
2849
+ ) const
2850
+ {
2851
+ EVENT_DATA_DESCRIPTOR dataDesc[3];
2852
+ EventDataDescCreate(dataDesc + 2, pbData, cbData);
2853
+ return ::tld::WriteEventEx(
2854
+ m_hProvider,
2855
+ eventDescriptor,
2856
+ m_pbMetadata,
2857
+ pEventMetadata,
2858
+ cbData ? 3 : 2,
2859
+ dataDesc,
2860
+ filter,
2861
+ flags,
2862
+ pActivityId,
2863
+ pRelatedActivityId);
2864
+ }
2865
+
2866
+ #endif // TLD_HAVE_EVENT_WRITE_EX
2867
+ };
2868
+
2869
+ #pragma endregion
2870
+
2871
+ #pragma region EventBuilder
2872
+
2873
+ enum EventState
2874
+ {
2875
+ EventStateOpen,
2876
+ EventStateClosed,
2877
+ EventStateError
2878
+ };
2879
+
2880
+ template<class ByteBufferTy>
2881
+ class EventBuilder
2882
+ {
2883
+ void operator=(EventBuilder const&); // = delete
2884
+
2885
+ EventMetadataBuilder<ByteBufferTy> m_metaBuilder;
2886
+ EventDataBuilder<ByteBufferTy> m_dataBuilder;
2887
+ EventState& m_eventState;
2888
+
2889
+ EventBuilder(EventBuilder& other, EventMetadataBuilder<ByteBufferTy>&& metaBuilder)
2890
+ : m_metaBuilder(metaBuilder)
2891
+ , m_dataBuilder(other.m_dataBuilder)
2892
+ , m_eventState(other.m_eventState)
2893
+ {
2894
+ return;
2895
+ }
2896
+
2897
+ protected:
2898
+
2899
+ EventBuilder(
2900
+ ByteBufferTy& metaBuffer,
2901
+ ByteBufferTy& dataBuffer,
2902
+ EventState& eventState)
2903
+ : m_metaBuilder(metaBuffer)
2904
+ , m_dataBuilder(dataBuffer)
2905
+ , m_eventState(eventState)
2906
+ {
2907
+ return;
2908
+ }
2909
+
2910
+ public:
2911
+
2912
+ EventBuilder(EventBuilder& other)
2913
+ : m_metaBuilder(other.m_metaBuilder)
2914
+ , m_dataBuilder(other.m_dataBuilder)
2915
+ , m_eventState(other.m_eventState)
2916
+ {
2917
+ return;
2918
+ }
2919
+
2920
+ EventBuilder(EventBuilder&& other)
2921
+ : m_metaBuilder(other.m_metaBuilder)
2922
+ , m_dataBuilder(other.m_dataBuilder)
2923
+ , m_eventState(other.m_eventState)
2924
+ {
2925
+ return;
2926
+ }
2927
+
2928
+ /*
2929
+ Returns a const reference to the event metadata's underlying buffer.
2930
+ */
2931
+ ByteBufferTy const& MetaBuffer() const
2932
+ {
2933
+ return m_metaBuilder.GetBuffer();
2934
+ }
2935
+
2936
+ /*
2937
+ Returns a const reference to the event payload data's underlying buffer.
2938
+ */
2939
+ ByteBufferTy const& DataBuffer() const
2940
+ {
2941
+ return m_dataBuilder.Buffer();
2942
+ }
2943
+
2944
+ /*
2945
+ Adds a nested struct to the event's metadata.
2946
+ Use the returned EventBuilder to add data and metadata for the fields
2947
+ of the nested struct.
2948
+ Note: do not call any Add methods on this builder object until you are
2949
+ done calling Add methods on the nested builder object.
2950
+ Note: Do not create structs with 0 fields.
2951
+ */
2952
+ template<class CharTy>
2953
+ EventBuilder AddStruct(
2954
+ _In_z_ CharTy const* szUtfStructName,
2955
+ UINT32 fieldTags = 0)
2956
+ {
2957
+ _tld_ASSERT(m_eventState == EventStateOpen, "Metadata already prepared.");
2958
+ return EventBuilder(*this, m_metaBuilder.AddStruct(szUtfStructName, fieldTags));
2959
+ }
2960
+
2961
+ /*
2962
+ Adds a nested array of struct to the event's metadata.
2963
+ Use the returned EventBuilder to add data and metadata for the fields
2964
+ of the nested struct.
2965
+ Note: do not call any Add methods on this builder object until you are
2966
+ done calling Add methods on the nested builder object.
2967
+ Note: Do not create structs with 0 fields.
2968
+ */
2969
+ template<class CharTy>
2970
+ EventBuilder AddStructArray(
2971
+ _In_z_ CharTy const* szUtfStructName,
2972
+ UINT32 fieldTags = 0)
2973
+ {
2974
+ _tld_ASSERT(m_eventState == EventStateOpen, "Metadata already prepared.");
2975
+ return EventBuilder(*this, m_metaBuilder.AddStructArray(szUtfStructName, fieldTags));
2976
+ }
2977
+
2978
+ /*
2979
+ Adds a nested array of struct to the event's metadata.
2980
+ Use the returned EventBuilder to add data and metadata for the fields
2981
+ of the nested struct.
2982
+ Note: do not call any Add methods on this builder object until you are
2983
+ done calling Add methods on the nested builder object.
2984
+ Note: Do not use 0 for itemCount.
2985
+ Note: Do not create structs with 0 fields.
2986
+ */
2987
+ template<class CharTy>
2988
+ EventBuilder AddStructFixedArray(
2989
+ _In_z_ CharTy const* szUtfStructName,
2990
+ UINT16 itemCount,
2991
+ UINT32 fieldTags = 0)
2992
+ {
2993
+ _tld_ASSERT(m_eventState == EventStateOpen, "Metadata already prepared.");
2994
+ return EventBuilder(*this, m_metaBuilder.AddStructFixedArray(szUtfStructName, itemCount, fieldTags));
2995
+ }
2996
+
2997
+ /*
2998
+ Adds a scalar field to the event's metadata.
2999
+ */
3000
+ template<class CharTy>
3001
+ void AddField(
3002
+ _In_z_ CharTy const* szUtfFieldName,
3003
+ Type type,
3004
+ UINT32 fieldTags = 0)
3005
+ {
3006
+ _tld_ASSERT(m_eventState == EventStateOpen, "Metadata already prepared.");
3007
+ m_metaBuilder.AddField(szUtfFieldName, type, fieldTags);
3008
+ }
3009
+
3010
+ /*
3011
+ Adds a variable-length array field to the event's metadata.
3012
+ The length (item count) must be added to the event's payload
3013
+ immediately before the array item values.
3014
+ */
3015
+ template<class CharTy>
3016
+ void AddFieldArray(
3017
+ _In_z_ CharTy const* szUtfFieldName,
3018
+ Type type,
3019
+ UINT32 fieldTags = 0)
3020
+ {
3021
+ _tld_ASSERT(m_eventState == EventStateOpen, "Metadata already prepared.");
3022
+ m_metaBuilder.AddFieldArray(szUtfFieldName, type, fieldTags);
3023
+ }
3024
+
3025
+ /*
3026
+ Adds a fixed-length array field to the event's metadata.
3027
+ The length (item count) is encoded in the metadata, so it does not
3028
+ need to be included in the event's payload.
3029
+ Note: Do not use 0 for itemCount.
3030
+ */
3031
+ template<class CharTy>
3032
+ void AddFieldFixedArray(
3033
+ _In_z_ CharTy const* szUtfFieldName,
3034
+ UINT16 itemCount,
3035
+ Type type,
3036
+ UINT32 fieldTags = 0)
3037
+ {
3038
+ _tld_ASSERT(m_eventState == EventStateOpen, "Metadata already prepared.");
3039
+ m_metaBuilder.AddFieldFixedArray(szUtfFieldName, itemCount, type, fieldTags);
3040
+ }
3041
+
3042
+ /*
3043
+ Adds a custom-encoded field to the event's metadata.
3044
+ Custom-encoded means that you are using some other serialization
3045
+ system (e.g. Bond, Protocol Buffers) to produce the schema and data.
3046
+ The payload is encoded as a UINT16 byte count followed by the data.
3047
+ */
3048
+ template<class CharTy>
3049
+ void AddFieldCustom(
3050
+ _In_z_ CharTy const* szUtfFieldName,
3051
+ _In_reads_bytes_(cbSchema) void const* pSchema,
3052
+ UINT16 cbSchema,
3053
+ Type type,
3054
+ UINT32 fieldTags = 0)
3055
+ {
3056
+ _tld_ASSERT(m_eventState == EventStateOpen, "Metadata already prepared.");
3057
+ m_metaBuilder.AddFieldCustom(szUtfFieldName, pSchema, cbSchema, type, fieldTags);
3058
+ }
3059
+
3060
+ /*
3061
+ Advanced use: adds raw metadata bytes.
3062
+ */
3063
+ void AddRawMetadata(
3064
+ _In_reads_bytes_(cbMetadata) void const* pMetadata,
3065
+ UINT32 cbMetadata)
3066
+ {
3067
+ auto& buf = m_metaBuilder.GetBuffer();
3068
+ auto pb = static_cast<BYTE const*>(pMetadata);
3069
+ buf.insert(buf.end(), pb + 0u, pb + cbMetadata);
3070
+ }
3071
+
3072
+ /*
3073
+ Adds an array length (item count) to the payload. This is for
3074
+ variable-length arrays only (not fixed-length), and must occur
3075
+ immediately before the array item values are written to the payload.
3076
+ */
3077
+ void AddArrayCount(UINT16 cItems)
3078
+ {
3079
+ m_dataBuilder.AddArrayCount(cItems);
3080
+ }
3081
+
3082
+ /*
3083
+ Adds a value to the payload.
3084
+ Note: should only be used for blittable POD types with no padding,
3085
+ e.g. INT32, FILETIME, GUID, not for strings or structs.
3086
+ */
3087
+ template<class T>
3088
+ void AddValue(T const& value)
3089
+ {
3090
+ m_dataBuilder.AddValue(value);
3091
+ }
3092
+
3093
+ /*
3094
+ Adds an array of values to the payload.
3095
+ Note: should only be used for blittable POD types with no padding,
3096
+ e.g. INT32, FILETIME, GUID, not for strings or structs.
3097
+ */
3098
+ template<class T>
3099
+ void AddValues(_In_reads_(cValues) T const* pValues, unsigned cValues)
3100
+ {
3101
+ m_dataBuilder.AddValues(pValues, cValues);
3102
+ }
3103
+
3104
+ /*
3105
+ Appends an InTypeBinary or InTypeCountedBinary field to the payload.
3106
+ Compatible with: Type[Counted]Binary, Type[Counted]IPv6, Type[Counted]SocketAddress.
3107
+ */
3108
+ void AddBinary(_In_reads_bytes_(cbData) void const* pbData, UINT16 cbData)
3109
+ {
3110
+ m_dataBuilder.AddBinary(pbData, cbData);
3111
+ }
3112
+
3113
+ /*
3114
+ Appends an InTypeCountedAnsiString field to the payload.
3115
+ Compatible with: TypeCountedMbcsString, TypeCountedMbcsXml, TypeCountedMbcsJson.
3116
+ */
3117
+ void AddCountedString(_In_reads_(cch) char const* pch, UINT16 cch)
3118
+ {
3119
+ m_dataBuilder.AddCountedString(pch, cch);
3120
+ }
3121
+
3122
+ /*
3123
+ Appends an InTypeCountedString field to the payload.
3124
+ Compatible with: TypeCountedUtf16String, TypeCountedUtf16Xml, TypeCountedUtf16Json.
3125
+ */
3126
+ void AddCountedString(_In_reads_(cch) wchar_t const* pch, UINT16 cch)
3127
+ {
3128
+ m_dataBuilder.AddCountedString(pch, cch);
3129
+ }
3130
+
3131
+ /*
3132
+ Appends an InTypeAnsiString field to the payload.
3133
+ Compatible with: TypeMbcsString, TypeMbcsXml, TypeMbcsJson.
3134
+ */
3135
+ void AddString(_In_z_ char const* psz)
3136
+ {
3137
+ m_dataBuilder.AddString(psz);
3138
+ }
3139
+
3140
+ /*
3141
+ Appends a InTypeUnicodeString field to the payload.
3142
+ Compatible with: TypeUtf16String, TypeUtf16Xml, TypeUtf16Json
3143
+ */
3144
+ void AddString(_In_z_ wchar_t const* psz)
3145
+ {
3146
+ m_dataBuilder.AddString(psz);
3147
+ }
3148
+
3149
+ /*
3150
+ Appends a raw byte to the payload.
3151
+ */
3152
+ void AddByte(UINT8 val)
3153
+ {
3154
+ m_dataBuilder.AddByte(val);
3155
+ }
3156
+
3157
+ /*
3158
+ Appends raw bytes to the payload.
3159
+ */
3160
+ void AddBytes(_In_reads_bytes_(cbData) void const* pbData, unsigned cbData)
3161
+ {
3162
+ m_dataBuilder.AddBytes(pbData, cbData);
3163
+ }
3164
+ };
3165
+
3166
+ #pragma endregion
3167
+
3168
+ #pragma region Event
3169
+
3170
+ template<class ByteBufferTy>
3171
+ class Event
3172
+ : public EventBuilder<ByteBufferTy>
3173
+ {
3174
+ Event(Event const&); // = delete
3175
+ void operator=(Event const&); // = delete
3176
+
3177
+ ByteBufferTy m_metaBuffer;
3178
+ ByteBufferTy m_dataBuffer;
3179
+ EventDescriptor m_descriptor;
3180
+ GUID const* m_pActivityId;
3181
+ GUID const* m_pRelatedActivityId;
3182
+ EventState m_state;
3183
+
3184
+ public:
3185
+
3186
+ Event(
3187
+ _In_z_ char const* szUtf8Name,
3188
+ UCHAR level = 5,
3189
+ ULONGLONG keyword = 0,
3190
+ UINT32 tags = 0,
3191
+ UCHAR opcode = 0,
3192
+ USHORT task = 0,
3193
+ GUID const* pActivityId = 0,
3194
+ GUID const* pRelatedActivityId = 0)
3195
+ : EventBuilder<ByteBufferTy>(m_metaBuffer, m_dataBuffer, m_state)
3196
+ , m_descriptor(level, keyword, opcode, task)
3197
+ , m_pActivityId(pActivityId)
3198
+ , m_pRelatedActivityId(pRelatedActivityId)
3199
+ , m_state(EventStateOpen)
3200
+ {
3201
+ EventMetadataBuilder<ByteBufferTy>(m_metaBuffer).Begin(szUtf8Name, tags);
3202
+ }
3203
+
3204
+ Event(
3205
+ _In_z_ wchar_t const* szUtf16Name,
3206
+ UCHAR level = 5,
3207
+ ULONGLONG keyword = 0,
3208
+ UINT32 tags = 0,
3209
+ UCHAR opcode = 0,
3210
+ USHORT task = 0,
3211
+ GUID const* pActivityId = 0,
3212
+ GUID const* pRelatedActivityId = 0)
3213
+ : EventBuilder<ByteBufferTy>(m_metaBuffer, m_dataBuffer, m_state)
3214
+ , m_descriptor(level, keyword, opcode, task)
3215
+ , m_pActivityId(pActivityId)
3216
+ , m_pRelatedActivityId(pRelatedActivityId)
3217
+ , m_state(EventStateOpen)
3218
+ {
3219
+ EventMetadataBuilder<ByteBufferTy>(m_metaBuffer).Begin(szUtf16Name, tags);
3220
+ }
3221
+
3222
+ /*
3223
+ Clears the metadata and the payload.
3224
+ */
3225
+ template<class CharTy>
3226
+ void Reset(
3227
+ _In_z_ CharTy const* szUtfName,
3228
+ UCHAR level = 5,
3229
+ ULONGLONG keyword = 0,
3230
+ UINT32 tags = 0,
3231
+ UCHAR opcode = 0,
3232
+ USHORT task = 0,
3233
+ GUID* pActivityId = 0,
3234
+ GUID* pRelatedActivityId = 0)
3235
+ {
3236
+ m_metaBuffer.clear();
3237
+ m_dataBuffer.clear();
3238
+ m_descriptor.Reset(level, keyword, opcode, task);
3239
+ m_pActivityId = pActivityId;
3240
+ m_pRelatedActivityId = pRelatedActivityId;
3241
+ m_state = EventStateOpen;
3242
+ EventMetadataBuilder<ByteBufferTy>(m_metaBuffer).Begin(szUtfName, tags);
3243
+ }
3244
+
3245
+ /*
3246
+ Clears the payload without clearing the metadata.
3247
+ */
3248
+ void ResetData()
3249
+ {
3250
+ m_dataBuffer.clear();
3251
+ }
3252
+
3253
+ /*
3254
+ Sends the event to ETW using EventWriteTransfer.
3255
+ */
3256
+ HRESULT Write(Provider const& provider)
3257
+ {
3258
+ HRESULT hr = E_INVALIDARG;
3259
+ if (PrepareEvent())
3260
+ {
3261
+ hr = provider.Write(
3262
+ m_descriptor,
3263
+ &m_metaBuffer.front(),
3264
+ m_dataBuffer.empty() ? NULL : &m_dataBuffer.front(),
3265
+ static_cast<UINT32>(m_dataBuffer.size()),
3266
+ m_pActivityId,
3267
+ m_pRelatedActivityId);
3268
+ }
3269
+ return hr;
3270
+ }
3271
+
3272
+ /*
3273
+ Sends the event to ETW using EventWriteTransfer.
3274
+ */
3275
+ HRESULT Write(
3276
+ REGHANDLE hProvider,
3277
+ _In_count_x_((UINT16*)pProviderMetadata) UINT8 const* pProviderMetadata)
3278
+ {
3279
+ HRESULT hr = E_INVALIDARG;
3280
+
3281
+ if (PrepareEvent())
3282
+ {
3283
+ EVENT_DATA_DESCRIPTOR dataDesc[3];
3284
+ ULONG cDataDesc = 2;
3285
+ if (!m_dataBuffer.empty())
3286
+ {
3287
+ EventDataDescCreate(
3288
+ &dataDesc[cDataDesc++],
3289
+ &m_dataBuffer.front(),
3290
+ static_cast<ULONG>(m_dataBuffer.size()));
3291
+ }
3292
+
3293
+ hr = ::tld::WriteEvent(
3294
+ hProvider,
3295
+ m_descriptor,
3296
+ pProviderMetadata,
3297
+ &m_metaBuffer.front(),
3298
+ cDataDesc,
3299
+ dataDesc,
3300
+ m_pActivityId,
3301
+ m_pRelatedActivityId);
3302
+ }
3303
+
3304
+ return hr;
3305
+ }
3306
+
3307
+ #if TLD_HAVE_EVENT_WRITE_EX == 1
3308
+
3309
+ /*
3310
+ Sends the event to ETW using EventWriteEx.
3311
+ */
3312
+ HRESULT WriteEx(
3313
+ Provider const& provider,
3314
+ ULONG64 filter,
3315
+ ULONG flags)
3316
+ {
3317
+ HRESULT hr = E_INVALIDARG;
3318
+ if (PrepareEvent())
3319
+ {
3320
+ hr = provider.WriteEx(
3321
+ m_descriptor,
3322
+ &m_metaBuffer.front(),
3323
+ m_dataBuffer.empty() ? NULL : &m_dataBuffer.front(),
3324
+ static_cast<UINT32>(m_dataBuffer.size()),
3325
+ filter,
3326
+ flags,
3327
+ m_pActivityId,
3328
+ m_pRelatedActivityId);
3329
+ }
3330
+ return hr;
3331
+ }
3332
+
3333
+ /*
3334
+ Sends the event to ETW using EventWriteEx.
3335
+ */
3336
+ HRESULT WriteEx(
3337
+ REGHANDLE hProvider,
3338
+ _In_count_x_((UINT16*)pEventMetadata) UINT8 const* pProviderMetadata,
3339
+ ULONG64 filter,
3340
+ ULONG flags)
3341
+ {
3342
+ HRESULT hr = E_INVALIDARG;
3343
+
3344
+ if (PrepareEvent())
3345
+ {
3346
+ EVENT_DATA_DESCRIPTOR dataDesc[3];
3347
+ ULONG cDataDesc = 2;
3348
+ if (!m_dataBuffer.empty())
3349
+ {
3350
+ EventDataDescCreate(
3351
+ &dataDesc[cDataDesc++],
3352
+ &m_dataBuffer.front(),
3353
+ static_cast<ULONG>(m_dataBuffer.size()));
3354
+ }
3355
+
3356
+ hr = ::tld::WriteEventEx(
3357
+ hProvider,
3358
+ m_descriptor,
3359
+ pProviderMetadata,
3360
+ &m_metaBuffer.front(),
3361
+ cDataDesc,
3362
+ dataDesc,
3363
+ filter,
3364
+ flags,
3365
+ m_pActivityId,
3366
+ m_pRelatedActivityId);
3367
+ }
3368
+
3369
+ return hr;
3370
+ }
3371
+
3372
+ #endif // TLD_HAVE_EVENT_WRITE_EX
3373
+
3374
+ #pragma region Basic properties
3375
+
3376
+ UCHAR Channel() const
3377
+ {
3378
+ return m_descriptor.Channel;
3379
+ }
3380
+
3381
+ /*
3382
+ Note: the default channel is 11 (WINEVENT_CHANNEL_TRACELOGGING).
3383
+ Other channels are only supported if the provider is running on
3384
+ Windows 10 or later. If a provider is running on an earlier version
3385
+ of Windows and it uses a channel other than 11, TDH will not be able
3386
+ to decode the events.
3387
+ */
3388
+ void Channel(UCHAR channel)
3389
+ {
3390
+ m_descriptor.Channel = channel;
3391
+ }
3392
+
3393
+ UCHAR Level() const
3394
+ {
3395
+ return m_descriptor.Level;
3396
+ }
3397
+
3398
+ void Level(UCHAR value)
3399
+ {
3400
+ m_descriptor.Level = value;
3401
+ }
3402
+
3403
+ ULONGLONG Keywords() const
3404
+ {
3405
+ return m_descriptor.Keyword;
3406
+ }
3407
+
3408
+ void Keywords(ULONGLONG value)
3409
+ {
3410
+ m_descriptor.Keyword = value;
3411
+ }
3412
+
3413
+ UCHAR Opcode() const
3414
+ {
3415
+ return m_descriptor.Opcode;
3416
+ }
3417
+
3418
+ void Opcode(UCHAR value)
3419
+ {
3420
+ m_descriptor.Opcode = value;
3421
+ }
3422
+
3423
+ USHORT Task() const
3424
+ {
3425
+ return m_descriptor.Task;
3426
+ }
3427
+
3428
+ void Task(USHORT value)
3429
+ {
3430
+ m_descriptor.Task = value;
3431
+ }
3432
+
3433
+ const GUID* ActivityId() const
3434
+ {
3435
+ return m_pActivityId;
3436
+ }
3437
+
3438
+ void ActivityId(GUID* pValue)
3439
+ {
3440
+ m_pActivityId = pValue;
3441
+ }
3442
+
3443
+ const GUID* RelatedActivityId() const
3444
+ {
3445
+ return m_pRelatedActivityId;
3446
+ }
3447
+
3448
+ void RelatedActivityId(GUID* pValue)
3449
+ {
3450
+ m_pRelatedActivityId = pValue;
3451
+ }
3452
+
3453
+ bool IsEnabledFor(Provider const& provider) const
3454
+ {
3455
+ return provider.IsEnabled(m_descriptor.Level, m_descriptor.Keyword);
3456
+ }
3457
+
3458
+ #pragma endregion
3459
+
3460
+ private:
3461
+
3462
+ bool PrepareEvent()
3463
+ {
3464
+ if (m_state == EventStateOpen)
3465
+ {
3466
+ PrepareEventImpl();
3467
+ }
3468
+ return m_state == EventStateClosed;
3469
+ }
3470
+
3471
+ void PrepareEventImpl()
3472
+ {
3473
+ m_state =
3474
+ EventMetadataBuilder<ByteBufferTy>(m_metaBuffer).End()
3475
+ ? EventStateClosed
3476
+ : EventStateError;
3477
+ }
3478
+ };
3479
+
3480
+ #pragma endregion
3481
+ }
3482
+ // namespace tld