1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxRegistryAPI.cpp
8 
9 Abstract:
10 
11     This module implements registry access in the framework
12 
13 Author:
14 
15 
16 
17 Environment:
18 
19     Both kernel and user mode
20 
21 Revision History:
22 
23 --*/
24 
25 #include "fxsupportpch.hpp"
26 
27 extern "C" {
28 // #include "FxRegistryAPI.tmh"
29 #define RtlSizeTToULong RtlULongPtrToULong
30 }
31 
32 extern "C" {
33 //
34 // Not in a public header that we can reach, but is documented
35 //
36 NTSYSAPI
37 NTSTATUS
38 NTAPI
39 ZwDeleteValueKey(
40     __in IN HANDLE Key,
41     __in IN PUNICODE_STRING ValueName
42     );
43 }
44 
45 
46 //
47 // Extern "C" the entire file
48 //
49 extern "C" {
50 
51 _Must_inspect_result_
52 __drv_maxIRQL(PASSIVE_LEVEL)
53 NTSTATUS
54 STDCALL
55 WDFEXPORT(WdfRegistryOpenKey)(
56     __in
57     PWDF_DRIVER_GLOBALS DriverGlobals,
58     __in_opt
59     WDFKEY ParentKey,
60     __in
61     PCUNICODE_STRING KeyName,
62     __in
63     ACCESS_MASK DesiredAccess,
64     __in_opt
65     PWDF_OBJECT_ATTRIBUTES KeyAttributes,
66     __out
67     WDFKEY* Key
68     )
69 {
70     DDI_ENTRY();
71 
72     FxRegKey* pKey;
73     PFX_DRIVER_GLOBALS pFxDriverGlobals;
74     NTSTATUS status;
75     WDFKEY keyHandle;
76     HANDLE parentHandle;
77 
78     pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
79     keyHandle = NULL;
80 
81     if (ParentKey != NULL) {
82         FxRegKey* pParent;
83 
84         FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
85                                        ParentKey,
86                                        FX_TYPE_REG_KEY,
87                                        (PVOID*) &pParent,
88                                        &pFxDriverGlobals);
89 
90         parentHandle = pParent->GetHandle();
91     }
92     else {
93         parentHandle = NULL;
94 
95         //
96         // Get the parent's globals if it is present
97         //
98         if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(pFxDriverGlobals,
99                                                                  KeyAttributes))) {
100             FxObject* pParent;
101 
102             FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
103                                            KeyAttributes->ParentObject,
104                                            FX_TYPE_OBJECT,
105                                            (PVOID*)&pParent,
106                                            &pFxDriverGlobals);
107         }
108     }
109 
110     FxPointerNotNull(pFxDriverGlobals, KeyName);
111     FxPointerNotNull(pFxDriverGlobals, Key);
112 
113     *Key = NULL;
114 
115     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
116     if (!NT_SUCCESS(status)) {
117         return status;
118     }
119 
120     status = FxValidateObjectAttributes(pFxDriverGlobals, KeyAttributes);
121     if (!NT_SUCCESS(status)) {
122         return status;
123     }
124 
125     status = FxValidateUnicodeString(pFxDriverGlobals, KeyName);
126     if (!NT_SUCCESS(status)) {
127         return status;
128     }
129 
130     pKey = new (pFxDriverGlobals, KeyAttributes) FxRegKey(pFxDriverGlobals);
131     if (pKey == NULL) {
132         status = STATUS_INSUFFICIENT_RESOURCES;
133 
134         DoTraceLevelMessage(
135             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
136             "Could not allocate memory for a WDFKEY, %!STATUS!", status);
137 
138         return status;
139     }
140 
141     status = pKey->Commit(KeyAttributes, (WDFOBJECT*)&keyHandle);
142 
143     if (NT_SUCCESS(status)) {
144         status = pKey->Open(parentHandle, KeyName, DesiredAccess);
145 
146         if (NT_SUCCESS(status)) {
147             *Key = keyHandle;
148         }
149         else {
150             DoTraceLevelMessage(
151                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
152                 "new WDFKEY object open failed, %!STATUS!", status);
153         }
154     }
155 
156     if (!NT_SUCCESS(status)) {
157         pKey->DeleteFromFailedCreate();
158         pKey = NULL;
159     }
160 
161     return status;
162 }
163 
164 _Must_inspect_result_
165 __drv_maxIRQL(PASSIVE_LEVEL)
166 NTSTATUS
167 STDCALL
168 WDFEXPORT(WdfRegistryCreateKey)(
169     __in
170     PWDF_DRIVER_GLOBALS DriverGlobals,
171     __in_opt
172     WDFKEY ParentKey,
173     __in
174     PCUNICODE_STRING KeyName,
175     __in
176     ACCESS_MASK DesiredAccess,
177     __in
178     ULONG CreateOptions,
179     __out_opt
180     PULONG CreateDisposition,
181     __in_opt
182     PWDF_OBJECT_ATTRIBUTES KeyAttributes,
183     __out
184     WDFKEY* Key
185     )
186 {
187     DDI_ENTRY();
188 
189     PFX_DRIVER_GLOBALS pFxDriverGlobals;
190     FxRegKey* pKey;
191     NTSTATUS status;
192     WDFKEY keyHandle;
193     HANDLE parentHandle;
194 
195     pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
196 
197     if (ParentKey != NULL) {
198         FxRegKey* pParent;
199 
200         FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
201                                        ParentKey,
202                                        FX_TYPE_REG_KEY,
203                                        (PVOID*) &pParent,
204                                        &pFxDriverGlobals);
205 
206         parentHandle = pParent->GetHandle();
207     }
208     else {
209         parentHandle = NULL;
210 
211         //
212         // Get the parent's globals if it is present
213         //
214         if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(pFxDriverGlobals,
215                                                                  KeyAttributes))) {
216             FxObject* pParent;
217 
218             FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
219                                            KeyAttributes->ParentObject,
220                                            FX_TYPE_OBJECT,
221                                            (PVOID*)&pParent,
222                                            &pFxDriverGlobals);
223         }
224     }
225 
226     FxPointerNotNull(pFxDriverGlobals, KeyName);
227     FxPointerNotNull(pFxDriverGlobals, Key);
228 
229     *Key = NULL;
230     keyHandle = NULL;
231 
232     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
233     if (!NT_SUCCESS(status)) {
234         return status;
235     }
236 
237     status = FxValidateObjectAttributes(pFxDriverGlobals, KeyAttributes);
238     if (!NT_SUCCESS(status)) {
239         return status;
240     }
241 
242     status = FxValidateUnicodeString(pFxDriverGlobals, KeyName);
243     if (!NT_SUCCESS(status)) {
244         return status;
245     }
246 
247     pKey = new (pFxDriverGlobals, KeyAttributes) FxRegKey(pFxDriverGlobals);
248 
249     if (pKey == NULL) {
250         status = STATUS_INSUFFICIENT_RESOURCES;
251         DoTraceLevelMessage(
252             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
253             "Could not allocate memory for WDFKEY, %!STATUS!", status);
254 
255         return status;
256     }
257 
258     status = pKey->Commit(KeyAttributes, (WDFOBJECT*)&keyHandle);
259 
260     if (NT_SUCCESS(status)) {
261         status = pKey->Create(parentHandle,
262                               KeyName,
263                               DesiredAccess,
264                               CreateOptions,
265                               CreateDisposition);
266 
267         if (NT_SUCCESS(status)) {
268             *Key = keyHandle;
269         }
270         else {
271             DoTraceLevelMessage(
272                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
273                 "Registry key creation failed, %!STATUS!", status);
274         }
275     }
276 
277     if (!NT_SUCCESS(status)) {
278         pKey->DeleteFromFailedCreate();
279         pKey = NULL;
280     }
281 
282     return status;
283 }
284 
285 __drv_maxIRQL(PASSIVE_LEVEL)
286 VOID
287 STDCALL
288 WDFEXPORT(WdfRegistryClose)(
289     __in
290     PWDF_DRIVER_GLOBALS DriverGlobals,
291     __in
292     WDFKEY Key
293     )
294 {
295     DDI_ENTRY();
296 
297     PFX_DRIVER_GLOBALS pFxDriverGlobals;
298     FxRegKey* pKey;
299     NTSTATUS status;
300 
301     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
302                                    Key,
303                                    FX_TYPE_REG_KEY,
304                                    (PVOID*) &pKey,
305                                    &pFxDriverGlobals);
306 
307     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
308     if (!NT_SUCCESS(status)) {
309         FxVerifierDbgBreakPoint(pFxDriverGlobals);
310         return;
311     }
312 
313     pKey->Close();
314 
315     pKey->DeleteObject();
316 }
317 
318 __drv_maxIRQL(PASSIVE_LEVEL)
319 HANDLE
320 STDCALL
321 WDFEXPORT(WdfRegistryWdmGetHandle)(
322     __in
323     PWDF_DRIVER_GLOBALS DriverGlobals,
324     __in
325     WDFKEY Key
326     )
327 {
328     DDI_ENTRY();
329 
330     FxRegKey* pKey;
331 
332     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
333                          Key,
334                          FX_TYPE_REG_KEY,
335                          (PVOID*) &pKey);
336 
337     return pKey->GetHandle();
338 }
339 
340 _Must_inspect_result_
341 __drv_maxIRQL(PASSIVE_LEVEL)
342 NTSTATUS
343 STDCALL
344 WDFEXPORT(WdfRegistryRemoveKey)(
345     __in
346     PWDF_DRIVER_GLOBALS DriverGlobals,
347     __in
348     WDFKEY Key
349     )
350 {
351     DDI_ENTRY();
352 
353     PFX_DRIVER_GLOBALS pFxDriverGlobals;
354     FxRegKey* pKey;
355     NTSTATUS status;
356 
357     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
358                                    Key,
359                                    FX_TYPE_REG_KEY,
360                                    (PVOID*) &pKey,
361                                    &pFxDriverGlobals);
362 
363     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
364     if (!NT_SUCCESS(status)) {
365         return status;
366     }
367 
368     status = Mx::MxDeleteKey(pKey->GetHandle());
369 
370     if (NT_SUCCESS(status)) {
371         //
372         // pKey->GetHandle() is now useless, delete the Fx object
373         //
374         pKey->DeleteObject();
375     }
376 
377     return status;
378 }
379 
380 _Must_inspect_result_
381 __drv_maxIRQL(PASSIVE_LEVEL)
382 NTSTATUS
383 STDCALL
384 WDFEXPORT(WdfRegistryRemoveValue)(
385     __in
386     PWDF_DRIVER_GLOBALS DriverGlobals,
387     __in
388     WDFKEY Key,
389     __in
390     PCUNICODE_STRING ValueName
391     )
392 {
393     DDI_ENTRY();
394 
395     PFX_DRIVER_GLOBALS pFxDriverGlobals;
396     FxRegKey* pKey;
397     NTSTATUS status;
398 
399     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
400                                    Key,
401                                    FX_TYPE_REG_KEY,
402                                    (PVOID*) &pKey,
403                                    &pFxDriverGlobals);
404 
405     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
406     if (!NT_SUCCESS(status)) {
407         return status;
408     }
409 
410     status = FxValidateUnicodeString(pFxDriverGlobals, ValueName);
411     if (!NT_SUCCESS(status)) {
412         return status;
413     }
414 
415     FxPointerNotNull(pFxDriverGlobals, ValueName);
416 
417     status = ZwDeleteValueKey(pKey->GetHandle(), (PUNICODE_STRING) ValueName);
418 
419     return status;
420 }
421 
422 _Must_inspect_result_
423 __drv_maxIRQL(PASSIVE_LEVEL)
424 NTSTATUS
425 STDCALL
426 WDFEXPORT(WdfRegistryQueryValue)(
427     __in
428     PWDF_DRIVER_GLOBALS DriverGlobals,
429     __in
430     WDFKEY Key,
431     __in
432     PCUNICODE_STRING ValueName,
433     __in
434     ULONG ValueLength,
435     __out_bcount_opt( ValueLength)
436     PVOID Value,
437      __out_opt
438     PULONG ValueLengthQueried,
439      __out_opt
440     PULONG ValueType
441     )
442 {
443     DDI_ENTRY();
444 
445     PFX_DRIVER_GLOBALS pFxDriverGlobals;
446     FxRegKey* pKey;
447     NTSTATUS status;
448 
449     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
450                                    Key,
451                                    FX_TYPE_REG_KEY,
452                                    (PVOID*) &pKey,
453                                    &pFxDriverGlobals);
454 
455     FxPointerNotNull(pFxDriverGlobals, ValueName);
456 
457     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
458     if (!NT_SUCCESS(status)) {
459         return status;
460     }
461 
462     status = FxValidateUnicodeString(pFxDriverGlobals, ValueName);
463     if (!NT_SUCCESS(status)) {
464         return status;
465     }
466 
467     status = FxRegKey::_QueryValue(pFxDriverGlobals,
468                                    pKey->GetHandle(),
469                                    ValueName,
470                                    ValueLength,
471                                    Value,
472                                    ValueLengthQueried,
473                                    ValueType);
474     if (!NT_SUCCESS(status)) {
475         UCHAR traceLevel = TRACE_LEVEL_ERROR;
476 
477         //
478         // Label message as Verbose if this is the known pattern of
479         // passing a 0-length NULL buffer to query the required buffer size.
480         //
481         if (status == STATUS_BUFFER_OVERFLOW && Value == NULL && ValueLength == 0) {
482             traceLevel = TRACE_LEVEL_VERBOSE;
483         }
484 
485         DoTraceLevelMessage(pFxDriverGlobals, traceLevel, TRACINGERROR,
486                             "WDFKEY %p QueryValue failed, %!STATUS!",
487                             Key, status);
488     }
489 
490     return status;
491 }
492 
493 _Must_inspect_result_
494 __drv_maxIRQL(PASSIVE_LEVEL)
495 NTSTATUS
496 STDCALL
497 WDFEXPORT(WdfRegistryQueryMemory)(
498     __in
499     PWDF_DRIVER_GLOBALS DriverGlobals,
500     __in
501     WDFKEY Key,
502     __in
503     PCUNICODE_STRING ValueName,
504     __in
505     __drv_strictTypeMatch( 1)
506     POOL_TYPE PoolType,
507      __in_opt
508     PWDF_OBJECT_ATTRIBUTES MemoryAttributes,
509     __out
510     WDFMEMORY* Memory,
511     __out_opt
512     PULONG ValueType
513     )
514 {
515     DDI_ENTRY();
516 
517     FxRegKey* pKey;
518     PFX_DRIVER_GLOBALS pFxDriverGlobals;
519     NTSTATUS status;
520     ULONG dataLength;
521     PVOID dataBuffer;
522 
523     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
524                                    Key,
525                                    FX_TYPE_REG_KEY,
526                                    (PVOID*) &pKey,
527                                    &pFxDriverGlobals);
528 
529     FxPointerNotNull(pFxDriverGlobals, ValueName);
530     FxPointerNotNull(pFxDriverGlobals, Memory);
531 
532     *Memory = NULL;
533 
534     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
535     if (!NT_SUCCESS(status)) {
536         return status;
537     }
538 
539     FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, pFxDriverGlobals->Tag);
540 
541     status = FxValidateObjectAttributes(pFxDriverGlobals, MemoryAttributes);
542     if (!NT_SUCCESS(status)) {
543         return status;
544     }
545 
546     status = FxValidateUnicodeString(pFxDriverGlobals, ValueName);
547     if (!NT_SUCCESS(status)) {
548         return status;
549     }
550 
551     //
552     // Query the buffer length required.
553     //
554     status = pKey->QueryValue(ValueName, 0, NULL, &dataLength, NULL);
555     if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) {
556         return status;
557     }
558 
559     dataBuffer = FxPoolAllocate(pFxDriverGlobals, PagedPool, dataLength);
560     if (dataBuffer == NULL) {
561         status = STATUS_INSUFFICIENT_RESOURCES;
562 
563         DoTraceLevelMessage(
564             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
565             "WDFKEY %p KEY_VALUE_PARTIAL_INFORMATION allocation failed, %!STATUS!",
566             Key, status);
567 
568         return status;
569     }
570 
571     status = pKey->QueryValue(ValueName, dataLength, dataBuffer, &dataLength, ValueType);
572     if (NT_SUCCESS(status)) {
573         FxMemoryObject* pObject;
574 
575         status = FxMemoryObject::_Create(pFxDriverGlobals,
576                                          MemoryAttributes,
577                                          PoolType,
578                                          pFxDriverGlobals->Tag,
579                                          dataLength,
580                                          &pObject);
581 
582         if (NT_SUCCESS(status)) {
583             status  = pObject->Commit(MemoryAttributes, (WDFOBJECT*) Memory);
584 
585             if (NT_SUCCESS(status)) {
586                 RtlCopyMemory(pObject->GetBuffer(),
587                               dataBuffer,
588                               dataLength);
589             }
590             else {
591                 pObject->DeleteFromFailedCreate();
592             }
593         }
594         else {
595             DoTraceLevelMessage(
596                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
597                 "WDFKEY %p WDFMEMORY object create failed, %!STATUS!",
598                 Key, status);
599         }
600     }
601     else {
602         DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
603                              "WDFKEY %p QueryPartial failed, %!STATUS!",
604                              Key, status);
605     }
606 
607     FxPoolFree(dataBuffer);
608 
609     return status;
610 }
611 
612 _Must_inspect_result_
613 __drv_maxIRQL(PASSIVE_LEVEL)
614 NTSTATUS
615 STDCALL
616 WDFEXPORT(WdfRegistryQueryMultiString)(
617     __in
618     PWDF_DRIVER_GLOBALS DriverGlobals,
619     __in
620     WDFKEY Key,
621     __in
622     PCUNICODE_STRING ValueName,
623     __in_opt
624     PWDF_OBJECT_ATTRIBUTES StringsAttributes,
625     __in
626     WDFCOLLECTION Collection
627     )
628 {
629     DDI_ENTRY();
630 
631     PFX_DRIVER_GLOBALS pFxDriverGlobals;
632     FxDeviceBase* pDeviceBase;
633     FxCollection* pCollection;
634     FxRegKey* pKey;
635     NTSTATUS status;
636     ULONG dataLength, type;
637     PVOID dataBuffer;
638 
639     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
640                                    Key,
641                                    FX_TYPE_REG_KEY,
642                                    (PVOID*) &pKey,
643                                    &pFxDriverGlobals);
644 
645     pDeviceBase = NULL;
646 
647     FxPointerNotNull(pFxDriverGlobals, ValueName);
648     FxPointerNotNull(pFxDriverGlobals, Collection);
649 
650     status = FxValidateObjectAttributes(pFxDriverGlobals, StringsAttributes);
651     if (!NT_SUCCESS(status)) {
652         return status;
653     }
654 
655     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
656     if (!NT_SUCCESS(status)) {
657         return status;
658     }
659 
660     status = FxValidateUnicodeString(pFxDriverGlobals, ValueName);
661     if (!NT_SUCCESS(status)) {
662         return status;
663     }
664 
665     FxObjectHandleGetPtr(pFxDriverGlobals,
666                          Collection,
667                          FX_TYPE_COLLECTION,
668                          (PVOID*) &pCollection);
669 
670     pDeviceBase = FxDeviceBase::_SearchForDevice(pFxDriverGlobals,
671                                                  StringsAttributes);
672 
673     status = pKey->QueryValue(ValueName, 0, NULL, &dataLength, &type);
674     if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) {
675         DoTraceLevelMessage(
676             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
677             "WDFKEY %p QueryPartial failed: %!STATUS!", Key, status);
678 
679         return status;
680     }
681 
682     if (type != REG_MULTI_SZ) {
683         return STATUS_OBJECT_TYPE_MISMATCH;
684     }
685 
686     dataBuffer = FxPoolAllocate(pFxDriverGlobals, PagedPool, dataLength);
687     if (dataBuffer == NULL) {
688         status = STATUS_INSUFFICIENT_RESOURCES;
689 
690         DoTraceLevelMessage(
691             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
692             "WDFKEY %p KEY_VALUE_PARTIAL_INFORMATION allocation failed, %!STATUS!",
693             Key, status);
694 
695         return status;
696     }
697 
698     status = pKey->QueryValue(ValueName, dataLength, dataBuffer, &dataLength, &type);
699     if (NT_SUCCESS(status)) {
700         //
701         // Verify that the data from the registry is a valid multi-sz string.
702         //
703         status = FxRegKey::_VerifyMultiSzString(pFxDriverGlobals,
704                                                 ValueName,
705                                                 (PWCHAR) dataBuffer,
706                                                 dataLength);
707     }
708 
709     if (NT_SUCCESS(status)) {
710         ULONG initialCount;
711         PWCHAR pCur;
712 
713         initialCount = pCollection->Count();
714         pCur = (PWCHAR) dataBuffer;
715 
716         while (*pCur != UNICODE_NULL) {
717             FxString* pString;
718 
719             pString = new (pFxDriverGlobals, StringsAttributes)
720                 FxString(pFxDriverGlobals);
721 
722             if (pString != NULL) {
723                 if (pDeviceBase != NULL) {
724                     pString->SetDeviceBase(pDeviceBase);
725                 }
726 
727                 status = pString->Assign(pCur);
728 
729                 if (NT_SUCCESS(status)) {
730                     WDFOBJECT dummy;
731 
732                     status = pString->Commit(StringsAttributes, &dummy);
733                 }
734 
735                 if (NT_SUCCESS(status)) {
736                     if (pCollection->Add(pString) == FALSE) {
737                         status = STATUS_INSUFFICIENT_RESOURCES;
738 
739                         DoTraceLevelMessage(
740                             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
741                             "WDFKEY %p, WDFCOLLECTION %p, collection add failed "
742                             "%!STATUS!", Key, Collection, status);
743                     }
744                 }
745 
746                 if (!NT_SUCCESS(status)) {
747                     //
748                     // Delete the string we just created
749                     //
750                     pString->DeleteFromFailedCreate();
751                 }
752                 else {
753                     //
754                     // NT_SUCCES(status)
755                     //
756                     // Either the caller is responsible for freeing the
757                     // WDFSTRING or it has been parented to another object.
758                     //
759                     DO_NOTHING();
760                 }
761             }
762             else {
763                 status = STATUS_INSUFFICIENT_RESOURCES;
764             }
765 
766             if (!NT_SUCCESS(status)) {
767                 DoTraceLevelMessage(
768                     pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
769                     "WDFKEY %p: WDFSTRING creation failed: %!STATUS!",
770                     Key, status);
771                 break;
772             }
773 
774             //
775             // Increment to the next string in the multi sz (length of string +
776             // 1 for the NULL)
777             //
778             pCur += wcslen(pCur) + 1;
779         }
780 
781         if (!NT_SUCCESS(status)) {
782             //
783             // Clear out all the items we added to the collection
784             //
785             while (pCollection->Count() > initialCount) {
786                 pCollection->Remove(initialCount);
787             }
788         }
789     }
790 
791     FxPoolFree(dataBuffer);
792 
793     return status;
794 }
795 
796 _Must_inspect_result_
797 __drv_maxIRQL(PASSIVE_LEVEL)
798 NTSTATUS
799 STDCALL
800 WDFEXPORT(WdfRegistryQueryUnicodeString)(
801     __in
802     PWDF_DRIVER_GLOBALS DriverGlobals,
803     __in
804     WDFKEY Key,
805     __in
806     PCUNICODE_STRING ValueName,
807     __out_opt
808     PUSHORT ValueByteLength,
809     __inout_opt
810     PUNICODE_STRING Value
811     )
812 {
813     DDI_ENTRY();
814 
815     PFX_DRIVER_GLOBALS pFxDriverGlobals;
816     FxRegKey* pKey;
817     NTSTATUS status;
818     ULONG dataLength, type;
819     PVOID dataBuffer;
820 
821     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
822                                    Key,
823                                    FX_TYPE_REG_KEY,
824                                    (PVOID*) &pKey,
825                                    &pFxDriverGlobals);
826 
827     FxPointerNotNull(pFxDriverGlobals, ValueName);
828 
829     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
830     if (!NT_SUCCESS(status)) {
831         return status;
832     }
833 
834     status = FxValidateUnicodeString(pFxDriverGlobals, ValueName);
835     if (!NT_SUCCESS(status)) {
836         return status;
837     }
838 
839     if (Value != NULL) {
840         status = FxValidateUnicodeString(pFxDriverGlobals, Value);
841         if (!NT_SUCCESS(status)) {
842             return status;
843         }
844     }
845 
846     if (Value == NULL) {
847         //
848         // Caller wants to know just the length
849         //
850         dataLength = 0;
851         dataBuffer = NULL;
852     }
853     else {
854         dataLength = Value->MaximumLength;
855         dataBuffer = FxPoolAllocate(pFxDriverGlobals, PagedPool, dataLength);
856 
857         if (dataBuffer == NULL) {
858             status = STATUS_INSUFFICIENT_RESOURCES;
859 
860             DoTraceLevelMessage(
861                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
862                 "WDFKEY %p KEY_VALUE_PARTIAL_INFORMATION allocation failed, "
863                 "%!STATUS!", Key, status);
864 
865             return status;
866         }
867     }
868 
869     status = pKey->QueryValue(ValueName, dataLength, dataBuffer, &dataLength, &type);
870     if (NT_SUCCESS(status) &&
871         FxRegKey::_IsValidSzType(type) == FALSE) {
872         status = STATUS_OBJECT_TYPE_MISMATCH;
873     }
874 
875     //
876     // Set ValueByteLength before doing the copy
877     //
878     if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {
879         //
880         // pPartial->DataLength is in bytes, convert to number of
881         // WCHARs
882         //
883         if (ValueByteLength != NULL) {
884             *ValueByteLength = (USHORT)dataLength ;
885         }
886     }
887 
888     if (NT_SUCCESS(status) && Value != NULL) {
889 
890 
891 
892 
893         ASSERT(ValueByteLength == NULL ||
894                *ValueByteLength  >= dataLength);
895 
896         //
897         // pPartial->DataLength cannot be greater than Value->MaximumLength
898         // based on the call to _ComputePartialSize above. So it is safe to
899         // copy the pPartial data buffer to the Value buffer.
900         //
901         __analysis_assume(dataLength <= Value->MaximumLength);
902         RtlCopyMemory(Value->Buffer, dataBuffer, dataLength);
903 
904         //terminating null shouldn't be included in the Length
905         Value->Length = (USHORT)dataLength;
906 
907         if (Value->Buffer[Value->Length/sizeof(WCHAR)-1] == UNICODE_NULL) {
908                 Value->Length -= sizeof(WCHAR);
909         }
910     }
911 
912     if (dataBuffer != NULL) {
913         FxPoolFree(dataBuffer);
914     }
915 
916     return status;
917 }
918 
919 _Must_inspect_result_
920 __drv_maxIRQL(PASSIVE_LEVEL)
921 NTSTATUS
922 STDCALL
923 WDFEXPORT(WdfRegistryQueryString)(
924     __in
925     PWDF_DRIVER_GLOBALS DriverGlobals,
926     __in
927     WDFKEY Key,
928     __in
929     PCUNICODE_STRING ValueName,
930     __in
931     WDFSTRING String
932     )
933 {
934     DDI_ENTRY();
935 
936     PFX_DRIVER_GLOBALS pFxDriverGlobals;
937     FxString* pString;
938     FxRegKey* pKey;
939     NTSTATUS status;
940     ULONG dataLength, type;
941     PVOID dataBuffer;
942 
943     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
944                                    Key,
945                                    FX_TYPE_REG_KEY,
946                                    (PVOID*) &pKey,
947                                    &pFxDriverGlobals);
948 
949     FxPointerNotNull(pFxDriverGlobals, ValueName);
950     FxPointerNotNull(pFxDriverGlobals, String);
951 
952     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
953     if (!NT_SUCCESS(status)) {
954         return status;
955     }
956 
957     status = FxValidateUnicodeString(pFxDriverGlobals, ValueName);
958     if (!NT_SUCCESS(status)) {
959         return status;
960     }
961 
962     FxObjectHandleGetPtr(pFxDriverGlobals,
963                          String,
964                          FX_TYPE_STRING,
965                          (PVOID*) &pString);
966 
967     status = pKey->QueryValue(ValueName, 0, NULL, &dataLength, &type);
968     if (NT_SUCCESS(status) &&
969         FxRegKey::_IsValidSzType(type) == FALSE) {
970         status = STATUS_OBJECT_TYPE_MISMATCH;
971     }
972 
973     if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) {
974         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
975                             "WDFKEY %p, QueryPartial failed, %!STATUS!",
976                             Key, status);
977         return status;
978     }
979 
980     dataBuffer = FxPoolAllocate(pFxDriverGlobals, PagedPool, dataLength);
981     if (dataBuffer == NULL) {
982         status = STATUS_INSUFFICIENT_RESOURCES;
983 
984         DoTraceLevelMessage(
985             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
986             "WDFKEY %p KEY_VALUE_PARTIAL_INFORMATION allocation failed, "
987             "%!STATUS!", Key, status);
988 
989         return status;
990     }
991 
992     status = pKey->QueryValue(ValueName, dataLength, dataBuffer, &dataLength, &type);
993     if (NT_SUCCESS(status) &&
994         FxRegKey::_IsValidSzType(type) == FALSE) {
995         status = STATUS_OBJECT_TYPE_MISMATCH;
996     }
997 
998     if (NT_SUCCESS(status)) {
999         if (dataLength <= USHORT_MAX) {
1000             UNICODE_STRING tmp;
1001 
1002             if (dataLength == 0x0) {
1003                 //
1004                 // Empty string
1005                 //
1006                 tmp.Buffer = L"";
1007                 tmp.Length = 0;
1008                 tmp.MaximumLength = 0;
1009             }
1010             else {
1011 
1012                 //
1013                 // The string we read may not be NULL terminated, so put it into a
1014                 // UNICODE_STRING.  If the final character is NULL, shorten the
1015                 // length of the string so that it does not include for the NULL.
1016                 //
1017                 // If there are embedded NULLs in the string previous to the final
1018                 // character, we leave them in place.
1019                 //
1020                 tmp.Buffer = (PWCHAR) dataBuffer;
1021                 tmp.Length = (USHORT) dataLength;
1022                 tmp.MaximumLength = tmp.Length;
1023 
1024                 if (tmp.Buffer[(tmp.Length/sizeof(WCHAR))-1] == UNICODE_NULL) {
1025                     //
1026                     // Do not include the UNICODE_NULL in the length
1027                     //
1028                     tmp.Length -= sizeof(WCHAR);
1029                 }
1030             }
1031 
1032             status = pString->Assign(&tmp);
1033         }
1034         else {
1035             status = STATUS_INVALID_BUFFER_SIZE;
1036 
1037             DoTraceLevelMessage(
1038                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1039                 "WDFKEY %p QueryPartial failed, Length %d > max %d, %!STATUS!",
1040                 Key, dataLength, USHORT_MAX, status);
1041         }
1042     }
1043     else {
1044         DoTraceLevelMessage(
1045             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1046             "WDFKEY %p QueryPartial failed, Length %d, %!STATUS!",
1047             Key, dataLength, status);
1048     }
1049 
1050     FxPoolFree(dataBuffer);
1051 
1052     return status;
1053 }
1054 
1055 _Must_inspect_result_
1056 __drv_maxIRQL(PASSIVE_LEVEL)
1057 NTSTATUS
1058 STDCALL
1059 WDFEXPORT(WdfRegistryQueryULong)(
1060     __in
1061     PWDF_DRIVER_GLOBALS DriverGlobals,
1062     __in
1063     WDFKEY Key,
1064     __in
1065     PCUNICODE_STRING ValueName,
1066     __out
1067     PULONG Value
1068     )
1069 {
1070     DDI_ENTRY();
1071 
1072     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1073     FxRegKey* pKey;
1074     NTSTATUS status;
1075 
1076     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1077                                    Key,
1078                                    FX_TYPE_REG_KEY,
1079                                    (PVOID*) &pKey,
1080                                    &pFxDriverGlobals);
1081 
1082     FxPointerNotNull(pFxDriverGlobals, ValueName);
1083     FxPointerNotNull(pFxDriverGlobals, Value);
1084 
1085     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
1086     if (!NT_SUCCESS(status)) {
1087         return status;
1088     }
1089 
1090     status = FxValidateUnicodeString(pFxDriverGlobals, ValueName);
1091     if (!NT_SUCCESS(status)) {
1092         return status;
1093     }
1094 
1095     status = FxRegKey::_QueryULong(pKey->GetHandle(), ValueName, Value);
1096 
1097     if (!NT_SUCCESS(status)) {
1098         DoTraceLevelMessage(
1099             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1100             "WDFKEY %p, QueryULong, %!STATUS!", Key, status);
1101     }
1102 
1103     return status;
1104 }
1105 
1106 
1107 _Must_inspect_result_
1108 __drv_maxIRQL(PASSIVE_LEVEL)
1109 NTSTATUS
1110 STDCALL
1111 WDFEXPORT(WdfRegistryAssignValue)(
1112     __in
1113     PWDF_DRIVER_GLOBALS DriverGlobals,
1114     __in
1115     WDFKEY Key,
1116     __in
1117     PCUNICODE_STRING ValueName,
1118     __in
1119     ULONG ValueType,
1120     __in
1121     ULONG ValueLength,
1122     __in_ecount( ValueLength)
1123     PVOID Value
1124     )
1125 {
1126     DDI_ENTRY();
1127 
1128     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1129     FxRegKey* pKey;
1130     NTSTATUS status;
1131 
1132     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1133                                    Key,
1134                                    FX_TYPE_REG_KEY,
1135                                    (PVOID*) &pKey,
1136                                    &pFxDriverGlobals);
1137 
1138     FxPointerNotNull(pFxDriverGlobals, ValueName);
1139 
1140     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
1141     if (!NT_SUCCESS(status)) {
1142         return status;
1143     }
1144 
1145     status = FxValidateUnicodeString(pFxDriverGlobals, ValueName);
1146     if (!NT_SUCCESS(status)) {
1147         return status;
1148     }
1149 
1150     status = pKey->SetValue(ValueName, ValueType, Value, ValueLength);
1151 
1152     if (!NT_SUCCESS(status)) {
1153         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1154                             "WDFKEY %p SetValue, %!STATUS!", Key, status);
1155     }
1156 
1157     return status;
1158 }
1159 
1160 
1161 _Must_inspect_result_
1162 __drv_maxIRQL(PASSIVE_LEVEL)
1163 NTSTATUS
1164 STDCALL
1165 WDFEXPORT(WdfRegistryAssignMemory)(
1166     __in
1167     PWDF_DRIVER_GLOBALS DriverGlobals,
1168     __in
1169     WDFKEY Key,
1170     __in
1171     PCUNICODE_STRING ValueName,
1172     __in
1173     ULONG ValueType,
1174     __in
1175     WDFMEMORY Memory,
1176     __in_opt
1177     PWDFMEMORY_OFFSET MemoryOffsets
1178     )
1179 {
1180     DDI_ENTRY();
1181 
1182     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1183     IFxMemory* pMemory;
1184     FxRegKey* pKey;
1185     PVOID pBuffer;
1186     ULONG length;
1187     NTSTATUS status;
1188 
1189     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1190                                    Key,
1191                                    FX_TYPE_REG_KEY,
1192                                    (PVOID*) &pKey,
1193                                    &pFxDriverGlobals);
1194 
1195     FxPointerNotNull(pFxDriverGlobals, ValueName);
1196     FxPointerNotNull(pFxDriverGlobals, Memory);
1197 
1198     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
1199     if (!NT_SUCCESS(status)) {
1200         return status;
1201     }
1202 
1203     status = FxValidateUnicodeString(pFxDriverGlobals, ValueName);
1204     if (!NT_SUCCESS(status)) {
1205         return status;
1206     }
1207 
1208     FxObjectHandleGetPtr(pFxDriverGlobals,
1209                          Memory,
1210                          IFX_TYPE_MEMORY,
1211                          (PVOID*) &pMemory);
1212 
1213     pBuffer = pMemory->GetBuffer();
1214     length = (ULONG) pMemory->GetBufferSize();
1215 
1216     if (MemoryOffsets != NULL) {
1217         status = pMemory->ValidateMemoryOffsets(MemoryOffsets);
1218 
1219         if (!NT_SUCCESS(status)) {
1220             DoTraceLevelMessage(
1221                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1222                 "WDFKEY %p, WDFMEMORY %p Offsets overflowed, %!STATUS!",
1223                 Key, Memory, status);
1224 
1225             return status;
1226         }
1227 
1228         if (MemoryOffsets->BufferLength > 0) {
1229             status = RtlSizeTToULong(MemoryOffsets->BufferLength, &length);
1230 
1231             if (!NT_SUCCESS(status)) {
1232                 DoTraceLevelMessage(
1233                     pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1234                     "WDFKEY %p, WDFMEMORY %p BufferLength in Offsets truncated, "
1235                     "%!STATUS!", Key, Memory, status);
1236 
1237                 return status;
1238             }
1239         }
1240 
1241         pBuffer = WDF_PTR_ADD_OFFSET(pBuffer, MemoryOffsets->BufferOffset);
1242     }
1243 
1244     status = pKey->SetValue(ValueName, ValueType, pBuffer, length);
1245 
1246     if (!NT_SUCCESS(status)) {
1247         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1248                             "WDFKEY handle %p SetValue, %!STATUS!", Key, status);
1249     }
1250 
1251     return status;
1252 }
1253 
1254 _Must_inspect_result_
1255 __drv_maxIRQL(PASSIVE_LEVEL)
1256 NTSTATUS
1257 STDCALL
1258 WDFEXPORT(WdfRegistryAssignULong)(
1259     __in
1260     PWDF_DRIVER_GLOBALS DriverGlobals,
1261     __in
1262     WDFKEY Key,
1263     __in
1264     PCUNICODE_STRING ValueName,
1265     __in
1266     ULONG Value
1267     )
1268 {
1269     DDI_ENTRY();
1270 
1271     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1272     FxRegKey* pKey;
1273     NTSTATUS status;
1274 
1275     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1276                                    Key,
1277                                    FX_TYPE_REG_KEY,
1278                                    (PVOID*) &pKey,
1279                                    &pFxDriverGlobals);
1280 
1281     FxPointerNotNull(pFxDriverGlobals, ValueName);
1282 
1283     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
1284     if (!NT_SUCCESS(status)) {
1285         return status;
1286     }
1287 
1288     status = FxValidateUnicodeString(pFxDriverGlobals, ValueName);
1289     if (!NT_SUCCESS(status)) {
1290         return status;
1291     }
1292 
1293     status = pKey->SetValue(ValueName, REG_DWORD, &Value, sizeof(Value));
1294 
1295     if (!NT_SUCCESS(status)) {
1296         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1297                             "WDFKEY %p SetValue, %!STATUS!",
1298                             Key, status);
1299     }
1300 
1301     return status;
1302 }
1303 
1304 _Must_inspect_result_
1305 __drv_maxIRQL(PASSIVE_LEVEL)
1306 NTSTATUS
1307 STDCALL
1308 WDFEXPORT(WdfRegistryAssignUnicodeString)(
1309     __in
1310     PWDF_DRIVER_GLOBALS DriverGlobals,
1311     __in
1312     WDFKEY Key,
1313     __in
1314     PCUNICODE_STRING ValueName,
1315     __in
1316     PCUNICODE_STRING Value
1317     )
1318 {
1319     DDI_ENTRY();
1320 
1321     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1322     FxRegKey* pKey;
1323     NTSTATUS status;
1324     PWCHAR tempValueBuf;
1325     ULONG length;
1326 
1327     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1328                                    Key,
1329                                    FX_TYPE_REG_KEY,
1330                                    (PVOID*) &pKey,
1331                                    &pFxDriverGlobals);
1332 
1333     FxPointerNotNull(pFxDriverGlobals, ValueName);
1334     FxPointerNotNull(pFxDriverGlobals, Value);
1335 
1336     tempValueBuf = NULL;
1337 
1338     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
1339     if (!NT_SUCCESS(status)) {
1340         return status;
1341     }
1342 
1343     status = FxValidateUnicodeString(pFxDriverGlobals, ValueName);
1344     if (!NT_SUCCESS(status)) {
1345         return status;
1346     }
1347 
1348     status = FxValidateUnicodeString(pFxDriverGlobals, Value);
1349     if (!NT_SUCCESS(status)) {
1350         return status;
1351     }
1352 
1353     length = Value->Length + sizeof(UNICODE_NULL);
1354 
1355     //
1356     // Buffer must be NULL terminated and Length of the buffer must also include the NULL
1357     // Allocate a temporary buffer and NULL terminate it.
1358     //
1359     tempValueBuf = (PWCHAR) FxPoolAllocate(pFxDriverGlobals, PagedPool, length);
1360 
1361     if (tempValueBuf == NULL) {
1362         status = STATUS_INSUFFICIENT_RESOURCES;
1363 
1364         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1365                             "WDFKEY %p allocate temporary buffer failed, "
1366                             "%!STATUS!", Key, status);
1367 
1368         return status;
1369     }
1370 
1371     //
1372     // Copy over the string from the callers buffer and make sure it is
1373     // NULL terminated.
1374     //
1375     RtlCopyMemory(tempValueBuf, Value->Buffer, Value->Length);
1376     tempValueBuf[Value->Length/sizeof(WCHAR)] = UNICODE_NULL;
1377 
1378     status = pKey->SetValue(ValueName, REG_SZ, tempValueBuf, length);
1379 
1380     FxPoolFree(tempValueBuf);
1381 
1382     if (!NT_SUCCESS(status)) {
1383         DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1384                              "WDFKEY %p set value failed, %!STATUS!",
1385                              Key, status);
1386     }
1387 
1388     return status;
1389 }
1390 
1391 _Must_inspect_result_
1392 __drv_maxIRQL(PASSIVE_LEVEL)
1393 NTSTATUS
1394 STDCALL
1395 WDFEXPORT(WdfRegistryAssignString)(
1396     __in
1397     PWDF_DRIVER_GLOBALS DriverGlobals,
1398     __in
1399     WDFKEY Key,
1400     __in
1401     PCUNICODE_STRING ValueName,
1402     __in
1403     WDFSTRING String
1404     )
1405 {
1406     DDI_ENTRY();
1407 
1408     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1409     FxString* pString;
1410     FxRegKey* pKey;
1411     NTSTATUS status;
1412 
1413     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1414                                    Key,
1415                                    FX_TYPE_REG_KEY,
1416                                    (PVOID*) &pKey,
1417                                    &pFxDriverGlobals);
1418 
1419     FxPointerNotNull(pFxDriverGlobals, ValueName);
1420     FxPointerNotNull(pFxDriverGlobals, String);
1421 
1422     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
1423     if (!NT_SUCCESS(status)) {
1424         return status;
1425     }
1426 
1427     status = FxValidateUnicodeString(pFxDriverGlobals, ValueName);
1428     if (!NT_SUCCESS(status)) {
1429         return status;
1430     }
1431 
1432     FxObjectHandleGetPtr(pFxDriverGlobals,
1433                          String,
1434                          FX_TYPE_STRING,
1435                          (PVOID*) &pString);
1436 
1437     status = pKey->SetValue(ValueName,
1438                             REG_SZ,
1439                             pString->Buffer(),
1440                             pString->ByteLength(TRUE));
1441 
1442     if (!NT_SUCCESS(status)) {
1443         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1444                             "WDFKEY handle %p SetValue, %!STATUS!",
1445                             Key, status);
1446     }
1447 
1448     return status;
1449 }
1450 
1451 _Must_inspect_result_
1452 __drv_maxIRQL(PASSIVE_LEVEL)
1453 NTSTATUS
1454 STDCALL
1455 WDFEXPORT(WdfRegistryAssignMultiString)(
1456     __in
1457     PWDF_DRIVER_GLOBALS DriverGlobals,
1458     __in
1459     WDFKEY Key,
1460     __in
1461     PCUNICODE_STRING ValueName,
1462     __in
1463     WDFCOLLECTION StringsCollection
1464     )
1465 {
1466     DDI_ENTRY();
1467 
1468     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1469     FxCollection* pCollection;
1470     FxRegKey* pKey;
1471     PWCHAR pValue;
1472     NTSTATUS status;
1473     ULONG length;
1474     BOOLEAN valid;
1475 
1476     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1477                                    Key,
1478                                    FX_TYPE_REG_KEY,
1479                                    (PVOID*) &pKey,
1480                                    &pFxDriverGlobals);
1481 
1482     FxPointerNotNull(pFxDriverGlobals, ValueName);
1483     FxPointerNotNull(pFxDriverGlobals, StringsCollection);
1484 
1485     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
1486     if (!NT_SUCCESS(status)) {
1487         return status;
1488     }
1489 
1490     status = FxValidateUnicodeString(pFxDriverGlobals, ValueName);
1491     if (!NT_SUCCESS(status)) {
1492         return status;
1493     }
1494 
1495     FxObjectHandleGetPtr(pFxDriverGlobals,
1496                          StringsCollection,
1497                          FX_TYPE_COLLECTION,
1498                          (PVOID *) &pCollection);
1499 
1500     valid = FALSE;
1501 
1502     status = RtlSizeTToULong(
1503         FxCalculateTotalStringSize(pCollection, TRUE, &valid),
1504         &length);
1505 
1506     if (!NT_SUCCESS(status)) {
1507         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1508                             "WDFCOLLECTION %p, collection too large to fit into "
1509                             "a ULONG, %!STATUS!", StringsCollection, status);
1510         return status;
1511     }
1512 
1513     if (valid == FALSE) {
1514         status = STATUS_INVALID_PARAMETER;
1515         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1516                             "WDFKEY %p,  WDFCOLLECTION %p contains "
1517                             "non string objects, %!STATUS!",
1518                             Key, StringsCollection, status);
1519         return status;
1520     }
1521 
1522     pValue = (PWCHAR) FxPoolAllocate(pFxDriverGlobals, PagedPool, length);
1523 
1524     if (pValue == NULL) {
1525         status = STATUS_INSUFFICIENT_RESOURCES;
1526 
1527         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1528                             "WDFKEY %p allocate for query buffer failed, "
1529                             "%!STATUS!", Key, status);
1530 
1531         return status;
1532     }
1533 
1534     FxCopyMultiSz(pValue, pCollection);
1535 
1536     status = pKey->SetValue(ValueName, REG_MULTI_SZ, pValue, length);
1537 
1538     if (!NT_SUCCESS(status)) {
1539         DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1540                              "WDFKEY %p SetValue, %!STATUS!",
1541                              Key, status);
1542     }
1543 
1544     FxPoolFree(pValue);
1545 
1546     return status;
1547 }
1548 
1549 } // extern "C"
1550