ReactOS 0.4.15-dev-5667-ged97270
verifier.cpp File Reference
#include "vfpriv.hpp"
Include dependency graph for verifier.cpp:

Go to the source code of this file.

Functions

_Must_inspect_result_ NTSTATUS AddEventHooksWdfDeviceCreate (__inout PVF_HOOK_PROCESS_INFO HookProcessInfo, __in PWDF_DRIVER_GLOBALS DriverGlobals, __in PWDFDEVICE_INIT *DeviceInit, __in PWDF_OBJECT_ATTRIBUTES DeviceAttributes, __out WDFDEVICE *Device)
 
_Must_inspect_result_ NTSTATUS AddEventHooksWdfIoQueueCreate (__inout PVF_HOOK_PROCESS_INFO HookProcessInfo, __in PWDF_DRIVER_GLOBALS DriverGlobals, __in WDFDEVICE Device, __in PWDF_IO_QUEUE_CONFIG Config, __in PWDF_OBJECT_ATTRIBUTES QueueAttributes, __out WDFQUEUE *Queue)
 
_Must_inspect_result_ PVOID FASTCALL VfWdfObjectGetTypedContext (__in WDFOBJECT Handle, __in PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo)
 
_Must_inspect_result_ NTSTATUS VfAllocateContext (__in PWDF_DRIVER_GLOBALS DriverGlobals, __in PWDF_OBJECT_ATTRIBUTES Attributes, __out PVOID *ContextHeader)
 
_Must_inspect_result_ NTSTATUS VfAddContextToHandle (__in PVOID ContextHeader, __in PWDF_OBJECT_ATTRIBUTES Attributes, __in WDFOBJECT Handle, __out_opt PVOID *Context)
 

Variables

WDFVERSION WdfVersion
 

Function Documentation

◆ AddEventHooksWdfDeviceCreate()

_Must_inspect_result_ NTSTATUS AddEventHooksWdfDeviceCreate ( __inout PVF_HOOK_PROCESS_INFO  HookProcessInfo,
__in PWDF_DRIVER_GLOBALS  DriverGlobals,
__in PWDFDEVICE_INIT DeviceInit,
__in PWDF_OBJECT_ATTRIBUTES  DeviceAttributes,
__out WDFDEVICE *  Device 
)

Definition at line 52 of file verifier.cpp.

71{
73 PWDFDEVICE_INIT deviceInit = *DeviceInit;
74 WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerEvtsOriginal;
75 WDF_PNPPOWER_EVENT_CALLBACKS *pnpPowerEvts;
77 PVOID contextHeader = NULL;
78 WDF_OBJECT_ATTRIBUTES attributes;
79
81
83
87
88 //
89 // Check if there are any callbacks set by the client driver. If not, we
90 // don't need any callback hooking.
91 //
92 if (deviceInit->PnpPower.PnpPowerEventCallbacks.Size !=
94 //
95 // no hooking required.
96 //
98 HookProcessInfo->DonotCallKmdfLib = FALSE;
99 return status;
100 }
101
102 //
103 // Hooking can be done only if we are able to allocate context memory.
104 // Try to allocate a context
105 //
107 &attributes,
109 );
110
111 status = VfAllocateContext(DriverGlobals, &attributes, &contextHeader);
112
113 if (!NT_SUCCESS(status)) {
114 //
115 // couldn't allocate context. hooking not possible
116 //
117 HookProcessInfo->DonotCallKmdfLib = FALSE;
118 return status;
119 }
120
121 //
122 // store original driver callbacks to local variable
123 //
124 RtlCopyMemory(&pnpPowerEvtsOriginal,
125 &deviceInit->PnpPower.PnpPowerEventCallbacks,
127 );
128
129 //
130 // Set callback hooks
131 //
132 // Normally override the hooks on local copy of stucture (not the original
133 // structure itself) and then pass the local struture to DDI call and
134 // copy back the original poniter when returning back to caller. In this case
135 // device_init is null'ed out by fx when returning to caller so we can
136 // directly override the original
137 //
138 pnpPowerEvts = &deviceInit->PnpPower.PnpPowerEventCallbacks;
139
140 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceD0Entry);
141 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceD0EntryPostInterruptsEnabled);
142 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceD0Exit);
143 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceD0ExitPreInterruptsDisabled);
144 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDevicePrepareHardware);
145 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceReleaseHardware);
146 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceSelfManagedIoCleanup);
147 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceSelfManagedIoFlush);
148 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceSelfManagedIoInit);
149 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceSelfManagedIoSuspend);
150 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceSelfManagedIoRestart);
151 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceSurpriseRemoval);
152 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceQueryRemove);
153 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceQueryStop);
154 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceUsageNotification);
155 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceUsageNotificationEx);
156 SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceRelationsQuery);
157
158 //
159 // Call the DDI on behalf of driver.
160 //
161 status = ((PFN_WDFDEVICECREATE)WdfVersion.Functions.pfnWdfDeviceCreate)(
165 Device
166 );
167 //
168 // Tell main hook routine not to call the DDI in kmdf lib since we
169 // already called it
170 //
171 HookProcessInfo->DonotCallKmdfLib = TRUE;
172 HookProcessInfo->DdiCallStatus = status;
173
174 //
175 // if DDI Succeeds, add context
176 //
177 if (NT_SUCCESS(status)) {
179
180 //
181 // add the already allocated context to the object.
182 //
183 status = VfAddContextToHandle(contextHeader,
184 &attributes,
185 *Device,
186 (PVOID *)&context);
187
188 if (NT_SUCCESS(status)) {
189 //
190 // store the DriverGlobals pointer used to associate the driver
191 // with its client driver callback later in the callback hooks
192 //
193 context->CommonHeader.DriverGlobals = DriverGlobals;
194
195 //
196 // store original client driver callbacks in context
197 //
199 &context->PnpPowerEventCallbacksOriginal,
200 &pnpPowerEvtsOriginal,
202 );
203 }
204 else {
205 //
206 // For some reason adding context to handle failed. This should be
207 // rare failure, because context allocation was already successful,
208 // only adding to handle failed.
209 //
210 // Hooking failed if adding context is unsuccessful. This means
211 // kmdf has callbacks hooks but verifier cannot assiociate client
212 // driver callbacks with callback hooks. This would be a fatal error.
213 //
214 ASSERTMSG("KMDF Enhanced Verifier failed to add context to object "
215 "handle\n", FALSE);
216
217 if (contextHeader != NULL) {
218 FxPoolFree(contextHeader);
219 }
220 }
221 }
222 else {
223 //
224 // KMDF DDI call failed. In case of failure, DeviceInit is not NULL'ed
225 // so the driver could potentially call WdfDeviceCreate again with this
226 // DeviceInit that contains callback hooks, and result in infinite
227 // callback loop. So put original callbacks back
228 //
229 if ((*DeviceInit) != NULL) {
230 //
231 // we overwrote only the pnppower callbacks. Put the original back.
232 //
233 deviceInit = *DeviceInit;
235 &pnpPowerEvtsOriginal,
237 );
238 }
239
240 if (contextHeader != NULL) {
241 FxPoolFree(contextHeader);
242 }
243 }
244
245 return status;
246}
LONG NTSTATUS
Definition: precomp.h:26
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
PFX_DRIVER_GLOBALS pFxDriverGlobals
DriverGlobals
__inline PFX_DRIVER_GLOBALS GetFxDriverGlobals(__in PWDF_DRIVER_GLOBALS DriverGlobals)
Definition: fxglobals.h:597
#define FxPointerNotNull(FxDriverGlobals, Ptr)
Definition: fxmacros.hpp:253
void FxPoolFree(__in_xcount(ptr is at an offset from AllocationStart) PVOID ptr)
Definition: wdfpool.cpp:361
#define ASSERTMSG(msg, exp)
Definition: nt_native.h:431
#define STATUS_SUCCESS
Definition: shellext.h:65
WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerEventCallbacks
PnpPowerInit PnpPower
PFN_WDFDEVICECREATE pfnWdfDeviceCreate
Definition: fxdynamics.h:108
WDFFUNCTIONS Functions
Definition: fxdynamics.h:594
Definition: http.c:7252
Definition: ps.c:97
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
WDFVERSION WdfVersion
_Must_inspect_result_ NTSTATUS VfAllocateContext(__in PWDF_DRIVER_GLOBALS DriverGlobals, __in PWDF_OBJECT_ATTRIBUTES Attributes, __out PVOID *ContextHeader)
Definition: verifier.cpp:502
_Must_inspect_result_ NTSTATUS VfAddContextToHandle(__in PVOID ContextHeader, __in PWDF_OBJECT_ATTRIBUTES Attributes, __in WDFOBJECT Handle, __out_opt PVOID *Context)
Definition: verifier.cpp:576
#define SET_HOOK_IF_CALLBACK_PRESENT(Source, Target, Name)
Definition: vfpriv.hpp:42
_Must_inspect_result_ _In_ WDFDEVICE Device
Definition: wdfchildlist.h:474
_In_ PWDFDEVICE_INIT DeviceInit
Definition: wdfcontrol.h:113
_Must_inspect_result_ _Inout_ PWDFDEVICE_INIT _In_opt_ PWDF_OBJECT_ATTRIBUTES DeviceAttributes
Definition: wdfdevice.h:3563
#define WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(_attributes, _contexttype)
Definition: wdfobject.h:170
#define PAGED_CODE_LOCKED()
Definition: kefuncs.h:1431

◆ AddEventHooksWdfIoQueueCreate()

_Must_inspect_result_ NTSTATUS AddEventHooksWdfIoQueueCreate ( __inout PVF_HOOK_PROCESS_INFO  HookProcessInfo,
__in PWDF_DRIVER_GLOBALS  DriverGlobals,
__in WDFDEVICE  Device,
__in PWDF_IO_QUEUE_CONFIG  Config,
__in PWDF_OBJECT_ATTRIBUTES  QueueAttributes,
__out WDFQUEUE *  Queue 
)

Definition at line 250 of file verifier.cpp.

267{
269 WDF_IO_QUEUE_CONFIG configNew;
271 WDFQUEUE *pQueue;
272 WDFQUEUE queue;
273 PVOID contextHeader = NULL;
274 WDF_OBJECT_ATTRIBUTES attributes;
275
277
279
281
282 //
283 // Check if there are any callbacks set by the client driver. If not, we
284 // don't need any callback hooking.
285 //
286 if (Config->Size != sizeof(WDF_IO_QUEUE_CONFIG)) {
287 //
288 // no hooking required.
289 //
291 HookProcessInfo->DonotCallKmdfLib = FALSE;
292 return status;
293 }
294
295 //
296 // Hooking can be done only if we are able to allocate context memory.
297 // Try to allocate a context
298 //
301
302 status = VfAllocateContext(DriverGlobals, &attributes, &contextHeader);
303
304 if (!NT_SUCCESS(status)) {
305 //
306 // couldn't allocate context. hooking not possible
307 //
308 HookProcessInfo->DonotCallKmdfLib = FALSE;
309 return status;
310 }
311
312 //
313 // create a local copy of config
314 //
315 RtlCopyMemory(&configNew,
316 Config,
317 sizeof(configNew)
318 );
319
320 //
321 // Override local copy with event callback hooks.
322 //
323 SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoDefault);
324 SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoRead);
325 SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoWrite);
326 SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoDeviceControl);
327 SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoInternalDeviceControl);
328 SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoStop);
329 SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoResume);
330 SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoCanceledOnQueue);
331
332 //
333 // Queue handle is an optional parameter
334 //
335 if (Queue == NULL) {
336 pQueue = &queue;
337 }
338 else {
339 pQueue = Queue;
340 }
341
342 //
343 // call the DDI
344 //
347 Device,
348 &configNew,
350 pQueue
351 );
352
353 //
354 // Tell main hook routine not to call the DDI in kmdf lib since we
355 // already called it
356 //
357 HookProcessInfo->DonotCallKmdfLib = TRUE;
358 HookProcessInfo->DdiCallStatus = status;
359
360 //
361 // if DDI Succeeds, add context
362 //
363 if (NT_SUCCESS(status)) {
365
366 //
367 // add the already allocated context to the object.
368 //
369 status = VfAddContextToHandle(contextHeader,
370 &attributes,
371 *pQueue,
372 (PVOID *)&context);
373
374 if (NT_SUCCESS(status)) {
375 //
376 // store the DriverGlobals pointer used to associate the driver
377 // with its client driver callback later in the callback hooks
378 //
379 context->CommonHeader.DriverGlobals = DriverGlobals;
380
381 //
382 // add stored original callbacks to context
383 //
385 &context->IoQueueConfigOriginal,
386 Config,
387 sizeof(WDF_IO_QUEUE_CONFIG)
388 );
389 }
390 else {
391 //
392 // For some reason adding context to handle failed. This should be
393 // rare failure, because context allocation was already successful,
394 // only adding to handle failed.
395 //
396 // Hooking failed if adding context is unsuccessful. This means
397 // kmdf has callbacks hooks but verifier cannot assiociate client
398 // driver callbacks with callback hooks. This would be a fatal error.
399 //
400 ASSERTMSG("KMDF Enhanced Verifier failed to add context to object "
401 "handle\n", FALSE);
402
403 if (contextHeader != NULL) {
404 FxPoolFree(contextHeader);
405 }
406 }
407 }
408 else {
409 //
410 // DDI call to KMDF failed. Nothing to do by verifier. Just return
411 // kmdf's status after freeing context header memory.
412 //
413 if (contextHeader != NULL) {
414 FxPoolFree(contextHeader);
415 }
416 }
417
418 return status;
419}
Definition: _queue.h:67
FxIoQueue * pQueue
PFN_WDFIOQUEUECREATE pfnWdfIoQueueCreate
Definition: fxdynamics.h:203
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_CHILD_LIST_CONFIG Config
Definition: wdfchildlist.h:476
_Must_inspect_result_ _In_ WDFDEVICE _In_ PIRP _In_ WDFQUEUE Queue
Definition: wdfdevice.h:2225
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_IO_QUEUE_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES QueueAttributes
Definition: wdfio.h:617

◆ VfAddContextToHandle()

_Must_inspect_result_ NTSTATUS VfAddContextToHandle ( __in PVOID  ContextHeader,
__in PWDF_OBJECT_ATTRIBUTES  Attributes,
__in WDFOBJECT  Handle,
__out_opt PVOID Context 
)

Definition at line 576 of file verifier.cpp.

582{
588
590
591 pHeader = (FxContextHeader *)ContextHeader;
592
593 if (pHeader == NULL) {
595 }
596
597 //
598 // No need to call FxObjectHandleGetPtr( , , FX_TYPE_OBJECT) because
599 // we assume that the object handle will point back to an FxObject. (The
600 // call to FxObjectHandleGetPtr will just make needless virtual call into
601 // FxObject anyways).
602 //
603 offset = 0;
605
607
608 if (offset != 0) {
609 //
610 // for lack of a better error code
611 //
613
616 "WDFHANDLE %p cannot have contexts added to it, %!STATUS!",
617 Handle, status);
618
619 goto cleanup;
620 }
621
622 pObject->ADDREF(&status);
623
625
627
628 //
629 // STATUS_OBJECT_NAME_EXISTS will not fail NT_SUCCESS, so check
630 // explicitly for STATUS_SUCCESS.
631 //
632 if (status != STATUS_SUCCESS) {
635 "WDFHANDLE %p failed to add context, %!STATUS!",
636 Handle, status);
637 }
638
639 pObject->RELEASE(&status);
640
641cleanup:
642
643 if (status != STATUS_SUCCESS && pHeader != NULL) {
645 }
646
647 return status;
648}
static FxObject * _GetObjectFromHandle(__in WDFOBJECT Handle, __inout PWDFOBJECT_OFFSET ObjectOffset)
Definition: fxobject.hpp:613
_Must_inspect_result_ NTSTATUS AddContext(__in FxContextHeader *Header, __in PVOID *Context, __in PWDF_OBJECT_ATTRIBUTES Attributes)
Definition: fxobject.cpp:605
__inline PFX_DRIVER_GLOBALS GetDriverGlobals(VOID)
Definition: fxobject.hpp:734
#define TRACINGHANDLE
Definition: dbgtrace.h:61
static void cleanup(void)
Definition: main.c:1335
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, "Enter, WDFDEVICE %p", Device)
VOID FxContextHeaderInit(__in FxContextHeader *Header, __in FxObject *Object, __in_opt PWDF_OBJECT_ATTRIBUTES Attributes)
Definition: handleapi.cpp:248
USHORT WDFOBJECT_OFFSET
Definition: fxobject.hpp:80
FxObject * pObject
ULONG Handle
Definition: gdb_input.c:15
GLintptr offset
Definition: glext.h:5920
FxContextHeader * pHeader
Definition: handleapi.cpp:604
#define STATUS_OBJECT_PATH_INVALID
Definition: ntstatus.h:293
#define TRACE_LEVEL_WARNING
Definition: storswtr.h:28
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes

Referenced by AddEventHooksWdfDeviceCreate(), and AddEventHooksWdfIoQueueCreate().

◆ VfAllocateContext()

_Must_inspect_result_ NTSTATUS VfAllocateContext ( __in PWDF_DRIVER_GLOBALS  DriverGlobals,
__in PWDF_OBJECT_ATTRIBUTES  Attributes,
__out PVOID ContextHeader 
)

Definition at line 502 of file verifier.cpp.

523{
527 size_t size;
528
530
532
535 if (!NT_SUCCESS(status)) {
536 return status;
537 }
538
539 //
540 // Must have a context type!
541 //
542 if (Attributes->ContextTypeInfo == NULL) {
546 "Attributes %p ContextTypeInfo is NULL, %!STATUS!",
548 return status;
549 }
550
551 //
552 // By passing 0's for raw object size and extra size, we can compute the
553 // size of only the header and its contents.
554 //
556 if (!NT_SUCCESS(status)) {
557 return status;
558 }
559
561 FxPoolAllocate(pFxDriverGlobals, NonPagedPool, size);
562
563 if (pHeader != NULL) {
564 *ContextHeader = pHeader;
566 }
567 else {
569 }
570
571 return status;
572}
#define NonPagedPool
Definition: env_spec_w32.h:307
_Must_inspect_result_ NTSTATUS FxCalculateObjectTotalSize(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in USHORT RawObjectSize, __in USHORT ExtraSize, __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, __out size_t *Total)
Definition: handleapi.cpp:147
@ FX_VALIDATE_OPTION_ATTRIBUTES_REQUIRED
_Must_inspect_result_ NTSTATUS FxValidateObjectAttributes(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PWDF_OBJECT_ATTRIBUTES Attributes, __in ULONG Flags=FX_VALIDATE_OPTION_NONE_SPECIFIED)
GLsizeiptr size
Definition: glext.h:5919
#define STATUS_OBJECT_NAME_INVALID
Definition: udferr_usr.h:148
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158

Referenced by AddEventHooksWdfDeviceCreate(), and AddEventHooksWdfIoQueueCreate().

◆ VfWdfObjectGetTypedContext()

_Must_inspect_result_ PVOID FASTCALL VfWdfObjectGetTypedContext ( __in WDFOBJECT  Handle,
__in PCWDF_OBJECT_CONTEXT_TYPE_INFO  TypeInfo 
)

Definition at line 424 of file verifier.cpp.

446{
451
453
454 //
455 // Do not call FxObjectHandleGetPtr( , , FX_TYPE_OBJECT) because this is a
456 // hot spot / workhorse function that should be as efficient as possible.
457 //
458 // A call to FxObjectHandleGetPtr would :
459 // 1) invoke a virtual call to QueryInterface
460 //
461 // 2) ASSERT that the ref count of the object is > zero. Since this is one
462 // of the few functions that can be called in EvtObjectDestroy where the
463 // ref count is zero, that is not a good side affect.
464 //
465 offset = 0;
467
468 //
469 // Use the object's globals, not the caller's
470 //
472
475
477
478 for ( ; pHeader != NULL; pHeader = pHeader->NextHeader) {
480 return &pHeader->Context[0];
481 }
482 }
483
485
486 if (TypeInfo->ContextName != NULL) {
487 pGivenName = TypeInfo->ContextName;
488 }
489 else {
490 pGivenName = "<no typename given>";
491 }
492
494 "Attempting to get context type %s from WDFOBJECT 0x%p",
496
497 return NULL;
498}
__inline FxContextHeader * GetContextHeader(VOID)
Definition: fxobject.hpp:720
#define TRACINGDEVICE
Definition: dbgtrace.h:58
PCHAR pGivenName
Definition: handleapi.cpp:640
__in WDFOBJECT __in PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo
Definition: handleapi.cpp:601
FxContextHeader * NextHeader
Definition: fxhandle.h:71
PCWDF_OBJECT_CONTEXT_TYPE_INFO ContextTypeInfo
Definition: fxhandle.h:87
char * PCHAR
Definition: typedefs.h:51

Variable Documentation

◆ WdfVersion