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
31 #define WIN32_NO_STATUS
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(reg);
44 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
45 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
46 #define NB_SPECIAL_ROOT_KEYS ((UINT_PTR)HKEY_SPECIAL_ROOT_LAST - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST + 1)
48 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
49 static BOOL hkcu_cache_disabled;
51 static const WCHAR name_CLASSES_ROOT[] =
52 {'M','a','c','h','i','n','e','\\',
53 'S','o','f','t','w','a','r','e','\\',
54 'C','l','a','s','s','e','s',0};
55 static const WCHAR name_LOCAL_MACHINE[] =
56 {'M','a','c','h','i','n','e',0};
57 static const WCHAR name_USERS[] =
59 static const WCHAR name_PERFORMANCE_DATA[] =
60 {'P','e','r','f','D','a','t','a',0};
61 static const WCHAR name_CURRENT_CONFIG[] =
62 {'M','a','c','h','i','n','e','\\',
63 'S','y','s','t','e','m','\\',
64 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
65 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
66 'C','u','r','r','e','n','t',0};
67 static const WCHAR name_DYN_DATA[] =
68 {'D','y','n','D','a','t','a',0};
70 static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] =
73 NULL, /* HKEY_CURRENT_USER is determined dynamically */
76 name_PERFORMANCE_DATA,
82 /* check if value type needs string conversion (Ansi<->Unicode) */
83 static inline int is_string( DWORD type )
85 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
88 /* check if current version is NT or Win95 */
89 static inline int is_version_nt(void)
91 return !(GetVersion() & 0x80000000);
94 /* wrapper for NtCreateKey that creates the key recursively if necessary */
95 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
96 const UNICODE_STRING *class, ULONG options, PULONG dispos )
98 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class, options, dispos );
100 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
102 DWORD attrs, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
104 while (i < len && attr->ObjectName->Buffer[i] != '\\') i++;
105 if (i == len) return status;
106 attrs = attr->Attributes;
107 attr->Attributes &= ~OBJ_OPENLINK;
111 attr->ObjectName->Length = i * sizeof(WCHAR);
112 status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class,
113 options & ~REG_OPTION_CREATE_LINK, dispos );
114 if (status) return status;
116 while (i < len && attr->ObjectName->Buffer[i] == '\\') i++;
117 while (i < len && attr->ObjectName->Buffer[i] != '\\') i++;
119 attr->Attributes = attrs;
120 attr->ObjectName->Length = len * sizeof(WCHAR);
121 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, class, options, dispos );
126 /* create one of the HKEY_* special root keys */
127 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
130 int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
132 if (hkey == HKEY_CURRENT_USER)
134 if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
135 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
137 /* don't cache the key in the table if caching is disabled */
138 if (hkcu_cache_disabled)
143 OBJECT_ATTRIBUTES attr;
146 attr.Length = sizeof(attr);
147 attr.RootDirectory = 0;
148 attr.ObjectName = &name;
150 attr.SecurityDescriptor = NULL;
151 attr.SecurityQualityOfService = NULL;
152 RtlInitUnicodeString( &name, root_key_names[idx] );
153 if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0;
154 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
157 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
160 NtClose( hkey ); /* somebody beat us to it */
164 /* map the hkey from special root to normal key if necessary */
165 static inline HKEY get_special_root_hkey( HKEY hkey )
169 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
171 if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
172 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED );
178 /******************************************************************************
179 * RegOverridePredefKey [ADVAPI32.@]
181 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
186 if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST))
187 return ERROR_INVALID_PARAMETER;
188 idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
192 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
193 GetCurrentProcess(), (HANDLE *)&override,
194 0, 0, DUPLICATE_SAME_ACCESS );
195 if (status) return RtlNtStatusToDosError( status );
198 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
199 if (old_key) NtClose( old_key );
200 return ERROR_SUCCESS;
204 /******************************************************************************
205 * RegCreateKeyExW [ADVAPI32.@]
207 * See RegCreateKeyExA.
209 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
210 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
211 PHKEY retkey, LPDWORD dispos )
213 OBJECT_ATTRIBUTES attr;
214 UNICODE_STRING nameW, classW;
216 if (reserved) return ERROR_INVALID_PARAMETER;
217 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
219 attr.Length = sizeof(attr);
220 attr.RootDirectory = hkey;
221 attr.ObjectName = &nameW;
223 attr.SecurityDescriptor = NULL;
224 attr.SecurityQualityOfService = NULL;
225 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
226 RtlInitUnicodeString( &nameW, name );
227 RtlInitUnicodeString( &classW, class );
229 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
233 /******************************************************************************
234 * RegCreateKeyExA [ADVAPI32.@]
236 * Open a registry key, creating it if it doesn't exist.
239 * hkey [I] Handle of the parent registry key
240 * name [I] Name of the new key to open or create
241 * reserved [I] Reserved, pass 0
242 * class [I] The object type of the new key
243 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
244 * access [I] Access level desired
245 * sa [I] Security attributes for the key
246 * retkey [O] Destination for the resulting handle
247 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
250 * Success: ERROR_SUCCESS.
251 * Failure: A standard Win32 error code. retkey remains untouched.
254 * MAXIMUM_ALLOWED in access mask not supported by server
256 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
257 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
258 PHKEY retkey, LPDWORD dispos )
260 OBJECT_ATTRIBUTES attr;
261 UNICODE_STRING classW;
262 ANSI_STRING nameA, classA;
265 if (reserved) return ERROR_INVALID_PARAMETER;
266 if (!is_version_nt())
268 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
269 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
271 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
273 attr.Length = sizeof(attr);
274 attr.RootDirectory = hkey;
275 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
277 attr.SecurityDescriptor = NULL;
278 attr.SecurityQualityOfService = NULL;
279 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
280 RtlInitAnsiString( &nameA, name );
281 RtlInitAnsiString( &classA, class );
283 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
286 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
288 status = create_key( retkey, access, &attr, &classW, options, dispos );
289 RtlFreeUnicodeString( &classW );
292 return RtlNtStatusToDosError( status );
296 /******************************************************************************
297 * RegCreateKeyW [ADVAPI32.@]
299 * Creates the specified reg key.
302 * hKey [I] Handle to an open key.
303 * lpSubKey [I] Name of a key that will be opened or created.
304 * phkResult [O] Receives a handle to the opened or created key.
307 * Success: ERROR_SUCCESS
308 * Failure: nonzero error code defined in Winerror.h
310 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
312 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
313 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
314 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
315 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
319 /******************************************************************************
320 * RegCreateKeyA [ADVAPI32.@]
324 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
326 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
327 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
332 /******************************************************************************
333 * RegOpenKeyExW [ADVAPI32.@]
337 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
339 OBJECT_ATTRIBUTES attr;
340 UNICODE_STRING nameW;
342 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
343 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
345 if (!retkey) return ERROR_INVALID_PARAMETER;
346 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
348 attr.Length = sizeof(attr);
349 attr.RootDirectory = hkey;
350 attr.ObjectName = &nameW;
352 attr.SecurityDescriptor = NULL;
353 attr.SecurityQualityOfService = NULL;
354 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
355 RtlInitUnicodeString( &nameW, name );
356 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE)retkey, access, &attr ) );
360 /******************************************************************************
361 * RegOpenKeyExA [ADVAPI32.@]
363 * Open a registry key.
366 * hkey [I] Handle of open key
367 * name [I] Name of subkey to open
368 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
369 * access [I] Security access mask
370 * retkey [O] Handle to open key
373 * Success: ERROR_SUCCESS
374 * Failure: A standard Win32 error code. retkey is set to 0.
377 * Unlike RegCreateKeyExA(), this function will not create the key if it
380 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
382 OBJECT_ATTRIBUTES attr;
386 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
389 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
390 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
393 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
395 attr.Length = sizeof(attr);
396 attr.RootDirectory = hkey;
397 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
399 attr.SecurityDescriptor = NULL;
400 attr.SecurityQualityOfService = NULL;
401 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
403 RtlInitAnsiString( &nameA, name );
404 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
407 status = NtOpenKey( (PHANDLE)retkey, access, &attr );
409 return RtlNtStatusToDosError( status );
413 /******************************************************************************
414 * RegOpenKeyW [ADVAPI32.@]
418 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
421 return ERROR_INVALID_PARAMETER;
426 return ERROR_SUCCESS;
428 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
432 /******************************************************************************
433 * RegOpenKeyA [ADVAPI32.@]
435 * Open a registry key.
438 * hkey [I] Handle of parent key to open the new key under
439 * name [I] Name of the key under hkey to open
440 * retkey [O] Destination for the resulting Handle
443 * Success: ERROR_SUCCESS
444 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
446 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
449 return ERROR_INVALID_PARAMETER;
454 return ERROR_SUCCESS;
456 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
460 /******************************************************************************
461 * RegOpenCurrentUser [ADVAPI32.@]
463 * Get a handle to the HKEY_CURRENT_USER key for the user
464 * the current thread is impersonating.
467 * access [I] Desired access rights to the key
468 * retkey [O] Handle to the opened key
471 * Success: ERROR_SUCCESS
472 * Failure: nonzero error code from Winerror.h
475 * This function is supposed to retrieve a handle to the
476 * HKEY_CURRENT_USER for the user the current thread is impersonating.
477 * Since Wine does not currently allow threads to impersonate other users,
478 * this stub should work fine.
480 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
482 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
487 /******************************************************************************
488 * RegEnumKeyExW [ADVAPI32.@]
490 * Enumerate subkeys of the specified open registry key.
493 * hkey [I] Handle to key to enumerate
494 * index [I] Index of subkey to enumerate
495 * name [O] Buffer for subkey name
496 * name_len [O] Size of subkey buffer
497 * reserved [I] Reserved
498 * class [O] Buffer for class string
499 * class_len [O] Size of class buffer
500 * ft [O] Time key last written to
503 * Success: ERROR_SUCCESS
504 * Failure: System error code. If there are no more subkeys available, the
505 * function returns ERROR_NO_MORE_ITEMS.
507 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
508 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
511 char buffer[256], *buf_ptr = buffer;
512 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
515 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
516 name_len ? *name_len : 0, reserved, class, class_len, ft );
518 if (reserved) return ERROR_INVALID_PARAMETER;
519 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
521 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
522 buffer, sizeof(buffer), &total_size );
524 while (status == STATUS_BUFFER_OVERFLOW)
526 /* retry with a dynamically allocated buffer */
527 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
528 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
529 return ERROR_NOT_ENOUGH_MEMORY;
530 info = (KEY_NODE_INFORMATION *)buf_ptr;
531 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
532 buf_ptr, total_size, &total_size );
537 DWORD len = info->NameLength / sizeof(WCHAR);
538 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
540 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
542 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
543 status = STATUS_BUFFER_OVERFLOW;
547 memcpy( name, info->Name, info->NameLength );
551 *class_len = cls_len;
554 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
561 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
562 return RtlNtStatusToDosError( status );
566 /******************************************************************************
567 * RegEnumKeyExA [ADVAPI32.@]
571 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
572 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
575 char buffer[256], *buf_ptr = buffer;
576 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
579 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
580 name_len ? *name_len : 0, reserved, class, class_len, ft );
582 if (reserved) return ERROR_INVALID_PARAMETER;
583 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
585 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
586 buffer, sizeof(buffer), &total_size );
588 while (status == STATUS_BUFFER_OVERFLOW)
590 /* retry with a dynamically allocated buffer */
591 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
592 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
593 return ERROR_NOT_ENOUGH_MEMORY;
594 info = (KEY_NODE_INFORMATION *)buf_ptr;
595 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
596 buf_ptr, total_size, &total_size );
603 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
604 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
606 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
608 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
609 status = STATUS_BUFFER_OVERFLOW;
613 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
617 *class_len = cls_len;
620 RtlUnicodeToMultiByteN( class, cls_len, NULL,
621 (WCHAR *)(buf_ptr + info->ClassOffset),
629 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
630 return RtlNtStatusToDosError( status );
634 /******************************************************************************
635 * RegEnumKeyW [ADVAPI32.@]
637 * Enumerates subkeys of the specified open reg key.
640 * hKey [I] Handle to an open key.
641 * dwIndex [I] Index of the subkey of hKey to retrieve.
642 * lpName [O] Name of the subkey.
643 * cchName [I] Size of lpName in TCHARS.
646 * Success: ERROR_SUCCESS
647 * Failure: system error code. If there are no more subkeys available, the
648 * function returns ERROR_NO_MORE_ITEMS.
650 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
652 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
656 /******************************************************************************
657 * RegEnumKeyA [ADVAPI32.@]
661 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
663 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
667 /******************************************************************************
668 * RegQueryInfoKeyW [ADVAPI32.@]
670 * Retrieves information about the specified registry key.
673 * hkey [I] Handle to key to query
674 * class [O] Buffer for class string
675 * class_len [O] Size of class string buffer
676 * reserved [I] Reserved
677 * subkeys [O] Buffer for number of subkeys
678 * max_subkey [O] Buffer for longest subkey name length
679 * max_class [O] Buffer for longest class string length
680 * values [O] Buffer for number of value entries
681 * max_value [O] Buffer for longest value name length
682 * max_data [O] Buffer for longest value data length
683 * security [O] Buffer for security descriptor length
684 * modif [O] Modification time
687 * Success: ERROR_SUCCESS
688 * Failure: system error code.
691 * - win95 allows class to be valid and class_len to be NULL
692 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
693 * - both allow class to be NULL and class_len to be NULL
694 * (it's hard to test validity, so test !NULL instead)
696 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
697 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
698 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
699 LPDWORD security, FILETIME *modif )
702 char buffer[256], *buf_ptr = buffer;
703 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
706 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
707 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
709 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
710 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
712 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
713 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
717 /* retry with a dynamically allocated buffer */
718 while (status == STATUS_BUFFER_OVERFLOW)
720 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
721 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
722 return ERROR_NOT_ENOUGH_MEMORY;
723 info = (KEY_FULL_INFORMATION *)buf_ptr;
724 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
727 if (status) goto done;
729 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
731 status = STATUS_BUFFER_OVERFLOW;
735 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
736 class[info->ClassLength/sizeof(WCHAR)] = 0;
739 else status = STATUS_SUCCESS;
741 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
742 if (subkeys) *subkeys = info->SubKeys;
743 if (max_subkey) *max_subkey = info->MaxNameLen;
744 if (max_class) *max_class = info->MaxClassLen;
745 if (values) *values = info->Values;
746 if (max_value) *max_value = info->MaxValueNameLen;
747 if (max_data) *max_data = info->MaxValueDataLen;
748 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
751 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
752 return RtlNtStatusToDosError( status );
756 /******************************************************************************
757 * RegQueryMultipleValuesA [ADVAPI32.@]
759 * Retrieves the type and data for a list of value names associated with a key.
762 * hKey [I] Handle to an open key.
763 * val_list [O] Array of VALENT structures that describes the entries.
764 * num_vals [I] Number of elements in val_list.
765 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
766 * ldwTotsize [I/O] Size of lpValueBuf.
769 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
770 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
773 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
774 LPSTR lpValueBuf, LPDWORD ldwTotsize )
777 DWORD maxBytes = *ldwTotsize;
779 LPSTR bufptr = lpValueBuf;
782 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
784 for(i=0; i < num_vals; ++i)
787 val_list[i].ve_valuelen=0;
788 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
789 if(status != ERROR_SUCCESS)
794 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
796 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
797 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
798 if(status != ERROR_SUCCESS)
803 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
805 bufptr += val_list[i].ve_valuelen;
808 *ldwTotsize += val_list[i].ve_valuelen;
810 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
814 /******************************************************************************
815 * RegQueryMultipleValuesW [ADVAPI32.@]
817 * See RegQueryMultipleValuesA.
819 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
820 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
823 DWORD maxBytes = *ldwTotsize;
825 LPSTR bufptr = (LPSTR)lpValueBuf;
828 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
830 for(i=0; i < num_vals; ++i)
832 val_list[i].ve_valuelen=0;
833 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
834 if(status != ERROR_SUCCESS)
839 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
841 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
842 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
843 if(status != ERROR_SUCCESS)
848 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
850 bufptr += val_list[i].ve_valuelen;
853 *ldwTotsize += val_list[i].ve_valuelen;
855 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
858 /******************************************************************************
859 * RegQueryInfoKeyA [ADVAPI32.@]
861 * Retrieves information about a registry key.
864 * hKey [I] Handle to an open key.
865 * lpClass [O] Class string of the key.
866 * lpcClass [I/O] size of lpClass.
867 * lpReserved [I] Reserved; must be NULL.
868 * lpcSubKeys [O] Number of subkeys contained by the key.
869 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
870 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
872 * lpcValues [O] Number of values associated with the key.
873 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
874 * lpcMaxValueLen [O] Longest data component among the key's values
875 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
876 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
879 * Success: ERROR_SUCCESS
880 * Failure: nonzero error code from Winerror.h
882 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
883 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
884 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
885 LPDWORD security, FILETIME *modif )
888 char buffer[256], *buf_ptr = buffer;
889 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
890 DWORD total_size, len;
892 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
893 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
895 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
896 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
898 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
899 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
901 if (class || class_len)
903 /* retry with a dynamically allocated buffer */
904 while (status == STATUS_BUFFER_OVERFLOW)
906 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
907 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
908 return ERROR_NOT_ENOUGH_MEMORY;
909 info = (KEY_FULL_INFORMATION *)buf_ptr;
910 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
913 if (status) goto done;
915 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
918 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
921 if (class && !status)
923 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
928 else status = STATUS_SUCCESS;
930 if (subkeys) *subkeys = info->SubKeys;
931 if (max_subkey) *max_subkey = info->MaxNameLen;
932 if (max_class) *max_class = info->MaxClassLen;
933 if (values) *values = info->Values;
934 if (max_value) *max_value = info->MaxValueNameLen;
935 if (max_data) *max_data = info->MaxValueDataLen;
936 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
939 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
940 return RtlNtStatusToDosError( status );
944 /******************************************************************************
945 * RegCloseKey [ADVAPI32.@]
947 * Close an open registry key.
950 * hkey [I] Handle of key to close
953 * Success: ERROR_SUCCESS
954 * Failure: Error code
956 LSTATUS WINAPI RegCloseKey( HKEY hkey )
958 if (!hkey) return ERROR_INVALID_HANDLE;
959 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
960 return RtlNtStatusToDosError( NtClose( hkey ) );
964 /******************************************************************************
965 * RegDeleteKeyExW [ADVAPI32.@]
967 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
972 if (!name) return ERROR_INVALID_PARAMETER;
974 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
976 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
977 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
979 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
982 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
987 /******************************************************************************
988 * RegDeleteKeyW [ADVAPI32.@]
992 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
994 return RegDeleteKeyExW( hkey, name, 0, 0 );
998 /******************************************************************************
999 * RegDeleteKeyExA [ADVAPI32.@]
1001 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1006 if (!name) return ERROR_INVALID_PARAMETER;
1008 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1010 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1011 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1013 if (!is_version_nt()) /* win95 does recursive key deletes */
1015 CHAR name[MAX_PATH];
1017 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
1019 if(RegDeleteKeyExA(tmp, name, access, reserved)) /* recurse */
1023 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1026 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1031 /******************************************************************************
1032 * RegDeleteKeyA [ADVAPI32.@]
1034 * Delete a registry key.
1037 * hkey [I] Handle to parent key containing the key to delete
1038 * name [I] Name of the key user hkey to delete
1042 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1043 * right. In reality, it opens a new handle with DELETE access.
1046 * Success: ERROR_SUCCESS
1047 * Failure: Error code
1049 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1051 return RegDeleteKeyExA( hkey, name, 0, 0 );
1056 /******************************************************************************
1057 * RegSetValueExW [ADVAPI32.@]
1059 * Set the data and contents of a registry value.
1062 * hkey [I] Handle of key to set value for
1063 * name [I] Name of value to set
1064 * reserved [I] Reserved, must be zero
1065 * type [I] Type of the value being set
1066 * data [I] The new contents of the value to set
1067 * count [I] Size of data
1070 * Success: ERROR_SUCCESS
1071 * Failure: Error code
1073 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1074 DWORD type, CONST BYTE *data, DWORD count )
1076 UNICODE_STRING nameW;
1078 /* no need for version check, not implemented on win9x anyway */
1079 if (count && is_string(type))
1081 LPCWSTR str = (LPCWSTR)data;
1082 /* if user forgot to count terminating null, add it (yes NT does this) */
1083 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1084 count += sizeof(WCHAR);
1086 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1088 RtlInitUnicodeString( &nameW, name );
1089 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1093 /******************************************************************************
1094 * RegSetValueExA [ADVAPI32.@]
1096 * See RegSetValueExW.
1099 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1100 * NT does definitely care (aj)
1102 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1103 CONST BYTE *data, DWORD count )
1106 UNICODE_STRING nameW;
1107 WCHAR *dataW = NULL;
1110 if (!is_version_nt()) /* win95 */
1114 if (!data) return ERROR_INVALID_PARAMETER;
1115 count = strlen((const char *)data) + 1;
1118 else if (count && is_string(type))
1120 /* if user forgot to count terminating null, add it (yes NT does this) */
1121 if (data[count-1] && !data[count]) count++;
1124 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1126 if (is_string( type )) /* need to convert to Unicode */
1129 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1130 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1131 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1133 data = (BYTE *)dataW;
1136 RtlInitAnsiString( &nameA, name );
1137 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1139 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1140 RtlFreeUnicodeString( &nameW );
1142 HeapFree( GetProcessHeap(), 0, dataW );
1143 return RtlNtStatusToDosError( status );
1147 /******************************************************************************
1148 * RegSetValueW [ADVAPI32.@]
1150 * Sets the data for the default or unnamed value of a reg key.
1153 * hKey [I] Handle to an open key.
1154 * lpSubKey [I] Name of a subkey of hKey.
1155 * dwType [I] Type of information to store.
1156 * lpData [I] String that contains the data to set for the default value.
1157 * cbData [I] Ignored.
1160 * Success: ERROR_SUCCESS
1161 * Failure: nonzero error code from Winerror.h
1163 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1168 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1170 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1172 if (name && name[0]) /* need to create the subkey */
1174 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1177 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1178 (strlenW( data ) + 1) * sizeof(WCHAR) );
1179 if (subkey != hkey) RegCloseKey( subkey );
1184 /******************************************************************************
1185 * RegSetValueA [ADVAPI32.@]
1189 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1194 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1196 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1198 if (name && name[0]) /* need to create the subkey */
1200 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1202 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1203 if (subkey != hkey) RegCloseKey( subkey );
1209 /******************************************************************************
1210 * RegQueryValueExW [ADVAPI32.@]
1212 * See RegQueryValueExA.
1214 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1215 LPBYTE data, LPDWORD count )
1218 UNICODE_STRING name_str;
1220 char buffer[256], *buf_ptr = buffer;
1221 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1222 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1224 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1225 hkey, debugstr_w(name), reserved, type, data, count,
1226 (count && data) ? *count : 0 );
1228 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1229 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1231 RtlInitUnicodeString( &name_str, name );
1233 if (data) total_size = min( sizeof(buffer), *count + info_size );
1236 total_size = info_size;
1237 if (count) *count = 0;
1240 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1241 buffer, total_size, &total_size );
1242 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1246 /* retry with a dynamically allocated buffer */
1247 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1249 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1250 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1251 return ERROR_NOT_ENOUGH_MEMORY;
1252 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1253 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1254 buf_ptr, total_size, &total_size );
1259 memcpy( data, buf_ptr + info_size, total_size - info_size );
1260 /* if the type is REG_SZ and data is not 0-terminated
1261 * and there is enough space in the buffer NT appends a \0 */
1262 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1264 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1265 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1268 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1270 else status = STATUS_SUCCESS;
1272 if (type) *type = info->Type;
1273 if (count) *count = total_size - info_size;
1276 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1277 return RtlNtStatusToDosError(status);
1281 /******************************************************************************
1282 * RegQueryValueExA [ADVAPI32.@]
1284 * Get the type and contents of a specified value under with a key.
1287 * hkey [I] Handle of the key to query
1288 * name [I] Name of value under hkey to query
1289 * reserved [I] Reserved - must be NULL
1290 * type [O] Destination for the value type, or NULL if not required
1291 * data [O] Destination for the values contents, or NULL if not required
1292 * count [I/O] Size of data, updated with the number of bytes returned
1295 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1296 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1297 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1298 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1301 * MSDN states that if data is too small it is partially filled. In reality
1302 * it remains untouched.
1304 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1305 LPBYTE data, LPDWORD count )
1309 UNICODE_STRING nameW;
1310 DWORD total_size, datalen = 0;
1311 char buffer[256], *buf_ptr = buffer;
1312 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1313 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1315 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1316 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1318 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1319 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1321 if (count) datalen = *count;
1322 if (!data && count) *count = 0;
1324 /* this matches Win9x behaviour - NT sets *type to a random value */
1325 if (type) *type = REG_NONE;
1327 RtlInitAnsiString( &nameA, name );
1328 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1329 return RtlNtStatusToDosError(status);
1331 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1332 buffer, sizeof(buffer), &total_size );
1333 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1335 /* we need to fetch the contents for a string type even if not requested,
1336 * because we need to compute the length of the ASCII string. */
1337 if (data || is_string(info->Type))
1339 /* retry with a dynamically allocated buffer */
1340 while (status == STATUS_BUFFER_OVERFLOW)
1342 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1343 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1345 status = STATUS_NO_MEMORY;
1348 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1349 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1350 buf_ptr, total_size, &total_size );
1353 if (status) goto done;
1355 if (is_string(info->Type))
1359 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1360 total_size - info_size );
1363 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1366 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1367 total_size - info_size );
1368 /* if the type is REG_SZ and data is not 0-terminated
1369 * and there is enough space in the buffer NT appends a \0 */
1370 if (len < datalen && data[len-1]) data[len] = 0;
1373 total_size = len + info_size;
1377 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1378 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1381 else status = STATUS_SUCCESS;
1383 if (type) *type = info->Type;
1384 if (count) *count = total_size - info_size;
1387 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1388 RtlFreeUnicodeString( &nameW );
1389 return RtlNtStatusToDosError(status);
1393 /******************************************************************************
1394 * RegQueryValueW [ADVAPI32.@]
1396 * Retrieves the data associated with the default or unnamed value of a key.
1399 * hkey [I] Handle to an open key.
1400 * name [I] Name of the subkey of hKey.
1401 * data [O] Receives the string associated with the default value
1403 * count [I/O] Size of lpValue in bytes.
1406 * Success: ERROR_SUCCESS
1407 * Failure: nonzero error code from Winerror.h
1409 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1414 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1416 if (name && name[0])
1418 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1420 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1421 if (subkey != hkey) RegCloseKey( subkey );
1422 if (ret == ERROR_FILE_NOT_FOUND)
1424 /* return empty string if default value not found */
1425 if (data) *data = 0;
1426 if (count) *count = sizeof(WCHAR);
1427 ret = ERROR_SUCCESS;
1433 /******************************************************************************
1434 * RegQueryValueA [ADVAPI32.@]
1436 * See RegQueryValueW.
1438 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1443 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1445 if (name && name[0])
1447 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1449 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1450 if (subkey != hkey) RegCloseKey( subkey );
1451 if (ret == ERROR_FILE_NOT_FOUND)
1453 /* return empty string if default value not found */
1454 if (data) *data = 0;
1455 if (count) *count = 1;
1456 ret = ERROR_SUCCESS;
1462 /******************************************************************************
1463 * ADVAPI_ApplyRestrictions [internal]
1465 * Helper function for RegGetValueA/W.
1467 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1468 DWORD cbData, PLONG ret )
1470 /* Check if the type is restricted by the passed flags */
1471 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1477 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1478 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1479 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1480 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1481 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1482 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1483 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1486 if (dwFlags & dwMask)
1488 /* Type is not restricted, check for size mismatch */
1489 if (dwType == REG_BINARY)
1493 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1495 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1498 if (cbExpect && cbData != cbExpect)
1499 *ret = ERROR_DATATYPE_MISMATCH;
1502 else *ret = ERROR_UNSUPPORTED_TYPE;
1507 /******************************************************************************
1508 * RegGetValueW [ADVAPI32.@]
1510 * Retrieves the type and data for a value name associated with a key,
1511 * optionally expanding its content and restricting its type.
1514 * hKey [I] Handle to an open key.
1515 * pszSubKey [I] Name of the subkey of hKey.
1516 * pszValue [I] Name of value under hKey/szSubKey to query.
1517 * dwFlags [I] Flags restricting the value type to retrieve.
1518 * pdwType [O] Destination for the values type, may be NULL.
1519 * pvData [O] Destination for the values content, may be NULL.
1520 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1521 * retrieve the whole content, including the trailing '\0'
1525 * Success: ERROR_SUCCESS
1526 * Failure: nonzero error code from Winerror.h
1529 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1530 * expanded and pdwType is set to REG_SZ instead.
1531 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1532 * without RRF_NOEXPAND is thus not allowed.
1533 * An exception is the case where RRF_RT_ANY is specified, because then
1534 * RRF_NOEXPAND is allowed.
1536 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1537 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1540 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1544 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1545 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1546 pvData, pcbData, cbData);
1548 if (pvData && !pcbData)
1549 return ERROR_INVALID_PARAMETER;
1550 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1551 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1552 return ERROR_INVALID_PARAMETER;
1554 if (pszSubKey && pszSubKey[0])
1556 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1557 if (ret != ERROR_SUCCESS) return ret;
1560 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1562 /* If we are going to expand we need to read in the whole the value even
1563 * if the passed buffer was too small as the expanded string might be
1564 * smaller than the unexpanded one and could fit into cbData bytes. */
1565 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1566 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1569 HeapFree(GetProcessHeap(), 0, pvBuf);
1571 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1574 ret = ERROR_NOT_ENOUGH_MEMORY;
1578 if (ret == ERROR_MORE_DATA || !pvData)
1579 ret = RegQueryValueExW(hKey, pszValue, NULL,
1580 &dwType, pvBuf, &cbData);
1583 /* Even if cbData was large enough we have to copy the
1584 * string since ExpandEnvironmentStrings can't handle
1585 * overlapping buffers. */
1586 CopyMemory(pvBuf, pvData, cbData);
1589 /* Both the type or the value itself could have been modified in
1590 * between so we have to keep retrying until the buffer is large
1591 * enough or we no longer have to expand the value. */
1592 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1594 if (ret == ERROR_SUCCESS)
1596 /* Recheck dwType in case it changed since the first call */
1597 if (dwType == REG_EXPAND_SZ)
1599 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1600 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1602 if(pvData && pcbData && cbData > *pcbData)
1603 ret = ERROR_MORE_DATA;
1606 CopyMemory(pvData, pvBuf, *pcbData);
1609 HeapFree(GetProcessHeap(), 0, pvBuf);
1612 if (pszSubKey && pszSubKey[0])
1615 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1617 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1618 ZeroMemory(pvData, *pcbData);
1620 if (pdwType) *pdwType = dwType;
1621 if (pcbData) *pcbData = cbData;
1627 /******************************************************************************
1628 * RegGetValueA [ADVAPI32.@]
1632 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1633 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1636 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1640 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1641 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1644 if (pvData && !pcbData)
1645 return ERROR_INVALID_PARAMETER;
1646 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1647 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1648 return ERROR_INVALID_PARAMETER;
1650 if (pszSubKey && pszSubKey[0])
1652 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1653 if (ret != ERROR_SUCCESS) return ret;
1656 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1658 /* If we are going to expand we need to read in the whole the value even
1659 * if the passed buffer was too small as the expanded string might be
1660 * smaller than the unexpanded one and could fit into cbData bytes. */
1661 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1662 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1665 HeapFree(GetProcessHeap(), 0, pvBuf);
1667 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1670 ret = ERROR_NOT_ENOUGH_MEMORY;
1674 if (ret == ERROR_MORE_DATA || !pvData)
1675 ret = RegQueryValueExA(hKey, pszValue, NULL,
1676 &dwType, pvBuf, &cbData);
1679 /* Even if cbData was large enough we have to copy the
1680 * string since ExpandEnvironmentStrings can't handle
1681 * overlapping buffers. */
1682 CopyMemory(pvBuf, pvData, cbData);
1685 /* Both the type or the value itself could have been modified in
1686 * between so we have to keep retrying until the buffer is large
1687 * enough or we no longer have to expand the value. */
1688 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1690 if (ret == ERROR_SUCCESS)
1692 /* Recheck dwType in case it changed since the first call */
1693 if (dwType == REG_EXPAND_SZ)
1695 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1696 pcbData ? *pcbData : 0);
1698 if(pvData && pcbData && cbData > *pcbData)
1699 ret = ERROR_MORE_DATA;
1702 CopyMemory(pvData, pvBuf, *pcbData);
1705 HeapFree(GetProcessHeap(), 0, pvBuf);
1708 if (pszSubKey && pszSubKey[0])
1711 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1713 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1714 ZeroMemory(pvData, *pcbData);
1716 if (pdwType) *pdwType = dwType;
1717 if (pcbData) *pcbData = cbData;
1723 /******************************************************************************
1724 * RegEnumValueW [ADVAPI32.@]
1726 * Enumerates the values for the specified open registry key.
1729 * hkey [I] Handle to key to query
1730 * index [I] Index of value to query
1731 * value [O] Value string
1732 * val_count [I/O] Size of value buffer (in wchars)
1733 * reserved [I] Reserved
1734 * type [O] Type code
1735 * data [O] Value data
1736 * count [I/O] Size of data buffer (in bytes)
1739 * Success: ERROR_SUCCESS
1740 * Failure: nonzero error code from Winerror.h
1743 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1744 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1748 char buffer[256], *buf_ptr = buffer;
1749 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1750 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1752 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1753 hkey, index, value, val_count, reserved, type, data, count );
1755 /* NT only checks count, not val_count */
1756 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1757 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1759 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1760 if (data) total_size += *count;
1761 total_size = min( sizeof(buffer), total_size );
1763 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1764 buffer, total_size, &total_size );
1765 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1769 /* retry with a dynamically allocated buffer */
1770 while (status == STATUS_BUFFER_OVERFLOW)
1772 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1773 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1774 return ERROR_NOT_ENOUGH_MEMORY;
1775 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1776 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1777 buf_ptr, total_size, &total_size );
1780 if (status) goto done;
1784 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1786 status = STATUS_BUFFER_OVERFLOW;
1789 memcpy( value, info->Name, info->NameLength );
1790 *val_count = info->NameLength / sizeof(WCHAR);
1791 value[*val_count] = 0;
1796 if (total_size - info->DataOffset > *count)
1798 status = STATUS_BUFFER_OVERFLOW;
1801 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1802 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1804 /* if the type is REG_SZ and data is not 0-terminated
1805 * and there is enough space in the buffer NT appends a \0 */
1806 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1807 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1811 else status = STATUS_SUCCESS;
1814 if (type) *type = info->Type;
1815 if (count) *count = info->DataLength;
1818 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1819 return RtlNtStatusToDosError(status);
1823 /******************************************************************************
1824 * RegEnumValueA [ADVAPI32.@]
1826 * See RegEnumValueW.
1828 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1829 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1833 char buffer[256], *buf_ptr = buffer;
1834 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1835 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1837 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1838 hkey, index, value, val_count, reserved, type, data, count );
1840 /* NT only checks count, not val_count */
1841 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1842 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1844 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1845 if (data) total_size += *count;
1846 total_size = min( sizeof(buffer), total_size );
1848 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1849 buffer, total_size, &total_size );
1850 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1852 /* we need to fetch the contents for a string type even if not requested,
1853 * because we need to compute the length of the ASCII string. */
1854 if (value || data || is_string(info->Type))
1856 /* retry with a dynamically allocated buffer */
1857 while (status == STATUS_BUFFER_OVERFLOW)
1859 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1860 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1861 return ERROR_NOT_ENOUGH_MEMORY;
1862 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1863 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1864 buf_ptr, total_size, &total_size );
1867 if (status) goto done;
1869 if (is_string(info->Type))
1872 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1873 total_size - info->DataOffset );
1876 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1879 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1880 total_size - info->DataOffset );
1881 /* if the type is REG_SZ and data is not 0-terminated
1882 * and there is enough space in the buffer NT appends a \0 */
1883 if (len < *count && data[len-1]) data[len] = 0;
1886 info->DataLength = len;
1890 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1891 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1894 if (value && !status)
1898 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1899 if (len >= *val_count)
1901 status = STATUS_BUFFER_OVERFLOW;
1904 len = *val_count - 1;
1905 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1911 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1917 else status = STATUS_SUCCESS;
1919 if (type) *type = info->Type;
1920 if (count) *count = info->DataLength;
1923 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1924 return RtlNtStatusToDosError(status);
1929 /******************************************************************************
1930 * RegDeleteValueW [ADVAPI32.@]
1932 * See RegDeleteValueA.
1934 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1936 UNICODE_STRING nameW;
1938 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1940 RtlInitUnicodeString( &nameW, name );
1941 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1945 /******************************************************************************
1946 * RegDeleteValueA [ADVAPI32.@]
1948 * Delete a value from the registry.
1951 * hkey [I] Registry handle of the key holding the value
1952 * name [I] Name of the value under hkey to delete
1955 * Success: ERROR_SUCCESS
1956 * Failure: nonzero error code from Winerror.h
1958 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1961 UNICODE_STRING nameW;
1964 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1966 RtlInitAnsiString( &nameA, name );
1967 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1969 status = NtDeleteValueKey( hkey, &nameW );
1970 RtlFreeUnicodeString( &nameW );
1972 return RtlNtStatusToDosError( status );
1976 /******************************************************************************
1977 * RegLoadKeyW [ADVAPI32.@]
1979 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1980 * registration information from a specified file into that subkey.
1983 * hkey [I] Handle of open key
1984 * subkey [I] Address of name of subkey
1985 * filename [I] Address of filename for registry information
1988 * Success: ERROR_SUCCESS
1989 * Failure: nonzero error code from Winerror.h
1991 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1993 OBJECT_ATTRIBUTES destkey, file;
1994 UNICODE_STRING subkeyW, filenameW;
1997 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
1999 destkey.Length = sizeof(destkey);
2000 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2001 destkey.ObjectName = &subkeyW; /* name of the key */
2002 destkey.Attributes = 0;
2003 destkey.SecurityDescriptor = NULL;
2004 destkey.SecurityQualityOfService = NULL;
2005 RtlInitUnicodeString(&subkeyW, subkey);
2007 file.Length = sizeof(file);
2008 file.RootDirectory = NULL;
2009 file.ObjectName = &filenameW; /* file containing the hive */
2010 file.Attributes = OBJ_CASE_INSENSITIVE;
2011 file.SecurityDescriptor = NULL;
2012 file.SecurityQualityOfService = NULL;
2013 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2015 status = NtLoadKey(&destkey, &file);
2016 RtlFreeUnicodeString(&filenameW);
2017 return RtlNtStatusToDosError( status );
2021 /******************************************************************************
2022 * RegLoadKeyA [ADVAPI32.@]
2026 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2028 UNICODE_STRING subkeyW, filenameW;
2029 STRING subkeyA, filenameA;
2033 RtlInitAnsiString(&subkeyA, subkey);
2034 RtlInitAnsiString(&filenameA, filename);
2036 RtlInitUnicodeString(&subkeyW, NULL);
2037 RtlInitUnicodeString(&filenameW, NULL);
2038 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2039 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2041 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2043 else ret = RtlNtStatusToDosError(status);
2044 RtlFreeUnicodeString(&subkeyW);
2045 RtlFreeUnicodeString(&filenameW);
2050 /******************************************************************************
2051 * RegSaveKeyW [ADVAPI32.@]
2053 * Save a key and all of its subkeys and values to a new file in the standard format.
2056 * hkey [I] Handle of key where save begins
2057 * lpFile [I] Address of filename to save to
2058 * sa [I] Address of security structure
2061 * Success: ERROR_SUCCESS
2062 * Failure: nonzero error code from Winerror.h
2064 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2066 static const WCHAR format[] =
2067 {'r','e','g','%','0','4','x','.','t','m','p',0};
2068 WCHAR buffer[MAX_PATH];
2074 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2076 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2077 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2079 err = GetLastError();
2080 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2084 snprintfW( nameW, 16, format, count++ );
2085 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2086 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2087 if (handle != INVALID_HANDLE_VALUE) break;
2088 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2090 /* Something gone haywire ? Please report if this happens abnormally */
2092 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);
2095 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2097 CloseHandle( handle );
2100 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2102 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2104 ret = GetLastError();
2107 if (ret) DeleteFileW( buffer );
2110 SetLastError( err ); /* restore last error code */
2115 /******************************************************************************
2116 * RegSaveKeyA [ADVAPI32.@]
2120 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2122 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2126 RtlInitAnsiString(&fileA, file);
2127 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2128 return RtlNtStatusToDosError( status );
2129 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2133 /******************************************************************************
2134 * RegRestoreKeyW [ADVAPI32.@]
2136 * Read the registry information from a file and copy it over a key.
2139 * hkey [I] Handle of key where restore begins
2140 * lpFile [I] Address of filename containing saved tree
2141 * dwFlags [I] Optional flags
2144 * Success: ERROR_SUCCESS
2145 * Failure: nonzero error code from Winerror.h
2147 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2149 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2151 /* It seems to do this check before the hkey check */
2152 if (!lpFile || !*lpFile)
2153 return ERROR_INVALID_PARAMETER;
2155 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2157 /* Check for file existence */
2159 return ERROR_SUCCESS;
2163 /******************************************************************************
2164 * RegRestoreKeyA [ADVAPI32.@]
2166 * See RegRestoreKeyW.
2168 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2170 UNICODE_STRING lpFileW;
2173 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2174 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2175 RtlFreeUnicodeString( &lpFileW );
2180 /******************************************************************************
2181 * RegUnLoadKeyW [ADVAPI32.@]
2183 * Unload a registry key and its subkeys from the registry.
2186 * hkey [I] Handle of open key
2187 * lpSubKey [I] Address of name of subkey to unload
2190 * Success: ERROR_SUCCESS
2191 * Failure: nonzero error code from Winerror.h
2193 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2197 OBJECT_ATTRIBUTES attr;
2198 UNICODE_STRING subkey;
2200 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2202 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2204 return ERROR_INVALID_PARAMETER;
2206 RtlInitUnicodeString(&subkey, lpSubKey);
2207 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2208 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2216 /******************************************************************************
2217 * RegUnLoadKeyA [ADVAPI32.@]
2219 * See RegUnLoadKeyW.
2221 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2223 UNICODE_STRING lpSubKeyW;
2226 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2227 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2228 RtlFreeUnicodeString( &lpSubKeyW );
2233 /******************************************************************************
2234 * RegReplaceKeyW [ADVAPI32.@]
2236 * Replace the file backing a registry key and all its subkeys with another file.
2239 * hkey [I] Handle of open key
2240 * lpSubKey [I] Address of name of subkey
2241 * lpNewFile [I] Address of filename for file with new data
2242 * lpOldFile [I] Address of filename for backup file
2245 * Success: ERROR_SUCCESS
2246 * Failure: nonzero error code from Winerror.h
2248 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2251 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2252 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2253 return ERROR_SUCCESS;
2257 /******************************************************************************
2258 * RegReplaceKeyA [ADVAPI32.@]
2260 * See RegReplaceKeyW.
2262 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2265 UNICODE_STRING lpSubKeyW;
2266 UNICODE_STRING lpNewFileW;
2267 UNICODE_STRING lpOldFileW;
2270 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2271 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2272 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2273 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2274 RtlFreeUnicodeString( &lpOldFileW );
2275 RtlFreeUnicodeString( &lpNewFileW );
2276 RtlFreeUnicodeString( &lpSubKeyW );
2281 /******************************************************************************
2282 * RegSetKeySecurity [ADVAPI32.@]
2284 * Set the security of an open registry key.
2287 * hkey [I] Open handle of key to set
2288 * SecurityInfo [I] Descriptor contents
2289 * pSecurityDesc [I] Address of descriptor for key
2292 * Success: ERROR_SUCCESS
2293 * Failure: nonzero error code from Winerror.h
2295 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2296 PSECURITY_DESCRIPTOR pSecurityDesc )
2298 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2300 /* It seems to perform this check before the hkey check */
2301 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2302 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2303 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2304 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2307 return ERROR_INVALID_PARAMETER;
2310 return ERROR_INVALID_PARAMETER;
2312 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2314 return ERROR_SUCCESS;
2318 /******************************************************************************
2319 * RegGetKeySecurity [ADVAPI32.@]
2321 * Get a copy of the security descriptor for a given registry key.
2324 * hkey [I] Open handle of key to set
2325 * SecurityInformation [I] Descriptor contents
2326 * pSecurityDescriptor [O] Address of descriptor for key
2327 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2330 * Success: ERROR_SUCCESS
2331 * Failure: Error code
2333 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2334 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2335 LPDWORD lpcbSecurityDescriptor )
2337 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2338 *lpcbSecurityDescriptor);
2340 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2342 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2343 SecurityInformation, pSecurityDescriptor,
2344 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2348 /******************************************************************************
2349 * RegFlushKey [ADVAPI32.@]
2351 * Immediately write a registry key to registry.
2354 * hkey [I] Handle of key to write
2357 * Success: ERROR_SUCCESS
2358 * Failure: Error code
2360 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2362 hkey = get_special_root_hkey( hkey );
2363 if (!hkey) return ERROR_INVALID_HANDLE;
2365 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2369 /******************************************************************************
2370 * RegConnectRegistryW [ADVAPI32.@]
2372 * Establish a connection to a predefined registry key on another computer.
2375 * lpMachineName [I] Address of name of remote computer
2376 * hHey [I] Predefined registry handle
2377 * phkResult [I] Address of buffer for remote registry handle
2380 * Success: ERROR_SUCCESS
2381 * Failure: nonzero error code from Winerror.h
2383 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2388 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2390 if (!lpMachineName || !*lpMachineName) {
2391 /* Use the local machine name */
2392 ret = RegOpenKeyW( hKey, NULL, phkResult );
2395 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2396 DWORD len = sizeof(compName) / sizeof(WCHAR);
2398 /* MSDN says lpMachineName must start with \\ : not so */
2399 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2401 if (GetComputerNameW(compName, &len))
2403 if (!strcmpiW(lpMachineName, compName))
2404 ret = RegOpenKeyW(hKey, NULL, phkResult);
2407 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2408 ret = ERROR_BAD_NETPATH;
2412 ret = GetLastError();
2418 /******************************************************************************
2419 * RegConnectRegistryA [ADVAPI32.@]
2421 * See RegConnectRegistryW.
2423 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2425 UNICODE_STRING machineW;
2428 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2429 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2430 RtlFreeUnicodeString( &machineW );
2435 /******************************************************************************
2436 * RegNotifyChangeKeyValue [ADVAPI32.@]
2438 * Notify the caller about changes to the attributes or contents of a registry key.
2441 * hkey [I] Handle of key to watch
2442 * fWatchSubTree [I] Flag for subkey notification
2443 * fdwNotifyFilter [I] Changes to be reported
2444 * hEvent [I] Handle of signaled event
2445 * fAsync [I] Flag for asynchronous reporting
2448 * Success: ERROR_SUCCESS
2449 * Failure: nonzero error code from Winerror.h
2451 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2452 DWORD fdwNotifyFilter, HANDLE hEvent,
2456 IO_STATUS_BLOCK iosb;
2458 hkey = get_special_root_hkey( hkey );
2459 if (!hkey) return ERROR_INVALID_HANDLE;
2461 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2464 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2465 fdwNotifyFilter, fAsync, NULL, 0,
2468 if (status && status != STATUS_TIMEOUT)
2469 return RtlNtStatusToDosError( status );
2471 return ERROR_SUCCESS;
2474 /******************************************************************************
2475 * RegOpenUserClassesRoot [ADVAPI32.@]
2477 * Open the HKEY_CLASSES_ROOT key for a user.
2480 * hToken [I] Handle of token representing the user
2481 * dwOptions [I] Reserved, must be 0
2482 * samDesired [I] Desired access rights
2483 * phkResult [O] Destination for the resulting key handle
2486 * Success: ERROR_SUCCESS
2487 * Failure: nonzero error code from Winerror.h
2490 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2491 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2492 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2494 LSTATUS WINAPI RegOpenUserClassesRoot(
2501 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2503 *phkResult = HKEY_CLASSES_ROOT;
2504 return ERROR_SUCCESS;
2507 /******************************************************************************
2508 * load_string [Internal]
2510 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2511 * avoid importing user32, which is higher level than advapi32. Helper for
2514 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2521 /* Negative values have to be inverted. */
2522 if (HIWORD(resId) == 0xffff)
2523 resId = (UINT)(-((INT)resId));
2525 /* Load the resource into memory and get a pointer to it. */
2526 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2527 if (!hResource) return 0;
2528 hMemory = LoadResource(hModule, hResource);
2529 if (!hMemory) return 0;
2530 pString = LockResource(hMemory);
2532 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2533 idxString = resId & 0xf;
2534 while (idxString--) pString += *pString + 1;
2536 /* If no buffer is given, return length of the string. */
2537 if (!pwszBuffer) return *pString;
2539 /* Else copy over the string, respecting the buffer size. */
2540 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2541 if (cMaxChars >= 0) {
2542 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2543 pwszBuffer[cMaxChars] = '\0';
2549 /******************************************************************************
2550 * RegLoadMUIStringW [ADVAPI32.@]
2552 * Load the localized version of a string resource from some PE, respective
2553 * id and path of which are given in the registry value in the format
2554 * @[path]\dllname,-resourceId
2557 * hKey [I] Key, of which to load the string value from.
2558 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2559 * pszBuffer [O] Buffer to store the localized string in.
2560 * cbBuffer [I] Size of the destination buffer in bytes.
2561 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2562 * dwFlags [I] None supported yet.
2563 * pszBaseDir [I] Not supported yet.
2566 * Success: ERROR_SUCCESS,
2567 * Failure: nonzero error code from winerror.h
2570 * This is an API of Windows Vista, which wasn't available at the time this code
2571 * was written. We have to check for the correct behaviour once it's available.
2573 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2574 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2576 DWORD dwValueType, cbData;
2577 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2580 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2581 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2582 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2584 /* Parameter sanity checks. */
2585 if (!hKey || !pwszBuffer)
2586 return ERROR_INVALID_PARAMETER;
2588 if (pwszBaseDir && *pwszBaseDir) {
2589 FIXME("BaseDir parameter not yet supported!\n");
2590 return ERROR_INVALID_PARAMETER;
2593 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2594 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2595 if (result != ERROR_SUCCESS) goto cleanup;
2596 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2597 result = ERROR_FILE_NOT_FOUND;
2600 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2601 if (!pwszTempBuffer) {
2602 result = ERROR_NOT_ENOUGH_MEMORY;
2605 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2606 if (result != ERROR_SUCCESS) goto cleanup;
2608 /* Expand environment variables, if appropriate, or copy the original string over. */
2609 if (dwValueType == REG_EXPAND_SZ) {
2610 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2611 if (!cbData) goto cleanup;
2612 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2613 if (!pwszExpandedBuffer) {
2614 result = ERROR_NOT_ENOUGH_MEMORY;
2617 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2619 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2620 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2623 /* If the value references a resource based string, parse the value and load the string.
2624 * Else just copy over the original value. */
2625 result = ERROR_SUCCESS;
2626 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2627 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2629 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2633 /* Format of the expanded value is 'path_to_dll,-resId' */
2634 if (!pComma || pComma[1] != '-') {
2635 result = ERROR_BADKEY;
2639 uiStringId = atoiW(pComma+2);
2642 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2643 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2644 result = ERROR_BADKEY;
2645 FreeLibrary(hModule);
2649 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2650 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2654 /******************************************************************************
2655 * RegLoadMUIStringA [ADVAPI32.@]
2657 * See RegLoadMUIStringW
2659 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2660 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2662 UNICODE_STRING valueW, baseDirW;
2664 DWORD cbData = cbBuffer * sizeof(WCHAR);
2667 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2668 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2669 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2670 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2672 result = ERROR_NOT_ENOUGH_MEMORY;
2676 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2679 if (result == ERROR_SUCCESS) {
2680 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2686 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2687 RtlFreeUnicodeString(&baseDirW);
2688 RtlFreeUnicodeString(&valueW);
2693 /******************************************************************************
2694 * RegDisablePredefinedCache [ADVAPI32.@]
2696 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2702 * Success: ERROR_SUCCESS
2703 * Failure: nonzero error code from Winerror.h
2706 * This is useful for services that use impersonation.
2708 LSTATUS WINAPI RegDisablePredefinedCache(void)
2710 HKEY hkey_current_user;
2711 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2713 /* prevent caching of future requests */
2714 hkcu_cache_disabled = TRUE;
2716 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2718 if (hkey_current_user)
2719 NtClose( hkey_current_user );
2721 return ERROR_SUCCESS;
2724 /******************************************************************************
2725 * RegDeleteTreeW [ADVAPI32.@]
2728 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2731 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2732 DWORD dwMaxLen, dwSize;
2733 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2734 HKEY hSubKey = hKey;
2736 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2740 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2741 if (ret) return ret;
2744 /* Get highest length for keys, values */
2745 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2746 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2747 if (ret) goto cleanup;
2751 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2752 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2754 /* Name too big: alloc a buffer for it */
2755 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2757 ret = ERROR_NOT_ENOUGH_MEMORY;
2763 /* Recursively delete all the subkeys */
2767 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2768 NULL, NULL, NULL)) break;
2770 ret = RegDeleteTreeW(hSubKey, lpszName);
2771 if (ret) goto cleanup;
2775 ret = RegDeleteKeyW(hKey, lpszSubKey);
2780 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2781 NULL, NULL, NULL, NULL)) break;
2783 ret = RegDeleteValueW(hKey, lpszName);
2784 if (ret) goto cleanup;
2788 /* Free buffer if allocated */
2789 if (lpszName != szNameBuf)
2790 HeapFree( GetProcessHeap(), 0, lpszName);
2792 RegCloseKey(hSubKey);
2796 /******************************************************************************
2797 * RegDeleteTreeA [ADVAPI32.@]
2800 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2803 UNICODE_STRING lpszSubKeyW;
2805 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2806 else lpszSubKeyW.Buffer = NULL;
2807 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2808 RtlFreeUnicodeString( &lpszSubKeyW );