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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +31 -0
- data/LICENSE.txt +28 -0
- data/README.md +243 -0
- data/ext/winlog/TraceLoggingDynamic.h +3482 -0
- data/ext/winlog/extconf.rb +30 -0
- data/ext/winlog/winlog.cpp +788 -0
- data/lib/winlog/version.rb +5 -0
- data/lib/winlog.rb +216 -0
- metadata +125 -0
|
@@ -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
|