ReactOS  0.4.13-dev-257-gfabbd7c
hkcr.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS system libraries
4  * FILE: lib/advapi32/reg/hkcr.c
5  * PURPOSE: Registry functions - HKEY_CLASSES_ROOT abstraction
6  * PROGRAMMER: Jerôme Gardou (jerome.gardou@reactos.org)
7  */
8 
9 #include <advapi32.h>
10 
11 #include <ndk/cmfuncs.h>
12 #include <pseh/pseh2.h>
13 
14 #include "reg.h"
15 
17 
18 static const UNICODE_STRING HKLM_ClassesPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Classes");
19 
20 static
21 LONG
23 {
24  UNICODE_STRING InfoName;
25  PKEY_NAME_INFORMATION NameInformation;
26  ULONG InfoLength;
28 
29  /* Get info length */
30  InfoLength = 0;
31  Status = NtQueryKey(hKey, KeyNameInformation, NULL, 0, &InfoLength);
33  {
34  ERR("NtQueryKey returned unexpected Status: 0x%08x\n", Status);
36  }
37 
38  /* Get it for real */
39  NameInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, InfoLength);
40  if (NameInformation == NULL)
41  {
42  ERR("Failed to allocate %lu bytes", InfoLength);
44  }
45 
46  Status = NtQueryKey(hKey, KeyNameInformation, NameInformation, InfoLength, &InfoLength);
47  if (!NT_SUCCESS(Status))
48  {
49  RtlFreeHeap(RtlGetProcessHeap(), 0, NameInformation);
50  ERR("NtQueryKey failed: 0x%08x\n", Status);
52  }
53 
54  /* Make it a proper UNICODE_STRING */
55  InfoName.Length = NameInformation->NameLength;
56  InfoName.MaximumLength = NameInformation->NameLength;
57  InfoName.Buffer = NameInformation->Name;
58 
60  if (!NT_SUCCESS(Status))
61  {
62  RtlFreeHeap(RtlGetProcessHeap(), 0, NameInformation);
63  ERR("RtlDuplicateUnicodeString failed: 0x%08x\n", Status);
65  }
66 
67  RtlFreeHeap(RtlGetProcessHeap(), 0, NameInformation);
68 
69  return ERROR_SUCCESS;
70 }
71 
72 static
73 LONG
75  _In_ HKEY hKey,
76  _Out_ REGSAM* RegSam)
77 {
79  OBJECT_BASIC_INFORMATION ObjectInfo;
80 
81  Status = NtQueryObject(hKey, ObjectBasicInformation, &ObjectInfo, sizeof(ObjectInfo), NULL);
82  if (!NT_SUCCESS(Status))
83  {
84  ERR("NtQueryObject failed, Status %x08x\n", Status);
86  }
87 
88  *RegSam = ObjectInfo.GrantedAccess;
89  return ERROR_SUCCESS;
90 }
91 
92 /*
93  * Gets a HKLM key from an HKCU key.
94  */
95 static
96 LONG
98  _In_ HKEY hKey,
99  _Out_ HKEY* MachineKey,
100  _In_ BOOL MustCreate)
101 {
104  LONG ErrorCode;
105  REGSAM SamDesired;
106 
107  /* Get the key name */
108  ErrorCode = GetKeyName(hKey, &KeyName);
109  if (ErrorCode != ERROR_SUCCESS)
110  return ErrorCode;
111 
112  /* See if we really need a conversion */
114  {
116  *MachineKey = hKey;
117  return ERROR_SUCCESS;
118  }
119 
120  SubKeyName = KeyName.Buffer + 15; /* 15 == wcslen(L"\\Registry\\User\\") */
121  /* Skip the user token */
122  while (*SubKeyName++ != L'\\')
123  {
124  if (!*SubKeyName)
125  {
126  ERR("Key name %S is invalid!\n", KeyName.Buffer);
127  return ERROR_INTERNAL_ERROR;
128  }
129  }
130 
131  /* Use the same access mask than the original key */
132  ErrorCode = GetKeySam(hKey, &SamDesired);
133  if (ErrorCode != ERROR_SUCCESS)
134  {
136  return ErrorCode;
137  }
138 
139  if (MustCreate)
140  {
143  SubKeyName,
144  0,
145  NULL,
146  0,
147  SamDesired,
148  NULL,
149  MachineKey,
150  NULL);
151  }
152  else
153  {
154  /* Open the key. */
157  SubKeyName,
158  0,
159  SamDesired,
160  MachineKey);
161  }
162 
164 
165  return ErrorCode;
166 }
167 
168 /* Get the HKCU key (if it exists) from an HKCR key */
169 static
170 LONG
172  _In_ HKEY hKey,
173  _Out_ HKEY* PreferredKey)
174 {
177  LONG ErrorCode;
178  REGSAM SamDesired;
179 
180  /* Get the key name */
181  ErrorCode = GetKeyName(hKey, &KeyName);
182  if (ErrorCode != ERROR_SUCCESS)
183  return ErrorCode;
184 
185  /* See if we really need a conversion */
187  {
189  *PreferredKey = hKey;
190  return ERROR_SUCCESS;
191  }
192 
193  /* 18 == wcslen(L"\\Registry\\Machine\\") */
194  SubKeyName = KeyName.Buffer + 18;
195 
196  /* Use the same access mask than the original key */
197  ErrorCode = GetKeySam(hKey, &SamDesired);
198  if (ErrorCode != ERROR_SUCCESS)
199  {
201  return ErrorCode;
202  }
203 
204  /* Open the key. */
207  SubKeyName,
208  0,
209  SamDesired,
210  PreferredKey);
211 
213 
214  return ErrorCode;
215 }
216 
217 /* HKCR version of RegCreateKeyExW. */
218 LONG
219 WINAPI
221  _In_ HKEY hKey,
222  _In_ LPCWSTR lpSubKey,
224  _In_opt_ LPWSTR lpClass,
226  _In_ REGSAM samDesired,
227  _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
228  _Out_ PHKEY phkResult,
229  _Out_opt_ LPDWORD lpdwDisposition)
230 {
231  LONG ErrorCode;
232  HKEY QueriedKey, TestKey;
233 
234  ASSERT(IsHKCRKey(hKey));
235 
236  /* Remove the HKCR flag while we're working */
237  hKey = (HKEY)(((ULONG_PTR)hKey) & ~0x2);
238 
239  ErrorCode = GetPreferredHKCRKey(hKey, &QueriedKey);
240 
242  {
243  /* The current key doesn't exist on HKCU side, so we can only create it in HKLM */
245  hKey,
246  lpSubKey,
247  Reserved,
248  lpClass,
249  dwOptions,
250  samDesired,
251  lpSecurityAttributes,
252  phkResult,
253  lpdwDisposition);
254  if (ErrorCode == ERROR_SUCCESS)
255  MakeHKCRKey(phkResult);
256  return ErrorCode;
257  }
258 
259  if (ErrorCode != ERROR_SUCCESS)
260  {
261  /* Somehow we failed for another reason (maybe deleted key or whatever) */
262  return ErrorCode;
263  }
264 
265  /* See if the subkey already exists in HKCU. */
266  ErrorCode = RegOpenKeyExW(QueriedKey, lpSubKey, 0, READ_CONTROL, &TestKey);
268  {
269  if (ErrorCode == ERROR_SUCCESS)
270  {
271  /* Great. Close the test one and do the real create operation */
272  RegCloseKey(TestKey);
274  QueriedKey,
275  lpSubKey,
276  Reserved,
277  lpClass,
278  dwOptions,
279  samDesired,
280  lpSecurityAttributes,
281  phkResult,
282  lpdwDisposition);
283  if (ErrorCode == ERROR_SUCCESS)
284  MakeHKCRKey(phkResult);
285  }
286  if (QueriedKey != hKey)
287  RegCloseKey(QueriedKey);
288 
289  return ERROR_SUCCESS;
290  }
291 
292  if (QueriedKey != hKey)
293  RegCloseKey(QueriedKey);
294 
295  /* So we must do the create operation in HKLM, creating the missing parent keys if needed. */
296  ErrorCode = GetFallbackHKCRKey(hKey, &QueriedKey, TRUE);
297  if (ErrorCode != ERROR_SUCCESS)
298  return ErrorCode;
299 
300  /* Do the key creation */
302  QueriedKey,
303  lpSubKey,
304  Reserved,
305  lpClass,
306  dwOptions,
307  samDesired,
308  lpSecurityAttributes,
309  phkResult,
310  lpdwDisposition);
311 
312  if (QueriedKey != hKey)
313  RegCloseKey(QueriedKey);
314 
315  if (ErrorCode == ERROR_SUCCESS)
316  MakeHKCRKey(phkResult);
317 
318  return ErrorCode;
319 }
320 
321 /* Same as RegOpenKeyExW, but for HKEY_CLASSES_ROOT subkeys */
322 LONG
323 WINAPI
325  _In_ HKEY hKey,
326  _In_ LPCWSTR lpSubKey,
327  _In_ DWORD ulOptions,
328  _In_ REGSAM samDesired,
329  _In_ PHKEY phkResult)
330 {
331  HKEY QueriedKey;
332  LONG ErrorCode;
333 
334  ASSERT(IsHKCRKey(hKey));
335 
336  /* Remove the HKCR flag while we're working */
337  hKey = (HKEY)(((ULONG_PTR)hKey) & ~0x2);
338 
339  ErrorCode = GetPreferredHKCRKey(hKey, &QueriedKey);
340 
342  {
343  /* The key doesn't exist on HKCU side, no chance for a subkey */
344  ErrorCode = RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult);
345  if (ErrorCode == ERROR_SUCCESS)
346  MakeHKCRKey(phkResult);
347  return ErrorCode;
348  }
349 
350  if (ErrorCode != ERROR_SUCCESS)
351  {
352  /* Somehow we failed for another reason (maybe deleted key or whatever) */
353  return ErrorCode;
354  }
355 
356  /* Try on the HKCU side */
357  ErrorCode = RegOpenKeyExW(QueriedKey, lpSubKey, ulOptions, samDesired, phkResult);
358  if (ErrorCode == ERROR_SUCCESS)
359  MakeHKCRKey(phkResult);
360 
361  /* Close it if we must */
362  if (QueriedKey != hKey)
363  {
364  RegCloseKey(QueriedKey);
365  }
366 
367  /* Anything else than ERROR_FILE_NOT_FOUND means that we found it, even if it is with failures. */
369  return ErrorCode;
370 
371  /* If we're here, we must open from HKLM key. */
372  ErrorCode = GetFallbackHKCRKey(hKey, &QueriedKey, FALSE);
373  if (ErrorCode != ERROR_SUCCESS)
374  {
375  /* Maybe the key doesn't exist in the HKLM view */
376  return ErrorCode;
377  }
378 
379  ErrorCode = RegOpenKeyExW(QueriedKey, lpSubKey, ulOptions, samDesired, phkResult);
380  if (ErrorCode == ERROR_SUCCESS)
381  MakeHKCRKey(phkResult);
382 
383  /* Close it if we must */
384  if (QueriedKey != hKey)
385  {
386  RegCloseKey(QueriedKey);
387  }
388 
389  return ErrorCode;
390 }
391 
392 /* HKCR version of RegDeleteKeyExW */
393 LONG
394 WINAPI
396  _In_ HKEY hKey,
397  _In_ LPCWSTR lpSubKey,
398  _In_ REGSAM RegSam,
400 {
401  HKEY QueriedKey;
402  LONG ErrorCode;
403 
404  ASSERT(IsHKCRKey(hKey));
405 
406  /* Remove the HKCR flag while we're working */
407  hKey = (HKEY)(((ULONG_PTR)hKey) & ~0x2);
408 
409  ErrorCode = GetPreferredHKCRKey(hKey, &QueriedKey);
410 
412  {
413  /* The key doesn't exist on HKCU side, no chance for a subkey */
414  return RegDeleteKeyExW(hKey, lpSubKey, RegSam, Reserved);
415  }
416 
417  if (ErrorCode != ERROR_SUCCESS)
418  {
419  /* Somehow we failed for another reason (maybe deleted key or whatever) */
420  return ErrorCode;
421  }
422 
423  ErrorCode = RegDeleteKeyExW(QueriedKey, lpSubKey, RegSam, Reserved);
424 
425  /* Close it if we must */
426  if (QueriedKey != hKey)
427  {
428  /* The original key is on the machine view */
429  RegCloseKey(QueriedKey);
430  }
431 
432  /* Anything else than ERROR_FILE_NOT_FOUND means that we found it, even if it is with failures. */
434  return ErrorCode;
435 
436  /* If we're here, we must open from HKLM key. */
437  ErrorCode = GetFallbackHKCRKey(hKey, &QueriedKey, FALSE);
438  if (ErrorCode != ERROR_SUCCESS)
439  {
440  /* Maybe the key doesn't exist in the HKLM view */
441  return ErrorCode;
442  }
443 
444  ErrorCode = RegDeleteKeyExW(QueriedKey, lpSubKey, RegSam, Reserved);
445 
446  /* Close it if we must */
447  if (QueriedKey != hKey)
448  {
449  RegCloseKey(QueriedKey);
450  }
451 
452  return ErrorCode;
453 }
454 
455 /* HKCR version of RegQueryValueExW */
456 LONG
457 WINAPI
459  _In_ HKEY hKey,
460  _In_ LPCWSTR Name,
462  _In_ LPDWORD Type,
463  _In_ LPBYTE Data,
465 {
466  HKEY QueriedKey;
467  LONG ErrorCode;
468 
469  ASSERT(IsHKCRKey(hKey));
470 
471  /* Remove the HKCR flag while we're working */
472  hKey = (HKEY)(((ULONG_PTR)hKey) & ~0x2);
473 
474  ErrorCode = GetPreferredHKCRKey(hKey, &QueriedKey);
475 
477  {
478  /* The key doesn't exist on HKCU side, no chance for a value in it */
479  return RegQueryValueExW(hKey, Name, Reserved, Type, Data, Count);
480  }
481 
482  if (ErrorCode != ERROR_SUCCESS)
483  {
484  /* Somehow we failed for another reason (maybe deleted key or whatever) */
485  return ErrorCode;
486  }
487 
489 
490  /* Close it if we must */
491  if (QueriedKey != hKey)
492  {
493  /* The original key is on the machine view */
494  RegCloseKey(QueriedKey);
495  }
496 
497  /* Anything else than ERROR_FILE_NOT_FOUND means that we found it, even if it is with failures. */
499  return ErrorCode;
500 
501  /* If we're here, we must open from HKLM key. */
502  ErrorCode = GetFallbackHKCRKey(hKey, &QueriedKey, FALSE);
503  if (ErrorCode != ERROR_SUCCESS)
504  {
505  /* Maybe the key doesn't exist in the HKLM view */
506  return ErrorCode;
507  }
508 
510 
511  /* Close it if we must */
512  if (QueriedKey != hKey)
513  {
514  RegCloseKey(QueriedKey);
515  }
516 
517  return ErrorCode;
518 }
519 
520 /* HKCR version of RegSetValueExW */
521 LONG
522 WINAPI
524  _In_ HKEY hKey,
525  _In_ LPCWSTR Name,
527  _In_ DWORD Type,
528  _In_ CONST BYTE* Data,
530 {
531  HKEY QueriedKey;
532  LONG ErrorCode;
533 
534  ASSERT(IsHKCRKey(hKey));
535 
536  /* Remove the HKCR flag while we're working */
537  hKey = (HKEY)(((ULONG_PTR)hKey) & ~0x2);
538 
539  ErrorCode = GetPreferredHKCRKey(hKey, &QueriedKey);
540 
542  {
543  /* The key doesn't exist on HKCU side, no chance to put a value in it */
544  return RegSetValueExW(hKey, Name, Reserved, Type, Data, DataSize);
545  }
546 
547  if (ErrorCode != ERROR_SUCCESS)
548  {
549  /* Somehow we failed for another reason (maybe deleted key or whatever) */
550  return ErrorCode;
551  }
552 
553  /* Check if the value already exists in the preferred key */
554  ErrorCode = RegQueryValueExW(QueriedKey, Name, NULL, NULL, NULL, NULL);
556  {
557  if (ErrorCode == ERROR_SUCCESS)
558  {
559  /* Yes, so we have the right to modify it */
561  }
562  if (QueriedKey != hKey)
563  RegCloseKey(QueriedKey);
564  return ErrorCode;
565  }
566  if (QueriedKey != hKey)
567  RegCloseKey(QueriedKey);
568 
569  /* So we must set the value in the HKLM version */
570  ErrorCode = GetPreferredHKCRKey(hKey, &QueriedKey);
572  {
573  /* No choice: put this in HKCU */
574  return RegSetValueExW(hKey, Name, Reserved, Type, Data, DataSize);
575  }
576  else if (ErrorCode != ERROR_SUCCESS)
577  {
578  return ErrorCode;
579  }
580 
582 
583  if (QueriedKey != hKey)
584  RegCloseKey(QueriedKey);
585 
586  return ErrorCode;
587 }
588 
589 /* HKCR version of RegEnumKeyExW */
590 LONG
591 WINAPI
593  _In_ HKEY hKey,
594  _In_ DWORD dwIndex,
596  _Inout_ LPDWORD lpcbName,
597  _Reserved_ LPDWORD lpReserved,
598  _Out_opt_ LPWSTR lpClass,
599  _Inout_opt_ LPDWORD lpcbClass,
600  _Out_opt_ PFILETIME lpftLastWriteTime)
601 {
602  HKEY PreferredKey, FallbackKey;
603  DWORD NumPreferredSubKeys;
604  DWORD MaxFallbackSubKeyLen;
605  DWORD FallbackIndex;
606  WCHAR* FallbackSubKeyName = NULL;
607  LONG ErrorCode;
608 
609  ASSERT(IsHKCRKey(hKey));
610 
611  /* Remove the HKCR flag while we're working */
612  hKey = (HKEY)(((ULONG_PTR)hKey) & ~0x2);
613 
614  /* Get the preferred key */
615  ErrorCode = GetPreferredHKCRKey(hKey, &PreferredKey);
616  if (ErrorCode != ERROR_SUCCESS)
617  {
619  {
620  /* Only the HKLM key exists */
621  return RegEnumKeyExW(
622  hKey,
623  dwIndex,
624  lpName,
625  lpcbName,
626  lpReserved,
627  lpClass,
628  lpcbClass,
629  lpftLastWriteTime);
630  }
631  return ErrorCode;
632  }
633 
634  /* Get the fallback key */
635  ErrorCode = GetFallbackHKCRKey(hKey, &FallbackKey, FALSE);
636  if (ErrorCode != ERROR_SUCCESS)
637  {
638  if (PreferredKey != hKey)
639  RegCloseKey(PreferredKey);
641  {
642  /* Only the HKCU key exists */
643  return RegEnumKeyExW(
644  hKey,
645  dwIndex,
646  lpName,
647  lpcbName,
648  lpReserved,
649  lpClass,
650  lpcbClass,
651  lpftLastWriteTime);
652  }
653  return ErrorCode;
654  }
655 
656  /* Get some info on the HKCU side */
658  PreferredKey,
659  NULL,
660  NULL,
661  NULL,
662  &NumPreferredSubKeys,
663  NULL,
664  NULL,
665  NULL,
666  NULL,
667  NULL,
668  NULL,
669  NULL);
670  if (ErrorCode != ERROR_SUCCESS)
671  goto Exit;
672 
673  if (dwIndex < NumPreferredSubKeys)
674  {
675  /* HKCU side takes precedence */
677  PreferredKey,
678  dwIndex,
679  lpName,
680  lpcbName,
681  lpReserved,
682  lpClass,
683  lpcbClass,
684  lpftLastWriteTime);
685  goto Exit;
686  }
687 
688  /* Here it gets tricky. We must enumerate the values from the HKLM side,
689  * without reporting those which are present on the HKCU side */
690 
691  /* Squash out the indices from HKCU */
692  dwIndex -= NumPreferredSubKeys;
693 
694  /* Get some info */
696  FallbackKey,
697  NULL,
698  NULL,
699  NULL,
700  NULL,
701  &MaxFallbackSubKeyLen,
702  NULL,
703  NULL,
704  NULL,
705  NULL,
706  NULL,
707  NULL);
708  if (ErrorCode != ERROR_SUCCESS)
709  {
710  ERR("Could not query info of key %p (Err: %d)\n", FallbackKey, ErrorCode);
711  goto Exit;
712  }
713 
714  MaxFallbackSubKeyLen++;
715  TRACE("Maxfallbacksubkeylen: %d\n", MaxFallbackSubKeyLen);
716 
717  /* Allocate our buffer */
718  FallbackSubKeyName = RtlAllocateHeap(
719  RtlGetProcessHeap(), 0, MaxFallbackSubKeyLen * sizeof(WCHAR));
720  if (!FallbackSubKeyName)
721  {
723  goto Exit;
724  }
725 
726  /* We must begin at the very first subkey of the fallback key,
727  * and then see if we meet keys that already are in the preferred key.
728  * In that case, we must bump dwIndex, as otherwise we would enumerate a key we already
729  * saw in a previous call.
730  */
731  FallbackIndex = 0;
732  while (TRUE)
733  {
734  HKEY PreferredSubKey;
735  DWORD FallbackSubkeyLen = MaxFallbackSubKeyLen;
736 
737  /* Try enumerating */
739  FallbackKey,
740  FallbackIndex,
741  FallbackSubKeyName,
742  &FallbackSubkeyLen,
743  NULL,
744  NULL,
745  NULL,
746  NULL);
747  if (ErrorCode != ERROR_SUCCESS)
748  {
750  ERR("Returning %d.\n", ErrorCode);
751  goto Exit;
752  }
753  FallbackSubKeyName[FallbackSubkeyLen] = L'\0';
754 
755  /* See if there is such a value on HKCU side */
757  PreferredKey,
758  FallbackSubKeyName,
759  0,
760  READ_CONTROL,
761  &PreferredSubKey);
762 
763  if (ErrorCode == ERROR_SUCCESS)
764  {
765  RegCloseKey(PreferredSubKey);
766  /* So we already enumerated it on HKCU side. */
767  dwIndex++;
768  }
769  else if (ErrorCode != ERROR_FILE_NOT_FOUND)
770  {
771  ERR("Got error %d while querying for %s on HKCU side.\n", ErrorCode, FallbackSubKeyName);
772  goto Exit;
773  }
774 
775  /* See if we caught up */
776  if (FallbackIndex == dwIndex)
777  break;
778 
779  FallbackIndex++;
780  }
781 
782  /* We can finally enumerate on the fallback side */
784  FallbackKey,
785  dwIndex,
786  lpName,
787  lpcbName,
788  lpReserved,
789  lpClass,
790  lpcbClass,
791  lpftLastWriteTime);
792 
793 Exit:
794  if (PreferredKey != hKey)
795  RegCloseKey(PreferredKey);
796  if (FallbackKey != hKey)
797  RegCloseKey(FallbackKey);
798  if (FallbackSubKeyName)
799  RtlFreeHeap(RtlGetProcessHeap(), 0, FallbackSubKeyName);
800 
801  return ErrorCode;
802 }
803 
804 /* HKCR version of RegEnumValueW */
805 LONG
806 WINAPI
808  _In_ HKEY hKey,
809  _In_ DWORD dwIndex,
811  _Inout_ PDWORD lpcbName,
812  _Reserved_ PDWORD lpReserved,
813  _Out_opt_ PDWORD lpdwType,
814  _Out_opt_ LPBYTE lpData,
815  _Inout_opt_ PDWORD lpcbData)
816 {
817  HKEY PreferredKey, FallbackKey;
818  DWORD NumPreferredValues;
819  DWORD MaxFallbackValueNameLen;
820  DWORD FallbackIndex;
821  WCHAR* FallbackValueName = NULL;
822  LONG ErrorCode;
823 
824  ASSERT(IsHKCRKey(hKey));
825 
826  /* Remove the HKCR flag while we're working */
827  hKey = (HKEY)(((ULONG_PTR)hKey) & ~0x2);
828 
829  /* Get the preferred key */
830  ErrorCode = GetPreferredHKCRKey(hKey, &PreferredKey);
831  if (ErrorCode != ERROR_SUCCESS)
832  {
834  {
835  /* Only the HKLM key exists */
836  return RegEnumValueW(
837  hKey,
838  dwIndex,
839  lpName,
840  lpcbName,
841  lpReserved,
842  lpdwType,
843  lpData,
844  lpcbData);
845  }
846  return ErrorCode;
847  }
848 
849  /* Get the fallback key */
850  ErrorCode = GetFallbackHKCRKey(hKey, &FallbackKey, FALSE);
851  if (ErrorCode != ERROR_SUCCESS)
852  {
853  if (PreferredKey != hKey)
854  RegCloseKey(PreferredKey);
856  {
857  /* Only the HKCU key exists */
858  return RegEnumValueW(
859  hKey,
860  dwIndex,
861  lpName,
862  lpcbName,
863  lpReserved,
864  lpdwType,
865  lpData,
866  lpcbData);
867  }
868  return ErrorCode;
869  }
870 
871  /* Get some info on the HKCU side */
873  PreferredKey,
874  NULL,
875  NULL,
876  NULL,
877  NULL,
878  NULL,
879  NULL,
880  &NumPreferredValues,
881  NULL,
882  NULL,
883  NULL,
884  NULL);
885  if (ErrorCode != ERROR_SUCCESS)
886  goto Exit;
887 
888  if (dwIndex < NumPreferredValues)
889  {
890  /* HKCU side takes precedence */
891  return RegEnumValueW(
892  PreferredKey,
893  dwIndex,
894  lpName,
895  lpcbName,
896  lpReserved,
897  lpdwType,
898  lpData,
899  lpcbData);
900  goto Exit;
901  }
902 
903  /* Here it gets tricky. We must enumerate the values from the HKLM side,
904  * without reporting those which are present on the HKCU side */
905 
906  /* Squash out the indices from HKCU */
907  dwIndex -= NumPreferredValues;
908 
909  /* Get some info */
911  FallbackKey,
912  NULL,
913  NULL,
914  NULL,
915  NULL,
916  NULL,
917  NULL,
918  NULL,
919  &MaxFallbackValueNameLen,
920  NULL,
921  NULL,
922  NULL);
923  if (ErrorCode != ERROR_SUCCESS)
924  {
925  ERR("Could not query info of key %p (Err: %d)\n", FallbackKey, ErrorCode);
926  goto Exit;
927  }
928 
929  MaxFallbackValueNameLen++;
930  TRACE("Maxfallbacksubkeylen: %d\n", MaxFallbackValueNameLen);
931 
932  /* Allocate our buffer */
933  FallbackValueName = RtlAllocateHeap(
934  RtlGetProcessHeap(), 0, MaxFallbackValueNameLen * sizeof(WCHAR));
935  if (!FallbackValueName)
936  {
938  goto Exit;
939  }
940 
941  /* We must begin at the very first subkey of the fallback key,
942  * and then see if we meet keys that already are in the preferred key.
943  * In that case, we must bump dwIndex, as otherwise we would enumerate a key we already
944  * saw in a previous call.
945  */
946  FallbackIndex = 0;
947  while (TRUE)
948  {
949  DWORD FallbackValueNameLen = MaxFallbackValueNameLen;
950 
951  /* Try enumerating */
953  FallbackKey,
954  FallbackIndex,
955  FallbackValueName,
956  &FallbackValueNameLen,
957  NULL,
958  NULL,
959  NULL,
960  NULL);
961  if (ErrorCode != ERROR_SUCCESS)
962  {
963  /* Most likely ERROR_NO_MORE_ITEMS */
964  ERR("Returning %d.\n", ErrorCode);
965  goto Exit;
966  }
967  FallbackValueName[FallbackValueNameLen] = L'\0';
968 
969  /* See if there is such a value on HKCU side */
971  PreferredKey,
972  FallbackValueName,
973  NULL,
974  NULL,
975  NULL,
976  NULL);
977 
978  if (ErrorCode == ERROR_SUCCESS)
979  {
980  /* So we already enumerated it on HKCU side. */
981  dwIndex++;
982  }
983  else if (ErrorCode != ERROR_FILE_NOT_FOUND)
984  {
985  ERR("Got error %d while querying for %s on HKCU side.\n", ErrorCode, FallbackValueName);
986  goto Exit;
987  }
988 
989  /* See if we caught up */
990  if (FallbackIndex == dwIndex)
991  break;
992 
993  FallbackIndex++;
994  }
995 
996  /* We can finally enumerate on the fallback side */
998  FallbackKey,
999  dwIndex,
1000  lpName,
1001  lpcbName,
1002  lpReserved,
1003  lpdwType,
1004  lpData,
1005  lpcbData);
1006 
1007 Exit:
1008  if (PreferredKey != hKey)
1009  RegCloseKey(PreferredKey);
1010  if (FallbackKey != hKey)
1011  RegCloseKey(FallbackKey);
1012  if (FallbackValueName)
1013  RtlFreeHeap(RtlGetProcessHeap(), 0, FallbackValueName);
1014 
1015  return ErrorCode;
1016 }
DWORD dwOptions
Definition: solitaire.cpp:23
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING KeyName
Definition: ndis.h:4711
#define TRUE
Definition: types.h:120
WINE_DEFAULT_DEBUG_CHANNEL(reg)
_In_ NDIS_ERROR_CODE ErrorCode
Definition: ndis.h:4436
Type
Definition: Type.h:6
LONG WINAPI SetHKCRValue(_In_ HKEY hKey, _In_ LPCWSTR Name, _In_ DWORD Reserved, _In_ DWORD Type, _In_ CONST BYTE *Data, _In_ DWORD DataSize)
Definition: hkcr.c:523
#define ERROR_SUCCESS
Definition: deptool.c:10
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ PNDIS_STRING SubKeyName
Definition: ndis.h:4723
#define ERROR_INTERNAL_ERROR
Definition: winerror.h:840
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:95
USHORT MaximumLength
Definition: env_spec_w32.h:370
FORCEINLINE void MakeHKCRKey(_Inout_ HKEY *hKey)
Definition: reg.h:20
#define HKEY_CURRENT_USER
Definition: winreg.h:11
LONG WINAPI EnumHKCRKey(_In_ HKEY hKey, _In_ DWORD dwIndex, _Out_ LPWSTR lpName, _Inout_ LPDWORD lpcbName, _Reserved_ LPDWORD lpReserved, _Out_opt_ LPWSTR lpClass, _Inout_opt_ LPDWORD lpcbClass, _Out_opt_ PFILETIME lpftLastWriteTime)
Definition: hkcr.c:592
LONG NTSTATUS
Definition: precomp.h:26
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:603
_In_ LPCSTR lpName
Definition: winbase.h:2729
static LONG GetPreferredHKCRKey(_In_ HKEY hKey, _Out_ HKEY *PreferredKey)
Definition: hkcr.c:171
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
static LONG GetKeyName(HKEY hKey, PUNICODE_STRING KeyName)
Definition: hkcr.c:22
NTSTATUS NTAPI NtQueryKey(IN HANDLE KeyHandle, IN KEY_INFORMATION_CLASS KeyInformationClass, OUT PVOID KeyInformation, IN ULONG Length, OUT PULONG ResultLength)
Definition: ntapi.c:632
LONG WINAPI OpenHKCRKey(_In_ HKEY hKey, _In_ LPCWSTR lpSubKey, _In_ DWORD ulOptions, _In_ REGSAM samDesired, _In_ PHKEY phkResult)
Definition: hkcr.c:324
static LONG GetKeySam(_In_ HKEY hKey, _Out_ REGSAM *RegSam)
Definition: hkcr.c:74
#define _In_opt_
Definition: no_sal2.h:213
LONG WINAPI RegCreateKeyExW(_In_ HKEY hKey, _In_ LPCWSTR lpSubKey, _In_ DWORD Reserved, _In_opt_ LPWSTR lpClass, _In_ DWORD dwOptions, _In_ REGSAM samDesired, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _Out_ PHKEY phkResult, _Out_opt_ LPDWORD lpdwDisposition)
Definition: reg.c:1094
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:64
LONG WINAPI RegDeleteKeyExW(_In_ HKEY hKey, _In_ LPCWSTR lpSubKey, _In_ REGSAM samDesired, _In_ DWORD Reserved)
Definition: reg.c:1287
uint32_t ULONG_PTR
Definition: typedefs.h:63
LONG WINAPI QueryHKCRValue(_In_ HKEY hKey, _In_ LPCWSTR Name, _In_ LPDWORD Reserved, _In_ LPDWORD Type, _In_ LPBYTE Data, _In_ LPDWORD Count)
Definition: hkcr.c:458
LONG WINAPI DeleteHKCRKey(_In_ HKEY hKey, _In_ LPCWSTR lpSubKey, _In_ REGSAM RegSam, _In_ DWORD Reserved)
Definition: hkcr.c:395
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
unsigned char * LPBYTE
Definition: typedefs.h:52
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
LONG WINAPI EnumHKCRValue(_In_ HKEY hKey, _In_ DWORD dwIndex, _Out_ LPWSTR lpName, _Inout_ PDWORD lpcbName, _Reserved_ PDWORD lpReserved, _Out_opt_ PDWORD lpdwType, _Out_opt_ LPBYTE lpData, _Inout_opt_ PDWORD lpcbData)
Definition: hkcr.c:807
LONG WINAPI RegEnumValueW(_In_ HKEY hKey, _In_ DWORD index, _Out_ LPWSTR value, _Inout_ PDWORD val_count, _Reserved_ PDWORD reserved, _Out_opt_ PDWORD type, _Out_opt_ LPBYTE data, _Inout_opt_ PDWORD count)
Definition: reg.c:2867
smooth NULL
Definition: ftsmooth.c:416
#define _Out_
Definition: no_sal2.h:323
_Reserved_ PVOID Reserved
Definition: winddi.h:3974
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:585
LONG WINAPI RegSetValueExW(_In_ HKEY hKey, _In_ LPCWSTR lpValueName, _In_ DWORD Reserved, _In_ DWORD dwType, _In_ CONST BYTE *lpData, _In_ DWORD cbData)
Definition: reg.c:4917
#define _Out_opt_
Definition: no_sal2.h:339
#define TRACE(s)
Definition: solgame.cpp:4
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4134
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
NTSTATUS NtQueryObject(IN HANDLE Handle, IN OBJECT_INFO_CLASS ObjectInformationClass, OUT PVOID ObjectInformation, IN ULONG ObjectInformationLength, OUT PULONG ReturnLength)
static void Exit(void)
Definition: sock.c:1331
FORCEINLINE BOOL IsHKCRKey(_In_ HKEY hKey)
Definition: reg.h:13
#define WINAPI
Definition: msvc.h:8
unsigned long DWORD
Definition: ntddk_ex.h:95
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define _Inout_
Definition: no_sal2.h:244
#define RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
Definition: green.h:15
LONG WINAPI RegQueryInfoKeyW(HKEY hKey, LPWSTR lpClass, LPDWORD lpcClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcMaxSubKeyLen, LPDWORD lpcMaxClassLen, LPDWORD lpcValues, LPDWORD lpcMaxValueNameLen, LPDWORD lpcMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime)
Definition: reg.c:3704
#define READ_CONTROL
Definition: nt_native.h:58
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define _Reserved_
Definition: no_sal2.h:573
NTSYSAPI NTSTATUS WINAPI RtlDuplicateUnicodeString(int, const UNICODE_STRING *, UNICODE_STRING *)
static const WCHAR L[]
Definition: oid.c:1250
unsigned char BYTE
Definition: mem.h:68
Status
Definition: gdiplustypes.h:24
NTSYSAPI ULONG WINAPI RtlNtStatusToDosError(NTSTATUS)
#define ERR(fmt,...)
Definition: debug.h:109
#define _In_
Definition: no_sal2.h:204
ACCESS_MASK GrantedAccess
Definition: winternl.h:1251
static LONG GetFallbackHKCRKey(_In_ HKEY hKey, _Out_ HKEY *MachineKey, _In_ BOOL MustCreate)
Definition: hkcr.c:97
ACCESS_MASK REGSAM
Definition: winreg.h:69
NTSYSAPI BOOLEAN NTAPI RtlPrefixUnicodeString(IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInSensitive)
static int reg
Definition: i386-dis.c:1275
DWORD * PDWORD
Definition: pedump.c:68
uint32_t * LPDWORD
Definition: typedefs.h:57
HANDLE HKEY
Definition: registry.h:24
unsigned int ULONG
Definition: retypes.h:1
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3381
LONG WINAPI RegEnumKeyExW(_In_ HKEY hKey, _In_ DWORD dwIndex, _Out_ LPWSTR lpName, _Inout_ LPDWORD lpcbName, _Reserved_ LPDWORD lpReserved, _Out_opt_ LPWSTR lpClass, _Inout_opt_ LPDWORD lpcbClass, _Out_opt_ PFILETIME lpftLastWriteTime)
Definition: reg.c:2541
WCHAR * LPWSTR
Definition: xmlstorage.h:184
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4751
#define CONST
Definition: pedump.c:81
#define RegCreateKeyEx
Definition: winreg.h:501
#define _Inout_opt_
Definition: no_sal2.h:258
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
static const UNICODE_STRING HKLM_ClassesPath
Definition: hkcr.c:18
LONG WINAPI CreateHKCRKey(_In_ HKEY hKey, _In_ LPCWSTR lpSubKey, _In_ DWORD Reserved, _In_opt_ LPWSTR lpClass, _In_ DWORD dwOptions, _In_ REGSAM samDesired, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _Out_ PHKEY phkResult, _Out_opt_ LPDWORD lpdwDisposition)
Definition: hkcr.c:220