ucrtbase: Add support for natural string widths.
[wine.git] / dlls / advapi32 / registry.c
blob4b3d852048e36b90e21981f7699cd10e08dfcfe2
1 /*
2 * Registry management
4 * Copyright (C) 1999 Alexandre Julliard
6 * Based on misc/registry.c code
7 * Copyright (C) 1996 Marcus Meissner
8 * Copyright (C) 1998 Matthew Becker
9 * Copyright (C) 1999 Sylvain St-Germain
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
32 #include "ntstatus.h"
33 #define WIN32_NO_STATUS
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winreg.h"
37 #include "winerror.h"
38 #include "winternl.h"
39 #include "winuser.h"
40 #include "sddl.h"
41 #include "advapi32_misc.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(reg);
48 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
49 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
51 static const WCHAR name_CLASSES_ROOT[] =
52 {'\\','R','e','g','i','s','t','r','y','\\',
53 'M','a','c','h','i','n','e','\\',
54 'S','o','f','t','w','a','r','e','\\',
55 'C','l','a','s','s','e','s',0};
56 static const WCHAR name_LOCAL_MACHINE[] =
57 {'\\','R','e','g','i','s','t','r','y','\\',
58 'M','a','c','h','i','n','e',0};
59 static const WCHAR name_USERS[] =
60 {'\\','R','e','g','i','s','t','r','y','\\',
61 'U','s','e','r',0};
62 static const WCHAR name_PERFORMANCE_DATA[] =
63 {'\\','R','e','g','i','s','t','r','y','\\',
64 'P','e','r','f','D','a','t','a',0};
65 static const WCHAR name_CURRENT_CONFIG[] =
66 {'\\','R','e','g','i','s','t','r','y','\\',
67 'M','a','c','h','i','n','e','\\',
68 'S','y','s','t','e','m','\\',
69 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
70 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
71 'C','u','r','r','e','n','t',0};
72 static const WCHAR name_DYN_DATA[] =
73 {'\\','R','e','g','i','s','t','r','y','\\',
74 'D','y','n','D','a','t','a',0};
76 static const WCHAR * const root_key_names[] =
78 name_CLASSES_ROOT,
79 NULL, /* HKEY_CURRENT_USER is determined dynamically */
80 name_LOCAL_MACHINE,
81 name_USERS,
82 name_PERFORMANCE_DATA,
83 name_CURRENT_CONFIG,
84 name_DYN_DATA
87 #define NB_SPECIAL_ROOT_KEYS (sizeof(root_key_names)/sizeof(root_key_names[0]))
89 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
90 static BOOL hkcu_cache_disabled;
92 static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
94 /* check if value type needs string conversion (Ansi<->Unicode) */
95 static inline BOOL is_string( DWORD type )
97 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
100 /* check if current version is NT or Win95 */
101 static inline BOOL is_version_nt(void)
103 return !(GetVersion() & 0x80000000);
106 static BOOL is_wow6432node( const UNICODE_STRING *name )
108 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e'};
110 return (name->Length == sizeof(wow6432nodeW) &&
111 !memicmpW( name->Buffer, wow6432nodeW, sizeof(wow6432nodeW)/sizeof(WCHAR) ));
114 /* open the Wow6432Node subkey of the specified key */
115 static HANDLE open_wow6432node( HANDLE key )
117 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
118 OBJECT_ATTRIBUTES attr;
119 UNICODE_STRING nameW;
120 HANDLE ret;
122 attr.Length = sizeof(attr);
123 attr.RootDirectory = key;
124 attr.ObjectName = &nameW;
125 attr.Attributes = 0;
126 attr.SecurityDescriptor = NULL;
127 attr.SecurityQualityOfService = NULL;
128 RtlInitUnicodeString( &nameW, wow6432nodeW );
129 if (NtOpenKey( &ret, MAXIMUM_ALLOWED, &attr )) ret = 0;
130 return ret;
133 /* wrapper for NtCreateKey that creates the key recursively if necessary */
134 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
135 const UNICODE_STRING *class, ULONG options, PULONG dispos )
137 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
138 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
139 HANDLE subkey, root = attr->RootDirectory;
141 if (!force_wow32) status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos );
143 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
145 static const WCHAR registry_root[] = {'\\','R','e','g','i','s','t','r','y','\\'};
146 WCHAR *buffer = attr->ObjectName->Buffer;
147 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
148 UNICODE_STRING str;
150 /* don't try to create registry root */
151 if (!attr->RootDirectory && len > sizeof(registry_root)/sizeof(WCHAR) &&
152 !memicmpW( buffer, registry_root, sizeof(registry_root)/sizeof(WCHAR)))
153 i += sizeof(registry_root)/sizeof(WCHAR);
155 while (i < len && buffer[i] != '\\') i++;
156 if (i == len && !force_wow32) return status;
158 attrs = attr->Attributes;
159 attr->ObjectName = &str;
161 for (;;)
163 str.Buffer = buffer + pos;
164 str.Length = (i - pos) * sizeof(WCHAR);
165 if (force_wow32 && pos)
167 if (is_wow6432node( &str )) force_wow32 = FALSE;
168 else if ((subkey = open_wow6432node( attr->RootDirectory )))
170 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
171 attr->RootDirectory = subkey;
172 force_wow32 = FALSE;
175 if (i == len)
177 attr->Attributes = attrs;
178 status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos );
180 else
182 attr->Attributes = attrs & ~OBJ_OPENLINK;
183 status = NtCreateKey( &subkey, access, attr, 0, class,
184 options & ~REG_OPTION_CREATE_LINK, dispos );
186 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
187 if (status) return status;
188 if (i == len) break;
189 attr->RootDirectory = subkey;
190 while (i < len && buffer[i] == '\\') i++;
191 pos = i;
192 while (i < len && buffer[i] != '\\') i++;
195 attr->RootDirectory = subkey;
196 if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory )))
198 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
199 attr->RootDirectory = subkey;
201 *retkey = attr->RootDirectory;
202 return status;
205 /* wrapper for NtOpenKey to handle Wow6432 nodes */
206 static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
208 NTSTATUS status;
209 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
210 HANDLE subkey, root = attr->RootDirectory;
211 WCHAR *buffer = attr->ObjectName->Buffer;
212 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
213 UNICODE_STRING str;
215 if (!force_wow32) return NtOpenKey( (HANDLE *)retkey, access, attr );
217 if (len && buffer[0] == '\\') return STATUS_OBJECT_PATH_INVALID;
218 while (i < len && buffer[i] != '\\') i++;
219 attrs = attr->Attributes;
220 attr->ObjectName = &str;
222 for (;;)
224 str.Buffer = buffer + pos;
225 str.Length = (i - pos) * sizeof(WCHAR);
226 if (force_wow32 && pos)
228 if (is_wow6432node( &str )) force_wow32 = FALSE;
229 else if ((subkey = open_wow6432node( attr->RootDirectory )))
231 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
232 attr->RootDirectory = subkey;
233 force_wow32 = FALSE;
236 if (i == len)
238 attr->Attributes = attrs;
239 status = NtOpenKey( &subkey, access, attr );
241 else
243 attr->Attributes = attrs & ~OBJ_OPENLINK;
244 status = NtOpenKey( &subkey, access, attr );
246 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
247 if (status) return status;
248 attr->RootDirectory = subkey;
249 if (i == len) break;
250 while (i < len && buffer[i] == '\\') i++;
251 pos = i;
252 while (i < len && buffer[i] != '\\') i++;
254 if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory )))
256 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
257 attr->RootDirectory = subkey;
259 *retkey = attr->RootDirectory;
260 return status;
263 /* create one of the HKEY_* special root keys */
264 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
266 HKEY ret = 0;
267 int idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
269 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CURRENT_USER))
271 if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
272 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
274 /* don't cache the key in the table if caching is disabled */
275 if (hkcu_cache_disabled)
276 return hkey;
278 else
280 OBJECT_ATTRIBUTES attr;
281 UNICODE_STRING name;
283 attr.Length = sizeof(attr);
284 attr.RootDirectory = 0;
285 attr.ObjectName = &name;
286 attr.Attributes = 0;
287 attr.SecurityDescriptor = NULL;
288 attr.SecurityQualityOfService = NULL;
289 RtlInitUnicodeString( &name, root_key_names[idx] );
290 if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0;
291 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
294 if (!(access & (KEY_WOW64_64KEY | KEY_WOW64_32KEY)))
296 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
297 ret = hkey;
298 else
299 NtClose( hkey ); /* somebody beat us to it */
301 else
302 ret = hkey;
303 return ret;
306 /* map the hkey from special root to normal key if necessary */
307 static inline HKEY get_special_root_hkey( HKEY hkey, REGSAM access )
309 HKEY ret = hkey;
311 if ((HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST))
312 && (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
314 REGSAM mask = 0;
316 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT))
317 mask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
319 if ((access & mask) ||
320 !(ret = special_root_keys[HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)]))
321 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED | (access & mask) );
323 return ret;
327 /******************************************************************************
328 * RegOverridePredefKey [ADVAPI32.@]
330 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
332 HKEY old_key;
333 int idx;
335 TRACE("(%p %p)\n", hkey, override);
337 if ((HandleToUlong(hkey) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST))
338 || (HandleToUlong(hkey) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
339 return ERROR_INVALID_PARAMETER;
340 idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
342 if (override)
344 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
345 GetCurrentProcess(), (HANDLE *)&override,
346 0, 0, DUPLICATE_SAME_ACCESS );
347 if (status) return RtlNtStatusToDosError( status );
350 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
351 if (old_key) NtClose( old_key );
352 return ERROR_SUCCESS;
356 /******************************************************************************
357 * RegCreateKeyExW [ADVAPI32.@]
359 * See RegCreateKeyExA.
361 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
362 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
363 PHKEY retkey, LPDWORD dispos )
365 OBJECT_ATTRIBUTES attr;
366 UNICODE_STRING nameW, classW;
368 if (reserved) return ERROR_INVALID_PARAMETER;
369 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
371 attr.Length = sizeof(attr);
372 attr.RootDirectory = hkey;
373 attr.ObjectName = &nameW;
374 attr.Attributes = 0;
375 attr.SecurityDescriptor = NULL;
376 attr.SecurityQualityOfService = NULL;
377 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
378 RtlInitUnicodeString( &nameW, name );
379 RtlInitUnicodeString( &classW, class );
381 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
385 /******************************************************************************
386 * RegCreateKeyExA [ADVAPI32.@]
388 * Open a registry key, creating it if it doesn't exist.
390 * PARAMS
391 * hkey [I] Handle of the parent registry key
392 * name [I] Name of the new key to open or create
393 * reserved [I] Reserved, pass 0
394 * class [I] The object type of the new key
395 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
396 * access [I] Access level desired
397 * sa [I] Security attributes for the key
398 * retkey [O] Destination for the resulting handle
399 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
401 * RETURNS
402 * Success: ERROR_SUCCESS.
403 * Failure: A standard Win32 error code. retkey remains untouched.
405 * FIXME
406 * MAXIMUM_ALLOWED in access mask not supported by server
408 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
409 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
410 PHKEY retkey, LPDWORD dispos )
412 OBJECT_ATTRIBUTES attr;
413 UNICODE_STRING classW;
414 ANSI_STRING nameA, classA;
415 NTSTATUS status;
417 if (reserved) return ERROR_INVALID_PARAMETER;
418 if (!is_version_nt())
420 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
421 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
423 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
425 attr.Length = sizeof(attr);
426 attr.RootDirectory = hkey;
427 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
428 attr.Attributes = 0;
429 attr.SecurityDescriptor = NULL;
430 attr.SecurityQualityOfService = NULL;
431 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
432 RtlInitAnsiString( &nameA, name );
433 RtlInitAnsiString( &classA, class );
435 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
436 &nameA, FALSE )))
438 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
440 status = create_key( retkey, access, &attr, &classW, options, dispos );
441 RtlFreeUnicodeString( &classW );
444 return RtlNtStatusToDosError( status );
448 /******************************************************************************
449 * RegCreateKeyW [ADVAPI32.@]
451 * Creates the specified reg key.
453 * PARAMS
454 * hKey [I] Handle to an open key.
455 * lpSubKey [I] Name of a key that will be opened or created.
456 * phkResult [O] Receives a handle to the opened or created key.
458 * RETURNS
459 * Success: ERROR_SUCCESS
460 * Failure: nonzero error code defined in Winerror.h
462 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
464 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
465 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
466 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
467 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
471 /******************************************************************************
472 * RegCreateKeyA [ADVAPI32.@]
474 * See RegCreateKeyW.
476 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
478 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
479 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
483 /******************************************************************************
484 * RegCreateKeyTransactedW [ADVAPI32.@]
486 LSTATUS WINAPI RegCreateKeyTransactedW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
487 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
488 PHKEY retkey, LPDWORD dispos, HANDLE transaction, PVOID reserved2 )
490 FIXME( "(%p,%s,%u,%s,%u,%u,%p,%p,%p,%p,%p): stub\n", hkey, debugstr_w(name), reserved,
491 debugstr_w(class), options, access, sa, retkey, dispos, transaction, reserved2 );
492 return ERROR_CALL_NOT_IMPLEMENTED;
496 /******************************************************************************
497 * RegCreateKeyTransactedA [ADVAPI32.@]
499 LSTATUS WINAPI RegCreateKeyTransactedA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
500 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
501 PHKEY retkey, LPDWORD dispos, HANDLE transaction, PVOID reserved2 )
503 FIXME( "(%p,%s,%u,%s,%u,%u,%p,%p,%p,%p,%p): stub\n", hkey, debugstr_a(name), reserved,
504 debugstr_a(class), options, access, sa, retkey, dispos, transaction, reserved2 );
505 return ERROR_CALL_NOT_IMPLEMENTED;
509 /******************************************************************************
510 * RegOpenKeyExW [ADVAPI32.@]
512 * See RegOpenKeyExA.
514 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
516 OBJECT_ATTRIBUTES attr;
517 UNICODE_STRING nameW;
519 if (retkey && (!name || !name[0]) &&
520 (HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) &&
521 (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
523 *retkey = hkey;
524 return ERROR_SUCCESS;
527 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
528 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++;
530 if (!retkey) return ERROR_INVALID_PARAMETER;
531 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
533 attr.Length = sizeof(attr);
534 attr.RootDirectory = hkey;
535 attr.ObjectName = &nameW;
536 attr.Attributes = 0;
537 attr.SecurityDescriptor = NULL;
538 attr.SecurityQualityOfService = NULL;
539 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
540 RtlInitUnicodeString( &nameW, name );
541 return RtlNtStatusToDosError( open_key( retkey, access, &attr ) );
545 /******************************************************************************
546 * RegOpenKeyExA [ADVAPI32.@]
548 * Open a registry key.
550 * PARAMS
551 * hkey [I] Handle of open key
552 * name [I] Name of subkey to open
553 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
554 * access [I] Security access mask
555 * retkey [O] Handle to open key
557 * RETURNS
558 * Success: ERROR_SUCCESS
559 * Failure: A standard Win32 error code. retkey is set to 0.
561 * NOTES
562 * Unlike RegCreateKeyExA(), this function will not create the key if it
563 * does not exist.
565 LSTATUS WINAPI DECLSPEC_HOTPATCH RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
567 OBJECT_ATTRIBUTES attr;
568 STRING nameA;
569 NTSTATUS status;
571 if (retkey && (!name || !name[0]) &&
572 (HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) &&
573 (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
575 *retkey = hkey;
576 return ERROR_SUCCESS;
579 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
580 else
582 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
583 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++;
586 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
588 attr.Length = sizeof(attr);
589 attr.RootDirectory = hkey;
590 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
591 attr.Attributes = 0;
592 attr.SecurityDescriptor = NULL;
593 attr.SecurityQualityOfService = NULL;
594 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
596 RtlInitAnsiString( &nameA, name );
597 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
598 &nameA, FALSE )))
600 status = open_key( retkey, access, &attr );
602 return RtlNtStatusToDosError( status );
606 /******************************************************************************
607 * RegOpenKeyW [ADVAPI32.@]
609 * See RegOpenKeyA.
611 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
613 if (!retkey)
614 return ERROR_INVALID_PARAMETER;
616 if (!name || !*name)
618 *retkey = hkey;
619 return ERROR_SUCCESS;
621 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
625 /******************************************************************************
626 * RegOpenKeyA [ADVAPI32.@]
628 * Open a registry key.
630 * PARAMS
631 * hkey [I] Handle of parent key to open the new key under
632 * name [I] Name of the key under hkey to open
633 * retkey [O] Destination for the resulting Handle
635 * RETURNS
636 * Success: ERROR_SUCCESS
637 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
639 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
641 if (!retkey)
642 return ERROR_INVALID_PARAMETER;
644 if (!name || !*name)
646 *retkey = hkey;
647 return ERROR_SUCCESS;
649 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
652 static WCHAR *get_thread_token_user_sid(HANDLE token)
654 WCHAR *sidstring = NULL;
655 TOKEN_USER *info;
656 DWORD len = 0;
658 GetTokenInformation(token, TokenUser, NULL, 0, &len);
660 info = heap_alloc(len);
661 if (GetTokenInformation(token, TokenUser, info, len, &len))
662 ConvertSidToStringSidW(info->User.Sid, &sidstring);
663 heap_free(info);
665 return sidstring;
668 /******************************************************************************
669 * RegOpenCurrentUser [ADVAPI32.@]
671 * Get a handle to the HKEY_CURRENT_USER key for the user
672 * the current thread is impersonating.
674 * PARAMS
675 * access [I] Desired access rights to the key
676 * retkey [O] Handle to the opened key
678 * RETURNS
679 * Success: ERROR_SUCCESS
680 * Failure: nonzero error code from Winerror.h
682 * FIXME
683 * This function is supposed to retrieve a handle to the
684 * HKEY_CURRENT_USER for the user the current thread is impersonating.
685 * Since Wine does not currently allow threads to impersonate other users,
686 * this stub should work fine.
688 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
690 WCHAR *sidstring = NULL;
691 HANDLE threadtoken;
692 LSTATUS ret;
694 /* get current user SID */
695 if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &threadtoken))
697 sidstring = get_thread_token_user_sid(threadtoken);
698 CloseHandle(threadtoken);
701 if (!sidstring)
703 ImpersonateSelf(SecurityIdentification);
704 if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &threadtoken))
706 sidstring = get_thread_token_user_sid(threadtoken);
707 CloseHandle(threadtoken);
709 RevertToSelf();
712 if (sidstring)
714 ret = RegOpenKeyExW( HKEY_USERS, sidstring, 0, access, retkey );
715 LocalFree(sidstring);
717 else
718 ret = RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
720 return ret;
725 /******************************************************************************
726 * RegEnumKeyExW [ADVAPI32.@]
728 * Enumerate subkeys of the specified open registry key.
730 * PARAMS
731 * hkey [I] Handle to key to enumerate
732 * index [I] Index of subkey to enumerate
733 * name [O] Buffer for subkey name
734 * name_len [O] Size of subkey buffer
735 * reserved [I] Reserved
736 * class [O] Buffer for class string
737 * class_len [O] Size of class buffer
738 * ft [O] Time key last written to
740 * RETURNS
741 * Success: ERROR_SUCCESS
742 * Failure: System error code. If there are no more subkeys available, the
743 * function returns ERROR_NO_MORE_ITEMS.
745 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
746 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
748 NTSTATUS status;
749 char buffer[256], *buf_ptr = buffer;
750 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
751 DWORD total_size;
753 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
754 name_len ? *name_len : 0, reserved, class, class_len, ft );
756 if (reserved) return ERROR_INVALID_PARAMETER;
757 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
759 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
760 buffer, sizeof(buffer), &total_size );
762 while (status == STATUS_BUFFER_OVERFLOW)
764 /* retry with a dynamically allocated buffer */
765 if (buf_ptr != buffer) heap_free( buf_ptr );
766 if (!(buf_ptr = heap_alloc( total_size )))
767 return ERROR_NOT_ENOUGH_MEMORY;
768 info = (KEY_NODE_INFORMATION *)buf_ptr;
769 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
770 buf_ptr, total_size, &total_size );
773 if (!status)
775 DWORD len = info->NameLength / sizeof(WCHAR);
776 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
778 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
780 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
781 status = STATUS_BUFFER_OVERFLOW;
782 else
784 *name_len = len;
785 memcpy( name, info->Name, info->NameLength );
786 name[len] = 0;
787 if (class_len)
789 *class_len = cls_len;
790 if (class)
792 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
793 class[cls_len] = 0;
799 if (buf_ptr != buffer) heap_free( buf_ptr );
800 return RtlNtStatusToDosError( status );
804 /******************************************************************************
805 * RegEnumKeyExA [ADVAPI32.@]
807 * See RegEnumKeyExW.
809 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
810 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
812 NTSTATUS status;
813 char buffer[256], *buf_ptr = buffer;
814 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
815 DWORD total_size;
817 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
818 name_len ? *name_len : 0, reserved, class, class_len, ft );
820 if (reserved) return ERROR_INVALID_PARAMETER;
821 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
823 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
824 buffer, sizeof(buffer), &total_size );
826 while (status == STATUS_BUFFER_OVERFLOW)
828 /* retry with a dynamically allocated buffer */
829 if (buf_ptr != buffer) heap_free( buf_ptr );
830 if (!(buf_ptr = heap_alloc( total_size )))
831 return ERROR_NOT_ENOUGH_MEMORY;
832 info = (KEY_NODE_INFORMATION *)buf_ptr;
833 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
834 buf_ptr, total_size, &total_size );
837 if (!status)
839 DWORD len, cls_len;
841 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
842 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
843 info->ClassLength );
844 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
846 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
847 status = STATUS_BUFFER_OVERFLOW;
848 else
850 *name_len = len;
851 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
852 name[len] = 0;
853 if (class_len)
855 *class_len = cls_len;
856 if (class)
858 RtlUnicodeToMultiByteN( class, cls_len, NULL,
859 (WCHAR *)(buf_ptr + info->ClassOffset),
860 info->ClassLength );
861 class[cls_len] = 0;
867 if (buf_ptr != buffer) heap_free( buf_ptr );
868 return RtlNtStatusToDosError( status );
872 /******************************************************************************
873 * RegEnumKeyW [ADVAPI32.@]
875 * Enumerates subkeys of the specified open reg key.
877 * PARAMS
878 * hKey [I] Handle to an open key.
879 * dwIndex [I] Index of the subkey of hKey to retrieve.
880 * lpName [O] Name of the subkey.
881 * cchName [I] Size of lpName in TCHARS.
883 * RETURNS
884 * Success: ERROR_SUCCESS
885 * Failure: system error code. If there are no more subkeys available, the
886 * function returns ERROR_NO_MORE_ITEMS.
888 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
890 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
894 /******************************************************************************
895 * RegEnumKeyA [ADVAPI32.@]
897 * See RegEnumKeyW.
899 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
901 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
905 /******************************************************************************
906 * RegQueryInfoKeyW [ADVAPI32.@]
908 * Retrieves information about the specified registry key.
910 * PARAMS
911 * hkey [I] Handle to key to query
912 * class [O] Buffer for class string
913 * class_len [O] Size of class string buffer
914 * reserved [I] Reserved
915 * subkeys [O] Buffer for number of subkeys
916 * max_subkey [O] Buffer for longest subkey name length
917 * max_class [O] Buffer for longest class string length
918 * values [O] Buffer for number of value entries
919 * max_value [O] Buffer for longest value name length
920 * max_data [O] Buffer for longest value data length
921 * security [O] Buffer for security descriptor length
922 * modif [O] Modification time
924 * RETURNS
925 * Success: ERROR_SUCCESS
926 * Failure: system error code.
928 * NOTES
929 * - win95 allows class to be valid and class_len to be NULL
930 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
931 * - both allow class to be NULL and class_len to be NULL
932 * (it's hard to test validity, so test !NULL instead)
934 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
935 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
936 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
937 LPDWORD security, FILETIME *modif )
939 NTSTATUS status;
940 char buffer[256], *buf_ptr = buffer;
941 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
942 DWORD total_size;
944 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
945 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
947 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
948 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
950 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
951 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
953 if (class && class_len && *class_len)
955 /* retry with a dynamically allocated buffer */
956 while (status == STATUS_BUFFER_OVERFLOW)
958 if (buf_ptr != buffer) heap_free( buf_ptr );
959 if (!(buf_ptr = heap_alloc( total_size )))
960 return ERROR_NOT_ENOUGH_MEMORY;
961 info = (KEY_FULL_INFORMATION *)buf_ptr;
962 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
965 if (status) goto done;
967 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
969 status = STATUS_BUFFER_TOO_SMALL;
971 else
973 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
974 class[info->ClassLength/sizeof(WCHAR)] = 0;
977 else status = STATUS_SUCCESS;
979 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
980 if (subkeys) *subkeys = info->SubKeys;
981 if (max_subkey) *max_subkey = info->MaxNameLen / sizeof(WCHAR);
982 if (max_class) *max_class = info->MaxClassLen / sizeof(WCHAR);
983 if (values) *values = info->Values;
984 if (max_value) *max_value = info->MaxValueNameLen / sizeof(WCHAR);
985 if (max_data) *max_data = info->MaxValueDataLen;
986 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
988 if (security)
990 FIXME( "security argument not supported.\n");
991 *security = 0;
994 done:
995 if (buf_ptr != buffer) heap_free( buf_ptr );
996 return RtlNtStatusToDosError( status );
1000 /******************************************************************************
1001 * RegQueryMultipleValuesA [ADVAPI32.@]
1003 * Retrieves the type and data for a list of value names associated with a key.
1005 * PARAMS
1006 * hKey [I] Handle to an open key.
1007 * val_list [O] Array of VALENT structures that describes the entries.
1008 * num_vals [I] Number of elements in val_list.
1009 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
1010 * ldwTotsize [I/O] Size of lpValueBuf.
1012 * RETURNS
1013 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
1014 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
1015 * bytes.
1017 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
1018 LPSTR lpValueBuf, LPDWORD ldwTotsize )
1020 unsigned int i;
1021 DWORD maxBytes = *ldwTotsize;
1022 HRESULT status;
1023 LPSTR bufptr = lpValueBuf;
1024 *ldwTotsize = 0;
1026 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
1028 for(i=0; i < num_vals; ++i)
1031 val_list[i].ve_valuelen=0;
1032 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
1033 if(status != ERROR_SUCCESS)
1035 return status;
1038 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
1040 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
1041 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
1042 if(status != ERROR_SUCCESS)
1044 return status;
1047 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
1049 bufptr += val_list[i].ve_valuelen;
1052 *ldwTotsize += val_list[i].ve_valuelen;
1054 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
1058 /******************************************************************************
1059 * RegQueryMultipleValuesW [ADVAPI32.@]
1061 * See RegQueryMultipleValuesA.
1063 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
1064 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
1066 unsigned int i;
1067 DWORD maxBytes = *ldwTotsize;
1068 HRESULT status;
1069 LPSTR bufptr = (LPSTR)lpValueBuf;
1070 *ldwTotsize = 0;
1072 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
1074 for(i=0; i < num_vals; ++i)
1076 val_list[i].ve_valuelen=0;
1077 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
1078 if(status != ERROR_SUCCESS)
1080 return status;
1083 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
1085 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
1086 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
1087 if(status != ERROR_SUCCESS)
1089 return status;
1092 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
1094 bufptr += val_list[i].ve_valuelen;
1097 *ldwTotsize += val_list[i].ve_valuelen;
1099 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
1102 /******************************************************************************
1103 * RegQueryInfoKeyA [ADVAPI32.@]
1105 * Retrieves information about a registry key.
1107 * PARAMS
1108 * hKey [I] Handle to an open key.
1109 * lpClass [O] Class string of the key.
1110 * lpcClass [I/O] size of lpClass.
1111 * lpReserved [I] Reserved; must be NULL.
1112 * lpcSubKeys [O] Number of subkeys contained by the key.
1113 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
1114 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
1115 * class in TCHARS.
1116 * lpcValues [O] Number of values associated with the key.
1117 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
1118 * lpcMaxValueLen [O] Longest data component among the key's values
1119 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
1120 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
1122 * RETURNS
1123 * Success: ERROR_SUCCESS
1124 * Failure: nonzero error code from Winerror.h
1126 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
1127 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
1128 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
1129 LPDWORD security, FILETIME *modif )
1131 NTSTATUS status;
1132 char buffer[256], *buf_ptr = buffer;
1133 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
1134 DWORD total_size, len;
1136 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
1137 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
1139 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
1140 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1142 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
1143 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1145 if (class || class_len)
1147 /* retry with a dynamically allocated buffer */
1148 while (status == STATUS_BUFFER_OVERFLOW)
1150 if (buf_ptr != buffer) heap_free( buf_ptr );
1151 if (!(buf_ptr = heap_alloc( total_size )))
1152 return ERROR_NOT_ENOUGH_MEMORY;
1153 info = (KEY_FULL_INFORMATION *)buf_ptr;
1154 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
1157 if (status) goto done;
1159 len = 0;
1160 if (class && class_len) len = *class_len;
1161 RtlUnicodeToMultiByteN( class, len, class_len,
1162 (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength );
1163 if (len)
1165 if (*class_len + 1 > len)
1167 status = STATUS_BUFFER_OVERFLOW;
1168 *class_len -= 1;
1170 class[*class_len] = 0;
1173 else status = STATUS_SUCCESS;
1175 if (subkeys) *subkeys = info->SubKeys;
1176 if (max_subkey) *max_subkey = info->MaxNameLen / sizeof(WCHAR);
1177 if (max_class) *max_class = info->MaxClassLen / sizeof(WCHAR);
1178 if (values) *values = info->Values;
1179 if (max_value) *max_value = info->MaxValueNameLen / sizeof(WCHAR);
1180 if (max_data) *max_data = info->MaxValueDataLen;
1181 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
1183 if (security)
1185 FIXME( "security argument not supported.\n");
1186 *security = 0;
1189 done:
1190 if (buf_ptr != buffer) heap_free( buf_ptr );
1191 return RtlNtStatusToDosError( status );
1195 /******************************************************************************
1196 * RegCloseKey [ADVAPI32.@]
1198 * Close an open registry key.
1200 * PARAMS
1201 * hkey [I] Handle of key to close
1203 * RETURNS
1204 * Success: ERROR_SUCCESS
1205 * Failure: Error code
1207 LSTATUS WINAPI DECLSPEC_HOTPATCH RegCloseKey( HKEY hkey )
1209 if (!hkey) return ERROR_INVALID_HANDLE;
1210 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
1211 return RtlNtStatusToDosError( NtClose( hkey ) );
1215 /******************************************************************************
1216 * RegDeleteKeyExW [ADVAPI32.@]
1218 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
1220 DWORD ret;
1221 HKEY tmp;
1223 if (!name) return ERROR_INVALID_PARAMETER;
1225 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
1227 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1228 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
1230 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1231 RegCloseKey( tmp );
1233 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
1234 return ret;
1238 /******************************************************************************
1239 * RegDeleteKeyW [ADVAPI32.@]
1241 * See RegDeleteKeyA.
1243 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
1245 return RegDeleteKeyExW( hkey, name, 0, 0 );
1249 /******************************************************************************
1250 * RegDeleteKeyExA [ADVAPI32.@]
1252 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1254 DWORD ret;
1255 HKEY tmp;
1257 if (!name) return ERROR_INVALID_PARAMETER;
1259 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
1261 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1262 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1264 if (!is_version_nt()) /* win95 does recursive key deletes */
1266 CHAR sub[MAX_PATH];
1268 while(!RegEnumKeyA(tmp, 0, sub, sizeof(sub)))
1270 if(RegDeleteKeyExA(tmp, sub, access, reserved)) /* recurse */
1271 break;
1274 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1275 RegCloseKey( tmp );
1277 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1278 return ret;
1282 /******************************************************************************
1283 * RegDeleteKeyA [ADVAPI32.@]
1285 * Delete a registry key.
1287 * PARAMS
1288 * hkey [I] Handle to parent key containing the key to delete
1289 * name [I] Name of the key user hkey to delete
1291 * NOTES
1293 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1294 * right. In reality, it opens a new handle with DELETE access.
1296 * RETURNS
1297 * Success: ERROR_SUCCESS
1298 * Failure: Error code
1300 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1302 return RegDeleteKeyExA( hkey, name, 0, 0 );
1307 /******************************************************************************
1308 * RegSetValueExW [ADVAPI32.@]
1310 * Set the data and contents of a registry value.
1312 * PARAMS
1313 * hkey [I] Handle of key to set value for
1314 * name [I] Name of value to set
1315 * reserved [I] Reserved, must be zero
1316 * type [I] Type of the value being set
1317 * data [I] The new contents of the value to set
1318 * count [I] Size of data
1320 * RETURNS
1321 * Success: ERROR_SUCCESS
1322 * Failure: Error code
1324 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1325 DWORD type, const BYTE *data, DWORD count )
1327 UNICODE_STRING nameW;
1329 /* no need for version check, not implemented on win9x anyway */
1331 if ((data && ((ULONG_PTR)data >> 16) == 0) || (!data && count)) return ERROR_NOACCESS;
1333 if (count && is_string(type))
1335 LPCWSTR str = (LPCWSTR)data;
1336 /* if user forgot to count terminating null, add it (yes NT does this) */
1337 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1338 count += sizeof(WCHAR);
1340 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1342 RtlInitUnicodeString( &nameW, name );
1343 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1347 /******************************************************************************
1348 * RegSetValueExA [ADVAPI32.@]
1350 * See RegSetValueExW.
1352 * NOTES
1353 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1354 * NT does definitely care (aj)
1356 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1357 const BYTE *data, DWORD count )
1359 ANSI_STRING nameA;
1360 UNICODE_STRING nameW;
1361 WCHAR *dataW = NULL;
1362 NTSTATUS status;
1364 if (!is_version_nt()) /* win95 */
1366 if (type == REG_SZ)
1368 if (!data) return ERROR_INVALID_PARAMETER;
1369 count = strlen((const char *)data) + 1;
1372 else if (count && is_string(type))
1374 /* if user forgot to count terminating null, add it (yes NT does this) */
1375 if (data[count-1] && !data[count]) count++;
1378 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1380 if (is_string( type )) /* need to convert to Unicode */
1382 DWORD lenW;
1383 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1384 if (!(dataW = heap_alloc( lenW ))) return ERROR_OUTOFMEMORY;
1385 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1386 count = lenW;
1387 data = (BYTE *)dataW;
1390 RtlInitAnsiString( &nameA, name );
1391 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1393 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1394 RtlFreeUnicodeString( &nameW );
1396 heap_free( dataW );
1397 return RtlNtStatusToDosError( status );
1401 /******************************************************************************
1402 * RegSetValueW [ADVAPI32.@]
1404 * Sets the data for the default or unnamed value of a reg key.
1406 * PARAMS
1407 * hkey [I] Handle to an open key.
1408 * subkey [I] Name of a subkey of hKey.
1409 * type [I] Type of information to store.
1410 * data [I] String that contains the data to set for the default value.
1411 * count [I] Ignored.
1413 * RETURNS
1414 * Success: ERROR_SUCCESS
1415 * Failure: nonzero error code from Winerror.h
1417 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR subkey, DWORD type, LPCWSTR data, DWORD count )
1419 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(subkey), type, debugstr_w(data), count );
1421 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1423 return RegSetKeyValueW( hkey, subkey, NULL, type, data, (strlenW(data) + 1)*sizeof(WCHAR) );
1426 /******************************************************************************
1427 * RegSetValueA [ADVAPI32.@]
1429 * See RegSetValueW.
1431 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR subkey, DWORD type, LPCSTR data, DWORD count )
1433 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(subkey), type, debugstr_a(data), count );
1435 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1437 return RegSetKeyValueA( hkey, subkey, NULL, type, data, strlen(data) + 1 );
1440 /******************************************************************************
1441 * RegSetKeyValueW [ADVAPI32.@]
1443 LONG WINAPI RegSetKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name, DWORD type, const void *data, DWORD len )
1445 HKEY hsubkey = NULL;
1446 DWORD ret;
1448 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey, debugstr_w(subkey), debugstr_w(name), type, data, len );
1450 if (subkey && subkey[0]) /* need to create the subkey */
1452 if ((ret = RegCreateKeyW( hkey, subkey, &hsubkey )) != ERROR_SUCCESS) return ret;
1453 hkey = hsubkey;
1456 ret = RegSetValueExW( hkey, name, 0, type, (const BYTE*)data, len );
1457 if (hsubkey) RegCloseKey( hsubkey );
1458 return ret;
1461 /******************************************************************************
1462 * RegSetKeyValueA [ADVAPI32.@]
1464 LONG WINAPI RegSetKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name, DWORD type, const void *data, DWORD len )
1466 HKEY hsubkey = NULL;
1467 DWORD ret;
1469 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey, debugstr_a(subkey), debugstr_a(name), type, data, len );
1471 if (subkey && subkey[0]) /* need to create the subkey */
1473 if ((ret = RegCreateKeyA( hkey, subkey, &hsubkey )) != ERROR_SUCCESS) return ret;
1474 hkey = hsubkey;
1477 ret = RegSetValueExA( hkey, name, 0, type, (const BYTE*)data, len );
1478 if (hsubkey) RegCloseKey( hsubkey );
1479 return ret;
1482 /******************************************************************************
1483 * RegQueryValueExW [ADVAPI32.@]
1485 * See RegQueryValueExA.
1487 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1488 LPBYTE data, LPDWORD count )
1490 NTSTATUS status;
1491 UNICODE_STRING name_str;
1492 DWORD total_size;
1493 char buffer[256], *buf_ptr = buffer;
1494 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1495 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1497 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1498 hkey, debugstr_w(name), reserved, type, data, count,
1499 (count && data) ? *count : 0 );
1501 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1502 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1504 RtlInitUnicodeString( &name_str, name );
1506 if (data) total_size = min( sizeof(buffer), *count + info_size );
1507 else
1509 total_size = info_size;
1510 if (count) *count = 0;
1513 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1514 buffer, total_size, &total_size );
1515 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1517 if (data)
1519 /* retry with a dynamically allocated buffer */
1520 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1522 if (buf_ptr != buffer) heap_free( buf_ptr );
1523 if (!(buf_ptr = heap_alloc( total_size )))
1524 return ERROR_NOT_ENOUGH_MEMORY;
1525 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1526 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1527 buf_ptr, total_size, &total_size );
1530 if (!status)
1532 memcpy( data, buf_ptr + info_size, total_size - info_size );
1533 /* if the type is REG_SZ and data is not 0-terminated
1534 * and there is enough space in the buffer NT appends a \0 */
1535 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1537 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1538 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1541 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1543 else status = STATUS_SUCCESS;
1545 if (type) *type = info->Type;
1546 if (count) *count = total_size - info_size;
1548 done:
1549 if (buf_ptr != buffer) heap_free( buf_ptr );
1550 return RtlNtStatusToDosError(status);
1554 /******************************************************************************
1555 * RegQueryValueExA [ADVAPI32.@]
1557 * Get the type and contents of a specified value under with a key.
1559 * PARAMS
1560 * hkey [I] Handle of the key to query
1561 * name [I] Name of value under hkey to query
1562 * reserved [I] Reserved - must be NULL
1563 * type [O] Destination for the value type, or NULL if not required
1564 * data [O] Destination for the values contents, or NULL if not required
1565 * count [I/O] Size of data, updated with the number of bytes returned
1567 * RETURNS
1568 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1569 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1570 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1571 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1573 * NOTES
1574 * MSDN states that if data is too small it is partially filled. In reality
1575 * it remains untouched.
1577 LSTATUS WINAPI DECLSPEC_HOTPATCH RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved,
1578 LPDWORD type, LPBYTE data, LPDWORD count )
1580 NTSTATUS status;
1581 ANSI_STRING nameA;
1582 UNICODE_STRING nameW;
1583 DWORD total_size, datalen = 0;
1584 char buffer[256], *buf_ptr = buffer;
1585 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1586 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1588 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1589 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1591 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1592 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1594 if (count) datalen = *count;
1595 if (!data && count) *count = 0;
1597 /* this matches Win9x behaviour - NT sets *type to a random value */
1598 if (type) *type = REG_NONE;
1600 RtlInitAnsiString( &nameA, name );
1601 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1602 return RtlNtStatusToDosError(status);
1604 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1605 buffer, sizeof(buffer), &total_size );
1606 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1608 /* we need to fetch the contents for a string type even if not requested,
1609 * because we need to compute the length of the ASCII string. */
1610 if (data || is_string(info->Type))
1612 /* retry with a dynamically allocated buffer */
1613 while (status == STATUS_BUFFER_OVERFLOW)
1615 if (buf_ptr != buffer) heap_free( buf_ptr );
1616 if (!(buf_ptr = heap_alloc( total_size )))
1618 status = STATUS_NO_MEMORY;
1619 goto done;
1621 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1622 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1623 buf_ptr, total_size, &total_size );
1626 if (status) goto done;
1628 if (is_string(info->Type))
1630 DWORD len;
1632 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1633 total_size - info_size );
1634 if (data && len)
1636 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1637 else
1639 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1640 total_size - info_size );
1641 /* if the type is REG_SZ and data is not 0-terminated
1642 * and there is enough space in the buffer NT appends a \0 */
1643 if (len < datalen && data[len-1]) data[len] = 0;
1646 total_size = len + info_size;
1648 else if (data)
1650 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1651 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1654 else status = STATUS_SUCCESS;
1656 if (type) *type = info->Type;
1657 if (count) *count = total_size - info_size;
1659 done:
1660 if (buf_ptr != buffer) heap_free( buf_ptr );
1661 RtlFreeUnicodeString( &nameW );
1662 return RtlNtStatusToDosError(status);
1666 /******************************************************************************
1667 * RegQueryValueW [ADVAPI32.@]
1669 * Retrieves the data associated with the default or unnamed value of a key.
1671 * PARAMS
1672 * hkey [I] Handle to an open key.
1673 * name [I] Name of the subkey of hKey.
1674 * data [O] Receives the string associated with the default value
1675 * of the key.
1676 * count [I/O] Size of lpValue in bytes.
1678 * RETURNS
1679 * Success: ERROR_SUCCESS
1680 * Failure: nonzero error code from Winerror.h
1682 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1684 DWORD ret;
1685 HKEY subkey = hkey;
1687 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1689 if (name && name[0])
1691 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1693 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1694 if (subkey != hkey) RegCloseKey( subkey );
1695 if (ret == ERROR_FILE_NOT_FOUND)
1697 /* return empty string if default value not found */
1698 if (data) *data = 0;
1699 if (count) *count = sizeof(WCHAR);
1700 ret = ERROR_SUCCESS;
1702 return ret;
1706 /******************************************************************************
1707 * RegQueryValueA [ADVAPI32.@]
1709 * See RegQueryValueW.
1711 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1713 DWORD ret;
1714 HKEY subkey = hkey;
1716 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1718 if (name && name[0])
1720 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1722 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1723 if (subkey != hkey) RegCloseKey( subkey );
1724 if (ret == ERROR_FILE_NOT_FOUND)
1726 /* return empty string if default value not found */
1727 if (data) *data = 0;
1728 if (count) *count = 1;
1729 ret = ERROR_SUCCESS;
1731 return ret;
1735 /******************************************************************************
1736 * ADVAPI_ApplyRestrictions [internal]
1738 * Helper function for RegGetValueA/W.
1740 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1741 DWORD cbData, PLONG ret )
1743 /* Check if the type is restricted by the passed flags */
1744 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1746 DWORD dwMask = 0;
1748 switch (dwType)
1750 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1751 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1752 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1753 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1754 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1755 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1756 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1759 if (dwFlags & dwMask)
1761 /* Type is not restricted, check for size mismatch */
1762 if (dwType == REG_BINARY)
1764 DWORD cbExpect = 0;
1766 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1767 cbExpect = 4;
1768 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1769 cbExpect = 8;
1771 if (cbExpect && cbData != cbExpect)
1772 *ret = ERROR_DATATYPE_MISMATCH;
1775 else *ret = ERROR_UNSUPPORTED_TYPE;
1780 /******************************************************************************
1781 * RegGetValueW [ADVAPI32.@]
1783 * Retrieves the type and data for a value name associated with a key,
1784 * optionally expanding its content and restricting its type.
1786 * PARAMS
1787 * hKey [I] Handle to an open key.
1788 * pszSubKey [I] Name of the subkey of hKey.
1789 * pszValue [I] Name of value under hKey/szSubKey to query.
1790 * dwFlags [I] Flags restricting the value type to retrieve.
1791 * pdwType [O] Destination for the values type, may be NULL.
1792 * pvData [O] Destination for the values content, may be NULL.
1793 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1794 * retrieve the whole content, including the trailing '\0'
1795 * for strings.
1797 * RETURNS
1798 * Success: ERROR_SUCCESS
1799 * Failure: nonzero error code from Winerror.h
1801 * NOTES
1802 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1803 * expanded and pdwType is set to REG_SZ instead.
1804 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1805 * without RRF_NOEXPAND is thus not allowed.
1806 * An exception is the case where RRF_RT_ANY is specified, because then
1807 * RRF_NOEXPAND is allowed.
1809 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1810 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1811 LPDWORD pcbData )
1813 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1814 PVOID pvBuf = NULL;
1815 LONG ret;
1817 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1818 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1819 pvData, pcbData, cbData);
1821 if (pvData && !pcbData)
1822 return ERROR_INVALID_PARAMETER;
1823 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1824 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1825 return ERROR_INVALID_PARAMETER;
1827 if (pszSubKey && pszSubKey[0])
1829 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1830 if (ret != ERROR_SUCCESS) return ret;
1833 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1835 /* If we are going to expand we need to read in the whole the value even
1836 * if the passed buffer was too small as the expanded string might be
1837 * smaller than the unexpanded one and could fit into cbData bytes. */
1838 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1839 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1841 do {
1842 heap_free(pvBuf);
1844 pvBuf = heap_alloc(cbData);
1845 if (!pvBuf)
1847 ret = ERROR_NOT_ENOUGH_MEMORY;
1848 break;
1851 if (ret == ERROR_MORE_DATA || !pvData)
1852 ret = RegQueryValueExW(hKey, pszValue, NULL,
1853 &dwType, pvBuf, &cbData);
1854 else
1856 /* Even if cbData was large enough we have to copy the
1857 * string since ExpandEnvironmentStrings can't handle
1858 * overlapping buffers. */
1859 CopyMemory(pvBuf, pvData, cbData);
1862 /* Both the type or the value itself could have been modified in
1863 * between so we have to keep retrying until the buffer is large
1864 * enough or we no longer have to expand the value. */
1865 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1867 if (ret == ERROR_SUCCESS)
1869 /* Recheck dwType in case it changed since the first call */
1870 if (dwType == REG_EXPAND_SZ)
1872 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1873 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1874 dwType = REG_SZ;
1875 if(pvData && pcbData && cbData > *pcbData)
1876 ret = ERROR_MORE_DATA;
1878 else if (pvData)
1879 CopyMemory(pvData, pvBuf, *pcbData);
1882 heap_free(pvBuf);
1885 if (pszSubKey && pszSubKey[0])
1886 RegCloseKey(hKey);
1888 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1890 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1891 ZeroMemory(pvData, *pcbData);
1893 if (pdwType) *pdwType = dwType;
1894 if (pcbData) *pcbData = cbData;
1896 return ret;
1900 /******************************************************************************
1901 * RegGetValueA [ADVAPI32.@]
1903 * See RegGetValueW.
1905 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1906 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1907 LPDWORD pcbData )
1909 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1910 PVOID pvBuf = NULL;
1911 LONG ret;
1913 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1914 hKey, debugstr_a(pszSubKey), debugstr_a(pszValue), dwFlags,
1915 pdwType, pvData, pcbData, cbData);
1917 if (pvData && !pcbData)
1918 return ERROR_INVALID_PARAMETER;
1919 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1920 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1921 return ERROR_INVALID_PARAMETER;
1923 if (pszSubKey && pszSubKey[0])
1925 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1926 if (ret != ERROR_SUCCESS) return ret;
1929 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1931 /* If we are going to expand we need to read in the whole the value even
1932 * if the passed buffer was too small as the expanded string might be
1933 * smaller than the unexpanded one and could fit into cbData bytes. */
1934 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1935 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1937 do {
1938 heap_free(pvBuf);
1940 pvBuf = heap_alloc(cbData);
1941 if (!pvBuf)
1943 ret = ERROR_NOT_ENOUGH_MEMORY;
1944 break;
1947 if (ret == ERROR_MORE_DATA || !pvData)
1948 ret = RegQueryValueExA(hKey, pszValue, NULL,
1949 &dwType, pvBuf, &cbData);
1950 else
1952 /* Even if cbData was large enough we have to copy the
1953 * string since ExpandEnvironmentStrings can't handle
1954 * overlapping buffers. */
1955 CopyMemory(pvBuf, pvData, cbData);
1958 /* Both the type or the value itself could have been modified in
1959 * between so we have to keep retrying until the buffer is large
1960 * enough or we no longer have to expand the value. */
1961 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1963 if (ret == ERROR_SUCCESS)
1965 /* Recheck dwType in case it changed since the first call */
1966 if (dwType == REG_EXPAND_SZ)
1968 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1969 pcbData ? *pcbData : 0);
1970 dwType = REG_SZ;
1971 if(pvData && pcbData && cbData > *pcbData)
1972 ret = ERROR_MORE_DATA;
1974 else if (pvData)
1975 CopyMemory(pvData, pvBuf, *pcbData);
1978 heap_free(pvBuf);
1981 if (pszSubKey && pszSubKey[0])
1982 RegCloseKey(hKey);
1984 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1986 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1987 ZeroMemory(pvData, *pcbData);
1989 if (pdwType) *pdwType = dwType;
1990 if (pcbData) *pcbData = cbData;
1992 return ret;
1996 /******************************************************************************
1997 * RegEnumValueW [ADVAPI32.@]
1999 * Enumerates the values for the specified open registry key.
2001 * PARAMS
2002 * hkey [I] Handle to key to query
2003 * index [I] Index of value to query
2004 * value [O] Value string
2005 * val_count [I/O] Size of value buffer (in wchars)
2006 * reserved [I] Reserved
2007 * type [O] Type code
2008 * data [O] Value data
2009 * count [I/O] Size of data buffer (in bytes)
2011 * RETURNS
2012 * Success: ERROR_SUCCESS
2013 * Failure: nonzero error code from Winerror.h
2016 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
2017 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
2019 NTSTATUS status;
2020 DWORD total_size;
2021 char buffer[256], *buf_ptr = buffer;
2022 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2023 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
2025 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
2026 hkey, index, value, val_count, reserved, type, data, count );
2028 if ((data && !count) || reserved || !value || !val_count)
2029 return ERROR_INVALID_PARAMETER;
2030 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2032 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2033 if (data) total_size += *count;
2034 total_size = min( sizeof(buffer), total_size );
2036 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
2037 buffer, total_size, &total_size );
2039 /* retry with a dynamically allocated buffer */
2040 while (status == STATUS_BUFFER_OVERFLOW)
2042 if (buf_ptr != buffer) heap_free( buf_ptr );
2043 if (!(buf_ptr = heap_alloc( total_size )))
2044 return ERROR_NOT_ENOUGH_MEMORY;
2045 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2046 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
2047 buf_ptr, total_size, &total_size );
2050 if (status) goto done;
2052 if (info->NameLength/sizeof(WCHAR) >= *val_count)
2054 status = STATUS_BUFFER_OVERFLOW;
2055 goto overflow;
2057 memcpy( value, info->Name, info->NameLength );
2058 *val_count = info->NameLength / sizeof(WCHAR);
2059 value[*val_count] = 0;
2061 if (data)
2063 if (total_size - info->DataOffset > *count)
2065 status = STATUS_BUFFER_OVERFLOW;
2066 goto overflow;
2068 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2069 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
2071 /* if the type is REG_SZ and data is not 0-terminated
2072 * and there is enough space in the buffer NT appends a \0 */
2073 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
2074 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
2078 overflow:
2079 if (type) *type = info->Type;
2080 if (count) *count = info->DataLength;
2082 done:
2083 if (buf_ptr != buffer) heap_free( buf_ptr );
2084 return RtlNtStatusToDosError(status);
2088 /******************************************************************************
2089 * RegEnumValueA [ADVAPI32.@]
2091 * See RegEnumValueW.
2093 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
2094 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
2096 NTSTATUS status;
2097 DWORD total_size;
2098 char buffer[256], *buf_ptr = buffer;
2099 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2100 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
2102 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
2103 hkey, index, value, val_count, reserved, type, data, count );
2105 if ((data && !count) || reserved || !value || !val_count)
2106 return ERROR_INVALID_PARAMETER;
2107 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2109 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2110 if (data) total_size += *count;
2111 total_size = min( sizeof(buffer), total_size );
2113 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
2114 buffer, total_size, &total_size );
2116 /* we need to fetch the contents for a string type even if not requested,
2117 * because we need to compute the length of the ASCII string. */
2119 /* retry with a dynamically allocated buffer */
2120 while (status == STATUS_BUFFER_OVERFLOW)
2122 if (buf_ptr != buffer) heap_free( buf_ptr );
2123 if (!(buf_ptr = heap_alloc( total_size )))
2124 return ERROR_NOT_ENOUGH_MEMORY;
2125 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2126 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
2127 buf_ptr, total_size, &total_size );
2130 if (status) goto done;
2132 if (is_string(info->Type))
2134 DWORD len;
2135 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
2136 total_size - info->DataOffset );
2137 if (data && len)
2139 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
2140 else
2142 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
2143 total_size - info->DataOffset );
2144 /* if the type is REG_SZ and data is not 0-terminated
2145 * and there is enough space in the buffer NT appends a \0 */
2146 if (len < *count && data[len-1]) data[len] = 0;
2149 info->DataLength = len;
2151 else if (data)
2153 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
2154 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2157 if (!status)
2159 DWORD len;
2161 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2162 if (len >= *val_count)
2164 status = STATUS_BUFFER_OVERFLOW;
2165 if (*val_count)
2167 len = *val_count - 1;
2168 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2169 value[len] = 0;
2172 else
2174 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2175 value[len] = 0;
2176 *val_count = len;
2180 if (type) *type = info->Type;
2181 if (count) *count = info->DataLength;
2183 done:
2184 if (buf_ptr != buffer) heap_free( buf_ptr );
2185 return RtlNtStatusToDosError(status);
2188 /******************************************************************************
2189 * RegDeleteValueW [ADVAPI32.@]
2191 * See RegDeleteValueA.
2193 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2195 return RegDeleteKeyValueW( hkey, NULL, name );
2198 /******************************************************************************
2199 * RegDeleteValueA [ADVAPI32.@]
2201 * Delete a value from the registry.
2203 * PARAMS
2204 * hkey [I] Registry handle of the key holding the value
2205 * name [I] Name of the value under hkey to delete
2207 * RETURNS
2208 * Success: ERROR_SUCCESS
2209 * Failure: nonzero error code from Winerror.h
2211 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2213 return RegDeleteKeyValueA( hkey, NULL, name );
2216 /******************************************************************************
2217 * RegDeleteKeyValueW [ADVAPI32.@]
2219 LONG WINAPI RegDeleteKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name )
2221 UNICODE_STRING nameW;
2222 HKEY hsubkey = 0;
2223 LONG ret;
2225 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2227 if (subkey)
2229 if ((ret = RegOpenKeyExW( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey )))
2230 return ret;
2231 hkey = hsubkey;
2234 RtlInitUnicodeString( &nameW, name );
2235 ret = RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2236 if (hsubkey) RegCloseKey( hsubkey );
2237 return ret;
2240 /******************************************************************************
2241 * RegDeleteKeyValueA [ADVAPI32.@]
2243 LONG WINAPI RegDeleteKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name )
2245 UNICODE_STRING nameW;
2246 HKEY hsubkey = 0;
2247 ANSI_STRING nameA;
2248 NTSTATUS status;
2250 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2252 if (subkey)
2254 LONG ret = RegOpenKeyExA( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey );
2255 if (ret)
2256 return ret;
2257 hkey = hsubkey;
2260 RtlInitAnsiString( &nameA, name );
2261 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2263 status = NtDeleteValueKey( hkey, &nameW );
2264 RtlFreeUnicodeString( &nameW );
2267 if (hsubkey) RegCloseKey( hsubkey );
2268 return RtlNtStatusToDosError( status );
2271 /******************************************************************************
2272 * RegLoadKeyW [ADVAPI32.@]
2274 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2275 * registration information from a specified file into that subkey.
2277 * PARAMS
2278 * hkey [I] Handle of open key
2279 * subkey [I] Address of name of subkey
2280 * filename [I] Address of filename for registry information
2282 * RETURNS
2283 * Success: ERROR_SUCCESS
2284 * Failure: nonzero error code from Winerror.h
2286 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2288 OBJECT_ATTRIBUTES destkey, file;
2289 UNICODE_STRING subkeyW, filenameW;
2290 NTSTATUS status;
2292 if (!(hkey = get_special_root_hkey(hkey, 0))) return ERROR_INVALID_HANDLE;
2294 destkey.Length = sizeof(destkey);
2295 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2296 destkey.ObjectName = &subkeyW; /* name of the key */
2297 destkey.Attributes = 0;
2298 destkey.SecurityDescriptor = NULL;
2299 destkey.SecurityQualityOfService = NULL;
2300 RtlInitUnicodeString(&subkeyW, subkey);
2302 file.Length = sizeof(file);
2303 file.RootDirectory = NULL;
2304 file.ObjectName = &filenameW; /* file containing the hive */
2305 file.Attributes = OBJ_CASE_INSENSITIVE;
2306 file.SecurityDescriptor = NULL;
2307 file.SecurityQualityOfService = NULL;
2308 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2310 status = NtLoadKey(&destkey, &file);
2311 RtlFreeUnicodeString(&filenameW);
2312 return RtlNtStatusToDosError( status );
2316 /******************************************************************************
2317 * RegLoadKeyA [ADVAPI32.@]
2319 * See RegLoadKeyW.
2321 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2323 UNICODE_STRING subkeyW, filenameW;
2324 STRING subkeyA, filenameA;
2325 NTSTATUS status;
2326 LONG ret;
2328 RtlInitAnsiString(&subkeyA, subkey);
2329 RtlInitAnsiString(&filenameA, filename);
2331 RtlInitUnicodeString(&subkeyW, NULL);
2332 RtlInitUnicodeString(&filenameW, NULL);
2333 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2334 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2336 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2338 else ret = RtlNtStatusToDosError(status);
2339 RtlFreeUnicodeString(&subkeyW);
2340 RtlFreeUnicodeString(&filenameW);
2341 return ret;
2345 /******************************************************************************
2346 * RegSaveKeyW [ADVAPI32.@]
2348 * Save a key and all of its subkeys and values to a new file in the standard format.
2350 * PARAMS
2351 * hkey [I] Handle of key where save begins
2352 * lpFile [I] Address of filename to save to
2353 * sa [I] Address of security structure
2355 * RETURNS
2356 * Success: ERROR_SUCCESS
2357 * Failure: nonzero error code from Winerror.h
2359 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2361 static const WCHAR format[] =
2362 {'r','e','g','%','0','4','x','.','t','m','p',0};
2363 WCHAR buffer[MAX_PATH];
2364 int count = 0;
2365 LPWSTR nameW;
2366 DWORD ret, err;
2367 HANDLE handle;
2369 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2371 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2372 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2374 err = GetLastError();
2375 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2377 for (;;)
2379 snprintfW( nameW, 16, format, count++ );
2380 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2381 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2382 if (handle != INVALID_HANDLE_VALUE) break;
2383 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2385 /* Something gone haywire ? Please report if this happens abnormally */
2386 if (count >= 100)
2387 MESSAGE("Wow, we are already fiddling with a temp file %s with an ordinal as high as %d !\nYou might want to delete all corresponding temp files in that directory.\n", debugstr_w(buffer), count);
2390 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2392 CloseHandle( handle );
2393 if (!ret)
2395 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2397 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2398 debugstr_w(file) );
2399 ret = GetLastError();
2402 if (ret) DeleteFileW( buffer );
2404 done:
2405 SetLastError( err ); /* restore last error code */
2406 return ret;
2410 /******************************************************************************
2411 * RegSaveKeyA [ADVAPI32.@]
2413 * See RegSaveKeyW.
2415 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2417 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2418 NTSTATUS status;
2419 STRING fileA;
2421 RtlInitAnsiString(&fileA, file);
2422 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2423 return RtlNtStatusToDosError( status );
2424 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2428 /******************************************************************************
2429 * RegRestoreKeyW [ADVAPI32.@]
2431 * Read the registry information from a file and copy it over a key.
2433 * PARAMS
2434 * hkey [I] Handle of key where restore begins
2435 * lpFile [I] Address of filename containing saved tree
2436 * dwFlags [I] Optional flags
2438 * RETURNS
2439 * Success: ERROR_SUCCESS
2440 * Failure: nonzero error code from Winerror.h
2442 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2444 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2446 /* It seems to do this check before the hkey check */
2447 if (!lpFile || !*lpFile)
2448 return ERROR_INVALID_PARAMETER;
2450 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2452 /* Check for file existence */
2454 return ERROR_SUCCESS;
2458 /******************************************************************************
2459 * RegRestoreKeyA [ADVAPI32.@]
2461 * See RegRestoreKeyW.
2463 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2465 UNICODE_STRING lpFileW;
2466 LONG ret;
2468 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2469 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2470 RtlFreeUnicodeString( &lpFileW );
2471 return ret;
2475 /******************************************************************************
2476 * RegUnLoadKeyW [ADVAPI32.@]
2478 * Unload a registry key and its subkeys from the registry.
2480 * PARAMS
2481 * hkey [I] Handle of open key
2482 * lpSubKey [I] Address of name of subkey to unload
2484 * RETURNS
2485 * Success: ERROR_SUCCESS
2486 * Failure: nonzero error code from Winerror.h
2488 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2490 DWORD ret;
2491 HKEY shkey;
2492 OBJECT_ATTRIBUTES attr;
2493 UNICODE_STRING subkey;
2495 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2497 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2498 if( ret )
2499 return ERROR_INVALID_PARAMETER;
2501 RtlInitUnicodeString(&subkey, lpSubKey);
2502 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2503 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2505 RegCloseKey(shkey);
2507 return ret;
2511 /******************************************************************************
2512 * RegUnLoadKeyA [ADVAPI32.@]
2514 * See RegUnLoadKeyW.
2516 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2518 UNICODE_STRING lpSubKeyW;
2519 LONG ret;
2521 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2522 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2523 RtlFreeUnicodeString( &lpSubKeyW );
2524 return ret;
2528 /******************************************************************************
2529 * RegReplaceKeyW [ADVAPI32.@]
2531 * Replace the file backing a registry key and all its subkeys with another file.
2533 * PARAMS
2534 * hkey [I] Handle of open key
2535 * lpSubKey [I] Address of name of subkey
2536 * lpNewFile [I] Address of filename for file with new data
2537 * lpOldFile [I] Address of filename for backup file
2539 * RETURNS
2540 * Success: ERROR_SUCCESS
2541 * Failure: nonzero error code from Winerror.h
2543 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2544 LPCWSTR lpOldFile )
2546 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2547 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2548 return ERROR_SUCCESS;
2552 /******************************************************************************
2553 * RegReplaceKeyA [ADVAPI32.@]
2555 * See RegReplaceKeyW.
2557 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2558 LPCSTR lpOldFile )
2560 UNICODE_STRING lpSubKeyW;
2561 UNICODE_STRING lpNewFileW;
2562 UNICODE_STRING lpOldFileW;
2563 LONG ret;
2565 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2566 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2567 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2568 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2569 RtlFreeUnicodeString( &lpOldFileW );
2570 RtlFreeUnicodeString( &lpNewFileW );
2571 RtlFreeUnicodeString( &lpSubKeyW );
2572 return ret;
2576 /******************************************************************************
2577 * RegSetKeySecurity [ADVAPI32.@]
2579 * Set the security of an open registry key.
2581 * PARAMS
2582 * hkey [I] Open handle of key to set
2583 * SecurityInfo [I] Descriptor contents
2584 * pSecurityDesc [I] Address of descriptor for key
2586 * RETURNS
2587 * Success: ERROR_SUCCESS
2588 * Failure: nonzero error code from Winerror.h
2590 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2591 PSECURITY_DESCRIPTOR pSecurityDesc )
2593 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2595 /* It seems to perform this check before the hkey check */
2596 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2597 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2598 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2599 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2600 /* Param OK */
2601 } else
2602 return ERROR_INVALID_PARAMETER;
2604 if (!pSecurityDesc)
2605 return ERROR_INVALID_PARAMETER;
2607 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2609 return RtlNtStatusToDosError( NtSetSecurityObject( hkey, SecurityInfo, pSecurityDesc ) );
2613 /******************************************************************************
2614 * RegGetKeySecurity [ADVAPI32.@]
2616 * Get a copy of the security descriptor for a given registry key.
2618 * PARAMS
2619 * hkey [I] Open handle of key to set
2620 * SecurityInformation [I] Descriptor contents
2621 * pSecurityDescriptor [O] Address of descriptor for key
2622 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2624 * RETURNS
2625 * Success: ERROR_SUCCESS
2626 * Failure: Error code
2628 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2629 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2630 LPDWORD lpcbSecurityDescriptor )
2632 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2633 *lpcbSecurityDescriptor);
2635 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2637 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2638 SecurityInformation, pSecurityDescriptor,
2639 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2643 /******************************************************************************
2644 * RegFlushKey [ADVAPI32.@]
2646 * Immediately write a registry key to registry.
2648 * PARAMS
2649 * hkey [I] Handle of key to write
2651 * RETURNS
2652 * Success: ERROR_SUCCESS
2653 * Failure: Error code
2655 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2657 hkey = get_special_root_hkey( hkey, 0 );
2658 if (!hkey) return ERROR_INVALID_HANDLE;
2660 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2664 /******************************************************************************
2665 * RegConnectRegistryW [ADVAPI32.@]
2667 * Establish a connection to a predefined registry key on another computer.
2669 * PARAMS
2670 * lpMachineName [I] Address of name of remote computer
2671 * hHey [I] Predefined registry handle
2672 * phkResult [I] Address of buffer for remote registry handle
2674 * RETURNS
2675 * Success: ERROR_SUCCESS
2676 * Failure: nonzero error code from Winerror.h
2678 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2679 PHKEY phkResult )
2681 LONG ret;
2683 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName), hKey, phkResult);
2685 if (!lpMachineName || !*lpMachineName) {
2686 /* Use the local machine name */
2687 ret = RegOpenKeyW( hKey, NULL, phkResult );
2689 else {
2690 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2691 DWORD len = sizeof(compName) / sizeof(WCHAR);
2693 /* MSDN says lpMachineName must start with \\ : not so */
2694 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2695 lpMachineName += 2;
2696 if (GetComputerNameW(compName, &len))
2698 if (!strcmpiW(lpMachineName, compName))
2699 ret = RegOpenKeyW(hKey, NULL, phkResult);
2700 else
2702 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2703 ret = ERROR_BAD_NETPATH;
2706 else
2707 ret = GetLastError();
2709 return ret;
2713 /******************************************************************************
2714 * RegConnectRegistryA [ADVAPI32.@]
2716 * See RegConnectRegistryW.
2718 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2720 UNICODE_STRING machineW;
2721 LONG ret;
2723 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2724 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2725 RtlFreeUnicodeString( &machineW );
2726 return ret;
2730 /******************************************************************************
2731 * RegNotifyChangeKeyValue [ADVAPI32.@]
2733 * Notify the caller about changes to the attributes or contents of a registry key.
2735 * PARAMS
2736 * hkey [I] Handle of key to watch
2737 * fWatchSubTree [I] Flag for subkey notification
2738 * fdwNotifyFilter [I] Changes to be reported
2739 * hEvent [I] Handle of signaled event
2740 * fAsync [I] Flag for asynchronous reporting
2742 * RETURNS
2743 * Success: ERROR_SUCCESS
2744 * Failure: nonzero error code from Winerror.h
2746 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2747 DWORD fdwNotifyFilter, HANDLE hEvent,
2748 BOOL fAsync )
2750 NTSTATUS status;
2751 IO_STATUS_BLOCK iosb;
2753 hkey = get_special_root_hkey( hkey, 0 );
2754 if (!hkey) return ERROR_INVALID_HANDLE;
2756 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2757 hEvent, fAsync);
2759 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2760 fdwNotifyFilter, fWatchSubTree, NULL, 0,
2761 fAsync);
2763 if (status && status != STATUS_PENDING)
2764 return RtlNtStatusToDosError( status );
2766 return ERROR_SUCCESS;
2769 /******************************************************************************
2770 * RegOpenUserClassesRoot [ADVAPI32.@]
2772 * Open the HKEY_CLASSES_ROOT key for a user.
2774 * PARAMS
2775 * hToken [I] Handle of token representing the user
2776 * dwOptions [I] Reserved, must be 0
2777 * samDesired [I] Desired access rights
2778 * phkResult [O] Destination for the resulting key handle
2780 * RETURNS
2781 * Success: ERROR_SUCCESS
2782 * Failure: nonzero error code from Winerror.h
2784 * NOTES
2785 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2786 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2787 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2789 LSTATUS WINAPI RegOpenUserClassesRoot(
2790 HANDLE hToken,
2791 DWORD dwOptions,
2792 REGSAM samDesired,
2793 PHKEY phkResult
2796 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2798 *phkResult = HKEY_CLASSES_ROOT;
2799 return ERROR_SUCCESS;
2802 /******************************************************************************
2803 * load_string [Internal]
2805 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2806 * avoid importing user32, which is higher level than advapi32. Helper for
2807 * RegLoadMUIString.
2809 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2811 HGLOBAL hMemory;
2812 HRSRC hResource;
2813 WCHAR *pString;
2814 int idxString;
2816 /* Negative values have to be inverted. */
2817 if (HIWORD(resId) == 0xffff)
2818 resId = (UINT)(-((INT)resId));
2820 /* Load the resource into memory and get a pointer to it. */
2821 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2822 if (!hResource) return 0;
2823 hMemory = LoadResource(hModule, hResource);
2824 if (!hMemory) return 0;
2825 pString = LockResource(hMemory);
2827 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2828 idxString = resId & 0xf;
2829 while (idxString--) pString += *pString + 1;
2831 /* If no buffer is given, return length of the string. */
2832 if (!pwszBuffer) return *pString;
2834 /* Else copy over the string, respecting the buffer size. */
2835 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2836 if (cMaxChars >= 0) {
2837 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2838 pwszBuffer[cMaxChars] = '\0';
2841 return cMaxChars;
2844 /******************************************************************************
2845 * RegLoadMUIStringW [ADVAPI32.@]
2847 * Load the localized version of a string resource from some PE, respective
2848 * id and path of which are given in the registry value in the format
2849 * @[path]\dllname,-resourceId
2851 * PARAMS
2852 * hKey [I] Key, of which to load the string value from.
2853 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2854 * pszBuffer [O] Buffer to store the localized string in.
2855 * cbBuffer [I] Size of the destination buffer in bytes.
2856 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2857 * dwFlags [I] None supported yet.
2858 * pszBaseDir [I] Not supported yet.
2860 * RETURNS
2861 * Success: ERROR_SUCCESS,
2862 * Failure: nonzero error code from winerror.h
2864 * NOTES
2865 * This is an API of Windows Vista, which wasn't available at the time this code
2866 * was written. We have to check for the correct behaviour once it's available.
2868 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2869 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2871 DWORD dwValueType, cbData;
2872 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2873 LONG result;
2875 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2876 "dwFlags = %d, pwszBaseDir = %s)\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2877 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2879 /* Parameter sanity checks. */
2880 if (!hKey || !pwszBuffer)
2881 return ERROR_INVALID_PARAMETER;
2883 if (pwszBaseDir && *pwszBaseDir) {
2884 FIXME("BaseDir parameter not yet supported!\n");
2885 return ERROR_INVALID_PARAMETER;
2888 /* Check for value existence and correctness of its type, allocate a buffer and load it. */
2889 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2890 if (result != ERROR_SUCCESS) goto cleanup;
2891 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2892 result = ERROR_FILE_NOT_FOUND;
2893 goto cleanup;
2895 pwszTempBuffer = heap_alloc(cbData);
2896 if (!pwszTempBuffer) {
2897 result = ERROR_NOT_ENOUGH_MEMORY;
2898 goto cleanup;
2900 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2901 if (result != ERROR_SUCCESS) goto cleanup;
2903 /* Expand environment variables, if appropriate, or copy the original string over. */
2904 if (dwValueType == REG_EXPAND_SZ) {
2905 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2906 if (!cbData) goto cleanup;
2907 pwszExpandedBuffer = heap_alloc(cbData);
2908 if (!pwszExpandedBuffer) {
2909 result = ERROR_NOT_ENOUGH_MEMORY;
2910 goto cleanup;
2912 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2913 } else {
2914 pwszExpandedBuffer = heap_alloc(cbData);
2915 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2918 /* If the value references a resource based string, parse the value and load the string.
2919 * Else just copy over the original value. */
2920 result = ERROR_SUCCESS;
2921 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2922 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2923 } else {
2924 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2925 UINT uiStringId;
2926 HMODULE hModule;
2928 /* Format of the expanded value is 'path_to_dll,-resId' */
2929 if (!pComma || pComma[1] != '-') {
2930 result = ERROR_BADKEY;
2931 goto cleanup;
2934 uiStringId = atoiW(pComma+2);
2935 *pComma = '\0';
2937 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2938 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2939 result = ERROR_BADKEY;
2940 FreeLibrary(hModule);
2943 cleanup:
2944 heap_free(pwszTempBuffer);
2945 heap_free(pwszExpandedBuffer);
2946 return result;
2949 /******************************************************************************
2950 * RegLoadMUIStringA [ADVAPI32.@]
2952 * See RegLoadMUIStringW
2954 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2955 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2957 UNICODE_STRING valueW, baseDirW;
2958 WCHAR *pwszBuffer;
2959 DWORD cbData = cbBuffer * sizeof(WCHAR);
2960 LONG result;
2962 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2963 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2964 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2965 !(pwszBuffer = heap_alloc(cbData)))
2967 result = ERROR_NOT_ENOUGH_MEMORY;
2968 goto cleanup;
2971 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2972 baseDirW.Buffer);
2974 if (result == ERROR_SUCCESS) {
2975 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2976 if (pcbData)
2977 *pcbData = cbData;
2980 cleanup:
2981 heap_free(pwszBuffer);
2982 RtlFreeUnicodeString(&baseDirW);
2983 RtlFreeUnicodeString(&valueW);
2985 return result;
2988 /******************************************************************************
2989 * RegDisablePredefinedCache [ADVAPI32.@]
2991 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2993 * PARAMS
2994 * None.
2996 * RETURNS
2997 * Success: ERROR_SUCCESS
2998 * Failure: nonzero error code from Winerror.h
3000 * NOTES
3001 * This is useful for services that use impersonation.
3003 LSTATUS WINAPI RegDisablePredefinedCache(void)
3005 HKEY hkey_current_user;
3006 int idx = HandleToUlong(HKEY_CURRENT_USER) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
3008 /* prevent caching of future requests */
3009 hkcu_cache_disabled = TRUE;
3011 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
3013 if (hkey_current_user)
3014 NtClose( hkey_current_user );
3016 return ERROR_SUCCESS;
3020 /******************************************************************************
3021 * RegDeleteTreeW [ADVAPI32.@]
3024 LSTATUS WINAPI RegDeleteTreeW( HKEY hkey, const WCHAR *subkey )
3026 static const WCHAR emptyW[] = {0};
3027 DWORD name_size, max_name, max_subkey;
3028 WCHAR *name_buf = NULL;
3029 LONG ret;
3031 TRACE( "(%p, %s)\n", hkey, debugstr_w(subkey) );
3033 if (subkey && *subkey)
3035 ret = RegOpenKeyExW( hkey, subkey, 0, KEY_READ, &hkey );
3036 if (ret) return ret;
3039 ret = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, &max_subkey,
3040 NULL, NULL, &max_name, NULL, NULL, NULL );
3041 if (ret)
3042 goto cleanup;
3044 max_name = max( max_subkey, max_name ) + 1;
3045 if (!(name_buf = heap_alloc( max_name * sizeof(WCHAR) )))
3047 ret = ERROR_NOT_ENOUGH_MEMORY;
3048 goto cleanup;
3051 /* Recursively delete subkeys */
3052 for (;;)
3054 name_size = max_name;
3055 ret = RegEnumKeyExW( hkey, 0, name_buf, &name_size, NULL, NULL, NULL, NULL );
3056 if (ret == ERROR_NO_MORE_ITEMS) break;
3057 if (ret) goto cleanup;
3058 ret = RegDeleteTreeW( hkey, name_buf );
3059 if (ret) goto cleanup;
3062 /* Delete the key itself */
3063 if (subkey && *subkey)
3065 ret = RegDeleteKeyW( hkey, emptyW );
3066 goto cleanup;
3069 /* Delete values */
3070 for (;;)
3072 name_size = max_name;
3073 ret = RegEnumValueW( hkey, 0, name_buf, &name_size, NULL, NULL, NULL, NULL );
3074 if (ret == ERROR_NO_MORE_ITEMS) break;
3075 if (ret) goto cleanup;
3076 ret = RegDeleteValueW( hkey, name_buf );
3077 if (ret) goto cleanup;
3080 ret = ERROR_SUCCESS;
3082 cleanup:
3083 heap_free( name_buf );
3084 if (subkey && *subkey)
3085 RegCloseKey( hkey );
3086 return ret;
3090 /******************************************************************************
3091 * RegDeleteTreeA [ADVAPI32.@]
3094 LSTATUS WINAPI RegDeleteTreeA( HKEY hkey, const char *subkey )
3096 UNICODE_STRING subkeyW;
3097 LONG ret;
3099 if (subkey) RtlCreateUnicodeStringFromAsciiz( &subkeyW, subkey );
3100 else subkeyW.Buffer = NULL;
3101 ret = RegDeleteTreeW( hkey, subkeyW.Buffer );
3102 RtlFreeUnicodeString( &subkeyW );
3103 return ret;
3107 /******************************************************************************
3108 * RegCopyTreeW [ADVAPI32.@]
3111 LONG WINAPI RegCopyTreeW( HKEY hsrc, const WCHAR *subkey, HKEY hdst )
3113 DWORD name_size, max_name;
3114 DWORD value_size, max_value;
3115 DWORD max_subkey, i, type;
3116 WCHAR *name_buf = NULL;
3117 BYTE *value_buf = NULL;
3118 HKEY hkey;
3119 LONG ret;
3121 TRACE( "(%p, %s, %p)\n", hsrc, debugstr_w(subkey), hdst );
3123 if (subkey)
3125 ret = RegOpenKeyExW( hsrc, subkey, 0, KEY_READ, &hsrc );
3126 if (ret) return ret;
3129 ret = RegQueryInfoKeyW( hsrc, NULL, NULL, NULL, NULL, &max_subkey,
3130 NULL, NULL, &max_name, &max_value, NULL, NULL );
3131 if (ret)
3132 goto cleanup;
3134 max_name = max( max_subkey, max_name ) + 1;
3135 if (!(name_buf = heap_alloc( max_name * sizeof(WCHAR) )))
3137 ret = ERROR_NOT_ENOUGH_MEMORY;
3138 goto cleanup;
3141 if (!(value_buf = heap_alloc( max_value )))
3143 ret = ERROR_NOT_ENOUGH_MEMORY;
3144 goto cleanup;
3147 /* Copy values */
3148 for (i = 0;; i++)
3150 name_size = max_name;
3151 value_size = max_value;
3152 ret = RegEnumValueW( hsrc, i, name_buf, &name_size, NULL, &type, value_buf, &value_size );
3153 if (ret == ERROR_NO_MORE_ITEMS) break;
3154 if (ret) goto cleanup;
3155 ret = RegSetValueExW( hdst, name_buf, 0, type, value_buf, value_size );
3156 if (ret) goto cleanup;
3159 /* Recursively copy subkeys */
3160 for (i = 0;; i++)
3162 name_size = max_name;
3163 ret = RegEnumKeyExW( hsrc, i, name_buf, &name_size, NULL, NULL, NULL, NULL );
3164 if (ret == ERROR_NO_MORE_ITEMS) break;
3165 if (ret) goto cleanup;
3166 ret = RegCreateKeyExW( hdst, name_buf, 0, NULL, 0, KEY_WRITE, NULL, &hkey, NULL );
3167 if (ret) goto cleanup;
3168 ret = RegCopyTreeW( hsrc, name_buf, hkey );
3169 RegCloseKey( hkey );
3170 if (ret) goto cleanup;
3173 ret = ERROR_SUCCESS;
3175 cleanup:
3176 heap_free( name_buf );
3177 heap_free( value_buf );
3178 if (subkey)
3179 RegCloseKey( hsrc );
3180 return ret;
3184 /******************************************************************************
3185 * RegCopyTreeA [ADVAPI32.@]
3188 LONG WINAPI RegCopyTreeA( HKEY hsrc, const char *subkey, HKEY hdst )
3190 UNICODE_STRING subkeyW;
3191 LONG ret;
3193 if (subkey) RtlCreateUnicodeStringFromAsciiz( &subkeyW, subkey );
3194 else subkeyW.Buffer = NULL;
3195 ret = RegCopyTreeW( hsrc, subkeyW.Buffer, hdst );
3196 RtlFreeUnicodeString( &subkeyW );
3197 return ret;
3201 /******************************************************************************
3202 * RegDisableReflectionKey [ADVAPI32.@]
3205 LONG WINAPI RegDisableReflectionKey(HKEY base)
3207 FIXME("%p: stub\n", base);
3208 return ERROR_SUCCESS;