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