- PCHify freeldr and cleanup some headers (just a start).
[reactos.git] / reactos / boot / freeldr / freeldr / reactos / registry.c
1 /*
2 * FreeLoader
3 *
4 * Copyright (C) 2001, 2002 Eric Kohl
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <freeldr.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26 static FRLDRHKEY RootKey;
27
28
29 VOID
30 RegInitializeRegistry (VOID)
31 {
32 #if 0
33 FRLDRHKEY TestKey;
34 #endif
35
36 /* Create root key */
37 RootKey = (FRLDRHKEY) MmAllocateMemory (sizeof(KEY));
38
39 InitializeListHead (&RootKey->SubKeyList);
40 InitializeListHead (&RootKey->ValueList);
41 InitializeListHead (&RootKey->KeyList);
42
43 RootKey->SubKeyCount = 0;
44 RootKey->ValueCount = 0;
45
46 RootKey->NameSize = 2;
47 RootKey->Name = MmAllocateMemory (2);
48 strcpy (RootKey->Name, "\\");
49
50 RootKey->DataType = 0;
51 RootKey->DataSize = 0;
52 RootKey->Data = NULL;
53
54 /* Create 'SYSTEM' key */
55 RegCreateKey (RootKey,
56 "Registry\\Machine\\SYSTEM",
57 NULL);
58
59 /* Create 'HARDWARE' key */
60 RegCreateKey (RootKey,
61 "Registry\\Machine\\HARDWARE",
62 NULL);
63
64 /* Create 'HARDWARE\DESCRIPTION' key */
65 RegCreateKey (RootKey,
66 "Registry\\Machine\\HARDWARE\\DESCRIPTION",
67 NULL);
68
69 /* Create 'HARDWARE\DEVICEMAP' key */
70 RegCreateKey (RootKey,
71 "Registry\\Machine\\HARDWARE\\DEVICEMAP",
72 NULL);
73
74 /* Create 'HARDWARE\RESOURCEMAP' key */
75 RegCreateKey (RootKey,
76 "Registry\\Machine\\HARDWARE\\RESOURCEMAP",
77 NULL);
78
79 /* Testcode */
80 #if 0
81 RegCreateKey (RootKey,
82 "Registry\\Machine\\HARDWARE\\DESCRIPTION\\TestKey",
83 &TestKey);
84
85 RegSetValue (TestKey,
86 "TestValue",
87 REG_SZ,
88 (PUCHAR)"TestString",
89 11);
90 #endif
91 }
92
93
94 LONG
95 RegInitCurrentControlSet(BOOL LastKnownGood)
96 {
97 CHAR ControlSetKeyName[80];
98 FRLDRHKEY SelectKey;
99 FRLDRHKEY SystemKey;
100 FRLDRHKEY ControlSetKey;
101 FRLDRHKEY LinkKey;
102 ULONG CurrentSet = 0;
103 ULONG DefaultSet = 0;
104 ULONG LastKnownGoodSet = 0;
105 ULONG DataSize;
106 LONG Error;
107
108 Error = RegOpenKey(NULL,
109 "\\Registry\\Machine\\SYSTEM\\Select",
110 &SelectKey);
111 if (Error != ERROR_SUCCESS)
112 {
113 DbgPrint((DPRINT_REGISTRY, "RegOpenKey() failed (Error %u)\n", (int)Error));
114 return(Error);
115 }
116
117 DataSize = sizeof(ULONG);
118 Error = RegQueryValue(SelectKey,
119 "Default",
120 NULL,
121 (PUCHAR)&DefaultSet,
122 &DataSize);
123 if (Error != ERROR_SUCCESS)
124 {
125 DbgPrint((DPRINT_REGISTRY, "RegQueryValue('Default') failed (Error %u)\n", (int)Error));
126 return(Error);
127 }
128
129 DataSize = sizeof(ULONG);
130 Error = RegQueryValue(SelectKey,
131 "LastKnownGood",
132 NULL,
133 (PUCHAR)&LastKnownGoodSet,
134 &DataSize);
135 if (Error != ERROR_SUCCESS)
136 {
137 DbgPrint((DPRINT_REGISTRY, "RegQueryValue('Default') failed (Error %u)\n", (int)Error));
138 return(Error);
139 }
140
141 CurrentSet = (LastKnownGood == TRUE) ? LastKnownGoodSet : DefaultSet;
142 strcpy(ControlSetKeyName, "ControlSet");
143 switch(CurrentSet)
144 {
145 case 1:
146 strcat(ControlSetKeyName, "001");
147 break;
148 case 2:
149 strcat(ControlSetKeyName, "002");
150 break;
151 case 3:
152 strcat(ControlSetKeyName, "003");
153 break;
154 case 4:
155 strcat(ControlSetKeyName, "004");
156 break;
157 case 5:
158 strcat(ControlSetKeyName, "005");
159 break;
160 }
161
162 Error = RegOpenKey(NULL,
163 "\\Registry\\Machine\\SYSTEM",
164 &SystemKey);
165 if (Error != ERROR_SUCCESS)
166 {
167 DbgPrint((DPRINT_REGISTRY, "RegOpenKey(SystemKey) failed (Error %u)\n", (int)Error));
168 return(Error);
169 }
170
171 Error = RegOpenKey(SystemKey,
172 ControlSetKeyName,
173 &ControlSetKey);
174 if (Error != ERROR_SUCCESS)
175 {
176 DbgPrint((DPRINT_REGISTRY, "RegOpenKey(ControlSetKey) failed (Error %u)\n", (int)Error));
177 return(Error);
178 }
179
180 Error = RegCreateKey(SystemKey,
181 "CurrentControlSet",
182 &LinkKey);
183 if (Error != ERROR_SUCCESS)
184 {
185 DbgPrint((DPRINT_REGISTRY, "RegCreateKey(LinkKey) failed (Error %u)\n", (int)Error));
186 return(Error);
187 }
188
189 Error = RegSetValue(LinkKey,
190 NULL,
191 REG_LINK,
192 (PCHAR)&ControlSetKey,
193 sizeof(PVOID));
194 if (Error != ERROR_SUCCESS)
195 {
196 DbgPrint((DPRINT_REGISTRY, "RegSetValue(LinkKey) failed (Error %u)\n", (int)Error));
197 return(Error);
198 }
199
200 return(ERROR_SUCCESS);
201 }
202
203
204 LONG
205 RegCreateKey(FRLDRHKEY ParentKey,
206 PCSTR KeyName,
207 PFRLDRHKEY Key)
208 {
209 PLIST_ENTRY Ptr;
210 FRLDRHKEY SearchKey = NULL;
211 FRLDRHKEY CurrentKey;
212 FRLDRHKEY NewKey;
213 PCHAR p;
214 PCSTR name;
215 int subkeyLength;
216 int stringLength;
217
218 DbgPrint((DPRINT_REGISTRY, "KeyName '%s'\n", KeyName));
219
220 if (*KeyName == '\\')
221 {
222 KeyName++;
223 CurrentKey = RootKey;
224 }
225 else if (ParentKey == NULL)
226 {
227 CurrentKey = RootKey;
228 }
229 else
230 {
231 CurrentKey = ParentKey;
232 }
233
234 /* Check whether current key is a link */
235 if (CurrentKey->DataType == REG_LINK)
236 {
237 CurrentKey = (FRLDRHKEY)CurrentKey->Data;
238 }
239
240 while (*KeyName != 0)
241 {
242 DbgPrint((DPRINT_REGISTRY, "KeyName '%s'\n", KeyName));
243
244 if (*KeyName == '\\')
245 KeyName++;
246 p = strchr(KeyName, '\\');
247 if ((p != NULL) && (p != KeyName))
248 {
249 subkeyLength = p - KeyName;
250 stringLength = subkeyLength + 1;
251 name = KeyName;
252 }
253 else
254 {
255 subkeyLength = strlen(KeyName);
256 stringLength = subkeyLength;
257 name = KeyName;
258 }
259
260 Ptr = CurrentKey->SubKeyList.Flink;
261 while (Ptr != &CurrentKey->SubKeyList)
262 {
263 DbgPrint((DPRINT_REGISTRY, "Ptr 0x%x\n", Ptr));
264
265 SearchKey = CONTAINING_RECORD(Ptr,
266 KEY,
267 KeyList);
268 DbgPrint((DPRINT_REGISTRY, "SearchKey 0x%x\n", SearchKey));
269 DbgPrint((DPRINT_REGISTRY, "Searching '%s'\n", SearchKey->Name));
270 if (strnicmp(SearchKey->Name, name, subkeyLength) == 0)
271 break;
272
273 Ptr = Ptr->Flink;
274 }
275
276 if (Ptr == &CurrentKey->SubKeyList)
277 {
278 /* no key found -> create new subkey */
279 NewKey = (FRLDRHKEY)MmAllocateMemory(sizeof(KEY));
280 if (NewKey == NULL)
281 return(ERROR_OUTOFMEMORY);
282
283 InitializeListHead(&NewKey->SubKeyList);
284 InitializeListHead(&NewKey->ValueList);
285
286 NewKey->SubKeyCount = 0;
287 NewKey->ValueCount = 0;
288
289 NewKey->DataType = 0;
290 NewKey->DataSize = 0;
291 NewKey->Data = NULL;
292
293 InsertTailList(&CurrentKey->SubKeyList, &NewKey->KeyList);
294 CurrentKey->SubKeyCount++;
295
296 NewKey->NameSize = subkeyLength + 1;
297 NewKey->Name = (PCHAR)MmAllocateMemory(NewKey->NameSize);
298 if (NewKey->Name == NULL)
299 return(ERROR_OUTOFMEMORY);
300 memcpy(NewKey->Name, name, subkeyLength);
301 NewKey->Name[subkeyLength] = 0;
302
303 DbgPrint((DPRINT_REGISTRY, "NewKey 0x%x\n", NewKey));
304 DbgPrint((DPRINT_REGISTRY, "NewKey '%s' Length %d\n", NewKey->Name, NewKey->NameSize));
305
306 CurrentKey = NewKey;
307 }
308 else
309 {
310 CurrentKey = SearchKey;
311
312 /* Check whether current key is a link */
313 if (CurrentKey->DataType == REG_LINK)
314 {
315 CurrentKey = (FRLDRHKEY)CurrentKey->Data;
316 }
317 }
318
319 KeyName = KeyName + stringLength;
320 }
321
322 if (Key != NULL)
323 *Key = CurrentKey;
324
325 return(ERROR_SUCCESS);
326 }
327
328
329 LONG
330 RegDeleteKey(FRLDRHKEY Key,
331 PCSTR Name)
332 {
333
334
335 if (strchr(Name, '\\') != NULL)
336 return(ERROR_INVALID_PARAMETER);
337
338
339
340 return(ERROR_SUCCESS);
341 }
342
343
344 LONG
345 RegEnumKey(FRLDRHKEY Key,
346 ULONG Index,
347 PCHAR Name,
348 ULONG* NameSize)
349 {
350 PLIST_ENTRY Ptr;
351 FRLDRHKEY SearchKey;
352 ULONG Count = 0;
353 ULONG Size;
354
355 Ptr = Key->SubKeyList.Flink;
356 while (Ptr != &Key->SubKeyList)
357 {
358 if (Index == Count)
359 break;
360
361 Count++;
362 Ptr = Ptr->Flink;
363 }
364
365 if (Ptr == &Key->SubKeyList)
366 return(ERROR_NO_MORE_ITEMS);
367
368 SearchKey = CONTAINING_RECORD(Ptr,
369 KEY,
370 KeyList);
371
372 DbgPrint((DPRINT_REGISTRY, "Name '%s' Length %d\n", SearchKey->Name, SearchKey->NameSize));
373
374 Size = min(SearchKey->NameSize, *NameSize);
375 *NameSize = Size;
376 memcpy(Name, SearchKey->Name, Size);
377
378 return(ERROR_SUCCESS);
379 }
380
381
382 LONG
383 RegOpenKey(FRLDRHKEY ParentKey,
384 PCSTR KeyName,
385 PFRLDRHKEY Key)
386 {
387 PLIST_ENTRY Ptr;
388 FRLDRHKEY SearchKey = NULL;
389 FRLDRHKEY CurrentKey;
390 PCHAR p;
391 PCSTR name;
392 int subkeyLength;
393 int stringLength;
394
395 DbgPrint((DPRINT_REGISTRY, "KeyName '%s'\n", KeyName));
396
397 *Key = NULL;
398
399 if (*KeyName == '\\')
400 {
401 KeyName++;
402 CurrentKey = RootKey;
403 }
404 else if (ParentKey == NULL)
405 {
406 CurrentKey = RootKey;
407 }
408 else
409 {
410 CurrentKey = ParentKey;
411 }
412
413 /* Check whether current key is a link */
414 if (CurrentKey->DataType == REG_LINK)
415 {
416 CurrentKey = (FRLDRHKEY)CurrentKey->Data;
417 }
418
419 while (*KeyName != 0)
420 {
421 DbgPrint((DPRINT_REGISTRY, "KeyName '%s'\n", KeyName));
422
423 if (*KeyName == '\\')
424 KeyName++;
425 p = strchr(KeyName, '\\');
426 if ((p != NULL) && (p != KeyName))
427 {
428 subkeyLength = p - KeyName;
429 stringLength = subkeyLength + 1;
430 name = KeyName;
431 }
432 else
433 {
434 subkeyLength = strlen(KeyName);
435 stringLength = subkeyLength;
436 name = KeyName;
437 }
438
439 Ptr = CurrentKey->SubKeyList.Flink;
440 while (Ptr != &CurrentKey->SubKeyList)
441 {
442 DbgPrint((DPRINT_REGISTRY, "Ptr 0x%x\n", Ptr));
443
444 SearchKey = CONTAINING_RECORD(Ptr,
445 KEY,
446 KeyList);
447
448 DbgPrint((DPRINT_REGISTRY, "SearchKey 0x%x\n", SearchKey));
449 DbgPrint((DPRINT_REGISTRY, "Searching '%s'\n", SearchKey->Name));
450
451 if (strnicmp(SearchKey->Name, name, subkeyLength) == 0)
452 break;
453
454 Ptr = Ptr->Flink;
455 }
456
457 if (Ptr == &CurrentKey->SubKeyList)
458 {
459 return(ERROR_PATH_NOT_FOUND);
460 }
461 else
462 {
463 CurrentKey = SearchKey;
464
465 /* Check whether current key is a link */
466 if (CurrentKey->DataType == REG_LINK)
467 {
468 CurrentKey = (FRLDRHKEY)CurrentKey->Data;
469 }
470 }
471
472 KeyName = KeyName + stringLength;
473 }
474
475 if (Key != NULL)
476 *Key = CurrentKey;
477
478 return(ERROR_SUCCESS);
479 }
480
481
482 LONG
483 RegSetValue(FRLDRHKEY Key,
484 PCSTR ValueName,
485 ULONG Type,
486 PCSTR Data,
487 ULONG DataSize)
488 {
489 PLIST_ENTRY Ptr;
490 PVALUE Value = NULL;
491
492 DbgPrint((DPRINT_REGISTRY, "Key 0x%x, ValueName '%s', Type %d, Data 0x%x, DataSize %d\n",
493 (int)Key, ValueName, (int)Type, (int)Data, (int)DataSize));
494
495 if ((ValueName == NULL) || (*ValueName == 0))
496 {
497 /* set default value */
498 if ((Key->Data != NULL) && (Key->DataSize > sizeof(PUCHAR)))
499 {
500 MmFreeMemory(Key->Data);
501 }
502
503 if (DataSize <= sizeof(PUCHAR))
504 {
505 Key->DataSize = DataSize;
506 Key->DataType = Type;
507 memcpy(&Key->Data, Data, DataSize);
508 }
509 else
510 {
511 Key->Data = MmAllocateMemory(DataSize);
512 Key->DataSize = DataSize;
513 Key->DataType = Type;
514 memcpy(Key->Data, Data, DataSize);
515 }
516 }
517 else
518 {
519 /* set non-default value */
520 Ptr = Key->ValueList.Flink;
521 while (Ptr != &Key->ValueList)
522 {
523 Value = CONTAINING_RECORD(Ptr,
524 VALUE,
525 ValueList);
526
527 DbgPrint((DPRINT_REGISTRY, "Value->Name '%s'\n", Value->Name));
528
529 if (stricmp(Value->Name, ValueName) == 0)
530 break;
531
532 Ptr = Ptr->Flink;
533 }
534
535 if (Ptr == &Key->ValueList)
536 {
537 /* add new value */
538 DbgPrint((DPRINT_REGISTRY, "No value found - adding new value\n"));
539
540 Value = (PVALUE)MmAllocateMemory(sizeof(VALUE));
541 if (Value == NULL)
542 return(ERROR_OUTOFMEMORY);
543
544 InsertTailList(&Key->ValueList, &Value->ValueList);
545 Key->ValueCount++;
546
547 Value->NameSize = strlen(ValueName)+1;
548 Value->Name = (PCHAR)MmAllocateMemory(Value->NameSize);
549 if (Value->Name == NULL)
550 return(ERROR_OUTOFMEMORY);
551 strcpy(Value->Name, ValueName);
552 Value->DataType = REG_NONE;
553 Value->DataSize = 0;
554 Value->Data = NULL;
555 }
556
557 /* set new value */
558 if ((Value->Data != NULL) && (Value->DataSize > sizeof(PUCHAR)))
559 {
560 MmFreeMemory(Value->Data);
561 }
562
563 if (DataSize <= sizeof(PUCHAR))
564 {
565 Value->DataSize = DataSize;
566 Value->DataType = Type;
567 memcpy(&Value->Data, Data, DataSize);
568 }
569 else
570 {
571 Value->Data = MmAllocateMemory(DataSize);
572 if (Value->Data == NULL)
573 return(ERROR_OUTOFMEMORY);
574 Value->DataType = Type;
575 Value->DataSize = DataSize;
576 memcpy(Value->Data, Data, DataSize);
577 }
578 }
579 return(ERROR_SUCCESS);
580 }
581
582
583 LONG
584 RegQueryValue(FRLDRHKEY Key,
585 PCSTR ValueName,
586 ULONG* Type,
587 PUCHAR Data,
588 ULONG* DataSize)
589 {
590 ULONG Size;
591 PLIST_ENTRY Ptr;
592 PVALUE Value = NULL;
593
594 if ((ValueName == NULL) || (*ValueName == 0))
595 {
596 /* query default value */
597 if (Key->Data == NULL)
598 return(ERROR_INVALID_PARAMETER);
599
600 if (Type != NULL)
601 *Type = Key->DataType;
602 if ((Data != NULL) && (DataSize != NULL))
603 {
604 if (Key->DataSize <= sizeof(PUCHAR))
605 {
606 Size = min(Key->DataSize, *DataSize);
607 memcpy(Data, &Key->Data, Size);
608 *DataSize = Size;
609 }
610 else
611 {
612 Size = min(Key->DataSize, *DataSize);
613 memcpy(Data, Key->Data, Size);
614 *DataSize = Size;
615 }
616 }
617 else if ((Data == NULL) && (DataSize != NULL))
618 {
619 *DataSize = Key->DataSize;
620 }
621 }
622 else
623 {
624 /* query non-default value */
625 Ptr = Key->ValueList.Flink;
626 while (Ptr != &Key->ValueList)
627 {
628 Value = CONTAINING_RECORD(Ptr,
629 VALUE,
630 ValueList);
631
632 DbgPrint((DPRINT_REGISTRY, "Searching for '%s'. Value name '%s'\n", ValueName, Value->Name));
633
634 if (stricmp(Value->Name, ValueName) == 0)
635 break;
636
637 Ptr = Ptr->Flink;
638 }
639
640 if (Ptr == &Key->ValueList)
641 return(ERROR_INVALID_PARAMETER);
642
643 if (Type != NULL)
644 *Type = Value->DataType;
645 if ((Data != NULL) && (DataSize != NULL))
646 {
647 if (Value->DataSize <= sizeof(PUCHAR))
648 {
649 Size = min(Value->DataSize, *DataSize);
650 memcpy(Data, &Value->Data, Size);
651 *DataSize = Size;
652 }
653 else
654 {
655 Size = min(Value->DataSize, *DataSize);
656 memcpy(Data, Value->Data, Size);
657 *DataSize = Size;
658 }
659 }
660 else if ((Data == NULL) && (DataSize != NULL))
661 {
662 *DataSize = Value->DataSize;
663 }
664 }
665
666 return(ERROR_SUCCESS);
667 }
668
669
670 LONG
671 RegDeleteValue(FRLDRHKEY Key,
672 PCSTR ValueName)
673 {
674 PLIST_ENTRY Ptr;
675 PVALUE Value = NULL;
676
677 if ((ValueName == NULL) || (*ValueName == 0))
678 {
679 /* delete default value */
680 if (Key->Data != NULL)
681 MmFreeMemory(Key->Data);
682 Key->Data = NULL;
683 Key->DataSize = 0;
684 Key->DataType = 0;
685 }
686 else
687 {
688 /* delete non-default value */
689 Ptr = Key->ValueList.Flink;
690 while (Ptr != &Key->ValueList)
691 {
692 Value = CONTAINING_RECORD(Ptr,
693 VALUE,
694 ValueList);
695 if (stricmp(Value->Name, ValueName) == 0)
696 break;
697
698 Ptr = Ptr->Flink;
699 }
700
701 if (Ptr == &Key->ValueList)
702 return(ERROR_INVALID_PARAMETER);
703
704 /* delete value */
705 Key->ValueCount--;
706 if (Value->Name != NULL)
707 MmFreeMemory(Value->Name);
708 Value->Name = NULL;
709 Value->NameSize = 0;
710
711 if (Value->DataSize > sizeof(PUCHAR))
712 {
713 if (Value->Data != NULL)
714 MmFreeMemory(Value->Data);
715 }
716 Value->Data = NULL;
717 Value->DataSize = 0;
718 Value->DataType = 0;
719
720 RemoveEntryList(&Value->ValueList);
721 MmFreeMemory(Value);
722 }
723 return(ERROR_SUCCESS);
724 }
725
726
727 LONG
728 RegEnumValue(FRLDRHKEY Key,
729 ULONG Index,
730 PCHAR ValueName,
731 ULONG* NameSize,
732 ULONG* Type,
733 PUCHAR Data,
734 ULONG* DataSize)
735 {
736 PLIST_ENTRY Ptr;
737 PVALUE Value;
738 ULONG Count = 0;
739
740 if (Key->Data != NULL)
741 {
742 if (Index > 0)
743 {
744 Index--;
745 }
746 else
747 {
748 /* enumerate default value */
749 if (ValueName != NULL)
750 *ValueName = 0;
751 if (Type != NULL)
752 *Type = Key->DataType;
753 if (Data != NULL)
754 {
755 if (Key->DataSize <= sizeof(PUCHAR))
756 {
757 memcpy(Data, &Key->Data, min(Key->DataSize, *DataSize));
758 }
759 else
760 {
761 memcpy(Data, Key->Data, min(Key->DataSize, *DataSize));
762 }
763 }
764 if (DataSize != NULL)
765 *DataSize = min(Key->DataSize, *DataSize);
766
767 return(ERROR_SUCCESS);
768 }
769 }
770
771 Ptr = Key->ValueList.Flink;
772 while (Ptr != &Key->ValueList)
773 {
774 if (Index == Count)
775 break;
776
777 Count++;
778 Ptr = Ptr->Flink;
779 }
780
781 if (Ptr == &Key->ValueList)
782 return(ERROR_NO_MORE_ITEMS);
783
784 Value = CONTAINING_RECORD(Ptr,
785 VALUE,
786 ValueList);
787
788 /* enumerate non-default value */
789 if (ValueName != NULL)
790 memcpy(ValueName, Value->Name, min(Value->NameSize, *NameSize));
791 if (Type != NULL)
792 *Type = Value->DataType;
793
794 if (Data != NULL)
795 {
796 if (Value->DataSize <= sizeof(PUCHAR))
797 {
798 memcpy(Data, &Value->Data, min(Value->DataSize, *DataSize));
799 }
800 else
801 {
802 memcpy(Data, Value->Data, min(Value->DataSize, *DataSize));
803 }
804 }
805
806 if (DataSize != NULL)
807 *DataSize = min(Value->DataSize, *DataSize);
808
809 return(ERROR_SUCCESS);
810 }
811
812
813 ULONG
814 RegGetSubKeyCount (FRLDRHKEY Key)
815 {
816 return Key->SubKeyCount;
817 }
818
819
820 ULONG
821 RegGetValueCount (FRLDRHKEY Key)
822 {
823 if (Key->DataSize != 0)
824 return Key->ValueCount + 1;
825
826 return Key->ValueCount;
827 }
828
829 /* EOF */