ReactOS 0.4.15-dev-7085-g12a5971
hivewrt.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Configuration Manager Library - Registry Syncing & Hive/Log/Alternate Writing
5 * COPYRIGHT: Copyright 2001 - 2005 Eric Kohl
6 * Copyright 2005 Filip Navara <navaraf@reactos.org>
7 * Copyright 2021 Max Korostil
8 * Copyright 2022 George Bișoc <george.bisoc@reactos.org>
9 */
10
11#include "cmlib.h"
12#define NDEBUG
13#include <debug.h>
14
15/* DECLARATIONS *************************************************************/
16
17#if !defined(CMLIB_HOST) && !defined(_BLDR_)
21 _In_ BOOLEAN HardErrorEnabled);
22#endif
23
24/* GLOBALS *****************************************************************/
25
26#if !defined(CMLIB_HOST) && !defined(_BLDR_)
28#endif
29
30/* PRIVATE FUNCTIONS ********************************************************/
31
41static
42VOID
44 _In_ PHHIVE RegistryHive)
45{
46 PHBASE_BLOCK BaseBlock;
47
48 /*
49 * Cache the base block and validate it.
50 * Especially...
51 *
52 * 1. It must must have a valid signature.
53 * 2. It must have a valid format.
54 * 3. It must be of an adequate major version,
55 * not anything else.
56 */
57 BaseBlock = RegistryHive->BaseBlock;
59 ASSERT(BaseBlock->Format == HBASE_FORMAT_MEMORY);
60 ASSERT(BaseBlock->Major == HSYS_MAJOR);
61}
62
86static
90 _In_ PHHIVE RegistryHive)
91{
94 ULONG BlockIndex;
95 ULONG LastIndex;
96 PVOID Block;
97 UINT32 BitmapSize, BufferSize;
98 PUCHAR HeaderBuffer, Ptr;
99
100 /*
101 * The hive log we are going to write data into
102 * has to be writable and with a sane storage.
103 */
104 ASSERT(RegistryHive->ReadOnly == FALSE);
105 ASSERT(RegistryHive->BaseBlock->Length ==
106 RegistryHive->Storage[Stable].Length * HBLOCK_SIZE);
107
108 /* Validate the base header before we go further */
109 HvpValidateBaseHeader(RegistryHive);
110
111 /*
112 * The sequences can diverge in an occurrence of forced
113 * shutdown of the system such as during a power failure,
114 * the hardware crapping itself or during a system crash
115 * when one of the sequences have been modified during
116 * writing into the log or hive. In such cases the hive
117 * needs a repair.
118 */
119 if (RegistryHive->BaseBlock->Sequence1 !=
120 RegistryHive->BaseBlock->Sequence2)
121 {
122 DPRINT1("The sequences DO NOT MATCH (Sequence1 == 0x%x, Sequence2 == 0x%x)\n",
123 RegistryHive->BaseBlock->Sequence1, RegistryHive->BaseBlock->Sequence2);
124 return FALSE;
125 }
126
127 /*
128 * FIXME: We must set a new file size for this log
129 * here but ReactOS lacks the necessary code implementation
130 * that manages the growing and shrinking of a hive's log
131 * size. So for now don't set any new size for the log.
132 */
133
134 /*
135 * Now calculate the bitmap and buffer sizes to hold up our
136 * contents in a buffer.
137 */
138 BitmapSize = ROUND_UP(sizeof(ULONG) + RegistryHive->DirtyVector.SizeOfBitMap / 8, HSECTOR_SIZE);
139 BufferSize = HV_LOG_HEADER_SIZE + BitmapSize;
140
141 /* Now allocate the base header block buffer */
142 HeaderBuffer = RegistryHive->Allocate(BufferSize, TRUE, TAG_CM);
143 if (!HeaderBuffer)
144 {
145 DPRINT1("Couldn't allocate buffer for base header block\n");
146 return FALSE;
147 }
148
149 /* Great, now zero out the buffer */
150 RtlZeroMemory(HeaderBuffer, BufferSize);
151
152 /*
153 * Update the base block of this hive and
154 * increment the primary sequence number
155 * as we are at the half of the work.
156 */
157 RegistryHive->BaseBlock->Type = HFILE_TYPE_LOG;
158 RegistryHive->BaseBlock->Sequence1++;
159 RegistryHive->BaseBlock->CheckSum = HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
160
161 /* Copy the base block header */
162 RtlCopyMemory(HeaderBuffer, RegistryHive->BaseBlock, HV_LOG_HEADER_SIZE);
163 Ptr = HeaderBuffer + HV_LOG_HEADER_SIZE;
164
165 /* Copy the dirty vector */
167 Ptr += sizeof(HV_LOG_DIRTY_SIGNATURE);
168
169 /*
170 * FIXME: In ReactOS a vector contains one bit per block
171 * whereas in Windows each bit within a vector is per
172 * sector. Furthermore, the dirty blocks within a respective
173 * hive has to be marked as such in an appropriate function
174 * for this purpose (probably HvMarkDirty or similar).
175 *
176 * For the moment being, mark the relevant dirty blocks
177 * here.
178 */
179 BlockIndex = 0;
180 while (BlockIndex < RegistryHive->Storage[Stable].Length)
181 {
182 /* Check if the block is clean or we're past the last block */
183 LastIndex = BlockIndex;
184 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyVector, 1, BlockIndex);
185 if (BlockIndex == ~HV_CLEAN_BLOCK || BlockIndex < LastIndex)
186 {
187 break;
188 }
189
190 /*
191 * Mark this block as dirty and go to the next one.
192 *
193 * FIXME: We should rather use RtlSetBits but that crashes
194 * the system with a bugckeck. So for now mark blocks manually
195 * by hand.
196 */
197 Ptr[BlockIndex] = HV_LOG_DIRTY_BLOCK;
198 BlockIndex++;
199 }
200
201 /* Now write the hive header and block bitmap into the log */
202 FileOffset = 0;
203 Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG,
204 &FileOffset, HeaderBuffer, BufferSize);
205 RegistryHive->Free(HeaderBuffer, 0);
206 if (!Success)
207 {
208 DPRINT1("Failed to write the hive header block to log (primary sequence)\n");
209 return FALSE;
210 }
211
212 /* Now write the actual dirty data to log */
214 BlockIndex = 0;
215 while (BlockIndex < RegistryHive->Storage[Stable].Length)
216 {
217 /* Check if the block is clean or we're past the last block */
218 LastIndex = BlockIndex;
219 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyVector, 1, BlockIndex);
220 if (BlockIndex == ~HV_CLEAN_BLOCK || BlockIndex < LastIndex)
221 {
222 break;
223 }
224
225 /* Get the block */
226 Block = (PVOID)RegistryHive->Storage[Stable].BlockList[BlockIndex].BlockAddress;
227
228 /* Write it to log */
229 Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG,
230 &FileOffset, Block, HBLOCK_SIZE);
231 if (!Success)
232 {
233 DPRINT1("Failed to write dirty block to log (block 0x%p, block index 0x%x)\n", Block, BlockIndex);
234 return FALSE;
235 }
236
237 /* Grow up the file offset as we go to the next block */
238 BlockIndex++;
240 }
241
242 /*
243 * We wrote the header and body of log with dirty,
244 * data do a flush immediately.
245 */
246 Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_LOG, NULL, 0);
247 if (!Success)
248 {
249 DPRINT1("Failed to flush the log\n");
250 return FALSE;
251 }
252
253 /*
254 * OK, we're now at 80% of the work done.
255 * Increment the secondary sequence and flush
256 * the log again. We can have a fully successful
257 * transacted write of a log if the sequences
258 * are synced up properly.
259 */
260 RegistryHive->BaseBlock->Sequence2++;
261 RegistryHive->BaseBlock->CheckSum = HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
262
263 /* Write new stuff into log first */
264 FileOffset = 0;
265 Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG,
266 &FileOffset, RegistryHive->BaseBlock,
268 if (!Success)
269 {
270 DPRINT1("Failed to write the log file (secondary sequence)\n");
271 return FALSE;
272 }
273
274 /* Flush it finally */
275 Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_LOG, NULL, 0);
276 if (!Success)
277 {
278 DPRINT1("Failed to flush the log\n");
279 return FALSE;
280 }
281
282 return TRUE;
283}
284
313static
315CMAPI
317 _In_ PHHIVE RegistryHive,
318 _In_ BOOLEAN OnlyDirty,
320{
323 ULONG BlockIndex;
324 ULONG LastIndex;
325 PVOID Block;
326
327 ASSERT(RegistryHive->ReadOnly == FALSE);
328 ASSERT(RegistryHive->BaseBlock->Length ==
329 RegistryHive->Storage[Stable].Length * HBLOCK_SIZE);
330 ASSERT(RegistryHive->BaseBlock->RootCell != HCELL_NIL);
331
332 /* Validate the base header before we go further */
333 HvpValidateBaseHeader(RegistryHive);
334
335 /*
336 * The sequences can diverge in an occurrence of forced
337 * shutdown of the system such as during a power failure,
338 * the hardware crapping itself or during a system crash
339 * when one of the sequences have been modified during
340 * writing into the log or hive. In such cases the hive
341 * needs a repair.
342 */
343 if (RegistryHive->BaseBlock->Sequence1 !=
344 RegistryHive->BaseBlock->Sequence2)
345 {
346 DPRINT1("The sequences DO NOT MATCH (Sequence1 == 0x%x, Sequence2 == 0x%x)\n",
347 RegistryHive->BaseBlock->Sequence1, RegistryHive->BaseBlock->Sequence2);
348 return FALSE;
349 }
350
351 /*
352 * Update the primary sequence number and write
353 * the base block to hive.
354 */
355 RegistryHive->BaseBlock->Type = HFILE_TYPE_PRIMARY;
356 RegistryHive->BaseBlock->Sequence1++;
357 RegistryHive->BaseBlock->CheckSum = HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
358
359 /* Write hive block */
360 FileOffset = 0;
361 Success = RegistryHive->FileWrite(RegistryHive, FileType,
362 &FileOffset, RegistryHive->BaseBlock,
363 sizeof(HBASE_BLOCK));
364 if (!Success)
365 {
366 DPRINT1("Failed to write the base block header to primary hive (primary sequence)\n");
367 return FALSE;
368 }
369
370 /* Write the whole primary hive, block by block */
371 BlockIndex = 0;
372 while (BlockIndex < RegistryHive->Storage[Stable].Length)
373 {
374 /*
375 * If we have to syncrhonize the registry hive we
376 * want to look for dirty blocks to reflect the new
377 * updates done to the hive. Otherwise just write
378 * all the blocks as if we were doing a regular
379 * writing of the hive.
380 */
381 if (OnlyDirty)
382 {
383 /* Check if the block is clean or we're past the last block */
384 LastIndex = BlockIndex;
385 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyVector, 1, BlockIndex);
386 if (BlockIndex == ~HV_CLEAN_BLOCK || BlockIndex < LastIndex)
387 {
388 break;
389 }
390 }
391
392 /* Get the block and offset position */
393 Block = (PVOID)RegistryHive->Storage[Stable].BlockList[BlockIndex].BlockAddress;
394 FileOffset = (BlockIndex + 1) * HBLOCK_SIZE;
395
396 /* Now write this block to primary hive file */
397 Success = RegistryHive->FileWrite(RegistryHive, FileType,
398 &FileOffset, Block, HBLOCK_SIZE);
399 if (!Success)
400 {
401 DPRINT1("Failed to write hive block to primary hive file (block 0x%p, block index 0x%x)\n",
402 Block, BlockIndex);
403 return FALSE;
404 }
405
406 /* Go to the next block */
407 BlockIndex++;
408 }
409
410 /*
411 * We wrote all the hive contents to the file, we
412 * must flush the changes to disk now.
413 */
414 Success = RegistryHive->FileFlush(RegistryHive, FileType, NULL, 0);
415 if (!Success)
416 {
417 DPRINT1("Failed to flush the primary hive\n");
418 return FALSE;
419 }
420
421 /*
422 * Increment the secondary sequence number and
423 * update the checksum. A successful transaction
424 * writing of hive is both of sequences are the
425 * same indicating the writing operation didn't
426 * fail.
427 */
428 RegistryHive->BaseBlock->Sequence2++;
429 RegistryHive->BaseBlock->CheckSum = HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
430
431 /* Write hive block */
432 FileOffset = 0;
433 Success = RegistryHive->FileWrite(RegistryHive, FileType,
434 &FileOffset, RegistryHive->BaseBlock,
435 sizeof(HBASE_BLOCK));
436 if (!Success)
437 {
438 DPRINT1("Failed to write the base block header to primary hive (secondary sequence)\n");
439 return FALSE;
440 }
441
442 /* Flush the hive immediately */
443 Success = RegistryHive->FileFlush(RegistryHive, FileType, NULL, 0);
444 if (!Success)
445 {
446 DPRINT1("Failed to flush the primary hive\n");
447 return FALSE;
448 }
449
450 return TRUE;
451}
452
453/* PUBLIC FUNCTIONS ***********************************************************/
454
471CMAPI
473 _In_ PHHIVE RegistryHive)
474{
475#if !defined(CMLIB_HOST) && !defined(_BLDR_)
476 BOOLEAN HardErrors;
477#endif
478
479 ASSERT(RegistryHive->ReadOnly == FALSE);
480 ASSERT(RegistryHive->Signature == HV_HHIVE_SIGNATURE);
481
482 /*
483 * Check if there's any dirty data in the vector.
484 * A space with clean blocks would be pointless for
485 * a log because we want to write dirty data in and
486 * sync up, not clean data. So just consider our
487 * job as done as there's literally nothing to do.
488 */
489 if (RtlFindSetBits(&RegistryHive->DirtyVector, 1, 0) == ~HV_CLEAN_BLOCK)
490 {
491 DPRINT("The dirty vector has clean data, nothing to do\n");
492 return TRUE;
493 }
494
495 /*
496 * We are either in Live CD or we are sharing hives.
497 * In either of the cases, hives can only be read
498 * so don't do any writing operations on them.
499 */
500#if !defined(CMLIB_HOST) && !defined(_BLDR_)
501 if (CmpMiniNTBoot)
502 {
503 DPRINT("We are sharing hives or in Live CD mode, abort syncing\n");
504 return TRUE;
505 }
506#endif
507
508 /* Avoid any writing operations on volatile hives */
509 if (RegistryHive->HiveFlags & HIVE_VOLATILE)
510 {
511 DPRINT("The hive is volatile (hive 0x%p)\n", RegistryHive);
512 return TRUE;
513 }
514
515#if !defined(CMLIB_HOST) && !defined(_BLDR_)
516 /* Disable hard errors before syncing the hive */
517 HardErrors = IoSetThreadHardErrorMode(FALSE);
518#endif
519
520#if !defined(_BLDR_)
521 /* Update hive header modification time */
522 KeQuerySystemTime(&RegistryHive->BaseBlock->TimeStamp);
523#endif
524
525 /* Update the log file of hive if present */
526 if (RegistryHive->Log == TRUE)
527 {
528 if (!HvpWriteLog(RegistryHive))
529 {
530 DPRINT1("Failed to write a log whilst syncing the hive\n");
531#if !defined(CMLIB_HOST) && !defined(_BLDR_)
532 IoSetThreadHardErrorMode(HardErrors);
533#endif
534 return FALSE;
535 }
536 }
537
538 /* Update the primary hive file */
539 if (!HvpWriteHive(RegistryHive, TRUE, HFILE_TYPE_PRIMARY))
540 {
541 DPRINT1("Failed to write the primary hive\n");
542#if !defined(CMLIB_HOST) && !defined(_BLDR_)
543 IoSetThreadHardErrorMode(HardErrors);
544#endif
545 return FALSE;
546 }
547
548 /* Update the alternate hive file if present */
549 if (RegistryHive->Alternate == TRUE)
550 {
551 if (!HvpWriteHive(RegistryHive, TRUE, HFILE_TYPE_ALTERNATE))
552 {
553 DPRINT1("Failed to write the alternate hive\n");
554#if !defined(CMLIB_HOST) && !defined(_BLDR_)
555 IoSetThreadHardErrorMode(HardErrors);
556#endif
557 return FALSE;
558 }
559 }
560
561 /* Clear dirty bitmap. */
562 RtlClearAllBits(&RegistryHive->DirtyVector);
563 RegistryHive->DirtyCount = 0;
564
565#if !defined(CMLIB_HOST) && !defined(_BLDR_)
566 IoSetThreadHardErrorMode(HardErrors);
567#endif
568 return TRUE;
569}
570
588CMAPI
590 _In_ PHHIVE RegistryHive)
591{
592 /* No shrinking yet */
594 return FALSE;
595}
596
614CMAPI
616 _In_ PHHIVE RegistryHive)
617{
618 ASSERT(RegistryHive->ReadOnly == FALSE);
619 ASSERT(RegistryHive->Signature == HV_HHIVE_SIGNATURE);
620
621#if !defined(_BLDR_)
622 /* Update hive header modification time */
623 KeQuerySystemTime(&RegistryHive->BaseBlock->TimeStamp);
624#endif
625
626 /* Update hive file */
627 if (!HvpWriteHive(RegistryHive, FALSE, HFILE_TYPE_PRIMARY))
628 {
629 DPRINT1("Failed to write the hive\n");
630 return FALSE;
631 }
632
633 return TRUE;
634}
635
652CMAPI
654 _In_ PHHIVE RegistryHive)
655{
656 ASSERT(RegistryHive->ReadOnly == FALSE);
657 ASSERT(RegistryHive->Signature == HV_HHIVE_SIGNATURE);
658 ASSERT(RegistryHive->Alternate == TRUE);
659
660#if !defined(_BLDR_)
661 /* Update hive header modification time */
662 KeQuerySystemTime(&RegistryHive->BaseBlock->TimeStamp);
663#endif
664
665 /* Update hive file */
666 if (!HvpWriteHive(RegistryHive, FALSE, HFILE_TYPE_ALTERNATE))
667 {
668 DPRINT1("Failed to write the alternate hive\n");
669 return FALSE;
670 }
671
672 return TRUE;
673}
674
690CMAPI
692 _In_ PHHIVE RegistryHive)
693{
694 ASSERT(RegistryHive->ReadOnly == FALSE);
695 ASSERT(RegistryHive->Signature == HV_HHIVE_SIGNATURE);
696
697 /* Call the private API call to do the deed for us */
698 return HvpWriteHive(RegistryHive, TRUE, HFILE_TYPE_PRIMARY);
699}
700
701/* EOF */
unsigned char BOOLEAN
unsigned int UINT32
#define DPRINT1
Definition: precomp.h:8
_In_ PFCB _In_ LONGLONG FileOffset
Definition: cdprocs.h:160
#define CMAPI
Definition: cfgmgr32.h:41
ULONG CMAPI HvpHiveHeaderChecksum(PHBASE_BLOCK HiveHeader)
Definition: hivesum.c:17
#define TAG_CM
Definition: cmlib.h:212
#define BufferSize
Definition: mmc.h:75
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
@ Success
Definition: eventcreate.c:712
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
#define HV_HHIVE_SIGNATURE
Definition: hivedata.h:62
@ Stable
Definition: hivedata.h:127
#define HBLOCK_SIZE
Definition: hivedata.h:42
#define HV_LOG_HEADER_SIZE
Definition: hivedata.h:46
#define HFILE_TYPE_ALTERNATE
Definition: hivedata.h:36
#define HFILE_TYPE_LOG
Definition: hivedata.h:34
#define HV_HBLOCK_SIGNATURE
Definition: hivedata.h:63
#define HIVE_VOLATILE
Definition: hivedata.h:23
#define HFILE_TYPE_PRIMARY
Definition: hivedata.h:33
#define HV_CLEAN_BLOCK
Definition: hivedata.h:51
#define HCELL_NIL
Definition: hivedata.h:110
#define HSYS_MAJOR
Definition: hivedata.h:69
#define HV_LOG_DIRTY_BLOCK
Definition: hivedata.h:56
#define HBASE_FORMAT_MEMORY
Definition: hivedata.h:78
#define HV_LOG_DIRTY_SIGNATURE
Definition: hivedata.h:57
#define HSECTOR_SIZE
Definition: hivedata.h:43
BOOLEAN CMAPI HvSyncHive(_In_ PHHIVE RegistryHive)
Synchronizes a registry hive with latest updates from dirty data present in volatile memory,...
Definition: hivewrt.c:472
static BOOLEAN CMAPI HvpWriteHive(_In_ PHHIVE RegistryHive, _In_ BOOLEAN OnlyDirty, _In_ ULONG FileType)
Writes data (dirty or non) to a primary hive during syncing operation. Hive writing is also performed...
Definition: hivewrt.c:316
BOOLEAN CMAPI HvSyncHiveFromRecover(_In_ PHHIVE RegistryHive)
Synchronizes a hive with recovered data during a healing/resuscitation operation of the registry.
Definition: hivewrt.c:691
BOOLEAN CMAPI HvWriteHive(_In_ PHHIVE RegistryHive)
Writes data to a registry hive. Unlike HvSyncHive, this function just writes the wholy registry data ...
Definition: hivewrt.c:615
BOOLEAN CMAPI HvHiveWillShrink(_In_ PHHIVE RegistryHive)
Determines whether a registry hive needs to be shrinked or not based on its overall size of the hive ...
Definition: hivewrt.c:589
BOOLEAN NTAPI IoSetThreadHardErrorMode(_In_ BOOLEAN HardErrorEnabled)
static BOOLEAN CMAPI HvpWriteLog(_In_ PHHIVE RegistryHive)
Writes dirty data in a transacted way to a hive log file during hive syncing operation....
Definition: hivewrt.c:89
BOOLEAN CMAPI HvWriteAlternateHive(_In_ PHHIVE RegistryHive)
Writes data to an alternate registry hive. An alternate hive is usually backed up by a primary hive....
Definition: hivewrt.c:653
BOOLEAN CmpMiniNTBoot
Definition: cmdata.c:60
static VOID HvpValidateBaseHeader(_In_ PHHIVE RegistryHive)
Validates the base block header of a primary hive for consistency.
Definition: hivewrt.c:43
NTSYSAPI void WINAPI RtlClearAllBits(PRTL_BITMAP)
NTSYSAPI ULONG WINAPI RtlFindSetBits(PCRTL_BITMAP, ULONG, ULONG)
#define ASSERT(a)
Definition: mode.c:44
static IStorage Storage
Definition: ole2.c:3548
#define _In_
Definition: ms_sal.h:308
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define DPRINT
Definition: sndvol32.h:71
ULONG Major
Definition: hivedata.h:154
ULONG Signature
Definition: hivedata.h:144
ULONG Format
Definition: hivedata.h:164
uint32_t * PULONG
Definition: typedefs.h:59
#define UNIMPLEMENTED_ONCE
Definition: typedefs.h:30
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
_In_ WDFDEVICE _In_ WDF_SPECIAL_FILE_TYPE FileType
Definition: wdfdevice.h:2741
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254