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
47 static const WCHAR name_CLASSES_ROOT[] =
48 {'M','a','c','h','i','n','e','\\',
49 'S','o','f','t','w','a','r','e','\\',
50 'C','l','a','s','s','e','s',0};
51 static const WCHAR name_LOCAL_MACHINE[] =
52 {'M','a','c','h','i','n','e',0};
53 static const WCHAR name_USERS[] =
55 static const WCHAR name_PERFORMANCE_DATA[] =
56 {'P','e','r','f','D','a','t','a',0};
57 static const WCHAR name_CURRENT_CONFIG[] =
58 {'M','a','c','h','i','n','e','\\',
59 'S','y','s','t','e','m','\\',
60 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
61 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
62 'C','u','r','r','e','n','t',0};
63 static const WCHAR name_DYN_DATA[] =
64 {'D','y','n','D','a','t','a',0};
66 static const WCHAR * const root_key_names[] =
69 NULL, /* HKEY_CURRENT_USER is determined dynamically */
72 name_PERFORMANCE_DATA,
77 #define NB_SPECIAL_ROOT_KEYS (sizeof(root_key_names)/sizeof(root_key_names[0]))
79 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
80 static BOOL hkcu_cache_disabled;
82 static const int is_win64 = (sizeof(void *) > sizeof(int));
84 /* check if value type needs string conversion (Ansi<->Unicode) */
85 static inline int is_string( DWORD type )
87 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
90 /* check if current version is NT or Win95 */
91 static inline int is_version_nt(void)
93 return !(GetVersion() & 0x80000000);
96 static BOOL is_wow6432node( const UNICODE_STRING *name )
98 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e'};
100 return (name->Length == sizeof(wow6432nodeW) &&
101 !memicmpW( name->Buffer, wow6432nodeW, sizeof(wow6432nodeW)/sizeof(WCHAR) ));
104 /* open the Wow6432Node subkey of the specified key */
105 static HANDLE open_wow6432node( HANDLE key, const UNICODE_STRING *name )
107 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
108 OBJECT_ATTRIBUTES attr;
109 UNICODE_STRING nameW;
112 attr.Length = sizeof(attr);
113 attr.RootDirectory = key;
114 attr.ObjectName = &nameW;
116 attr.SecurityDescriptor = NULL;
117 attr.SecurityQualityOfService = NULL;
118 RtlInitUnicodeString( &nameW, wow6432nodeW );
119 if (NtOpenKey( &ret, MAXIMUM_ALLOWED, &attr )) ret = 0;
123 /* wrapper for NtCreateKey that creates the key recursively if necessary */
124 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
125 const UNICODE_STRING *class, ULONG options, PULONG dispos )
127 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
128 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
130 if (!force_wow32) status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class, options, dispos );
132 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
134 HANDLE subkey, root = attr->RootDirectory;
135 WCHAR *buffer = attr->ObjectName->Buffer;
136 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
139 while (i < len && buffer[i] != '\\') i++;
140 if (i == len && !force_wow32) return status;
142 attrs = attr->Attributes;
143 attr->Attributes &= ~OBJ_OPENLINK;
144 attr->ObjectName = &str;
148 str.Buffer = buffer + pos;
149 str.Length = (i - pos) * sizeof(WCHAR);
150 if (force_wow32 && pos)
152 if (is_wow6432node( &str )) force_wow32 = FALSE;
153 else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
155 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
156 attr->RootDirectory = subkey;
160 status = NtCreateKey( &subkey, access, attr, 0, class,
161 options & ~REG_OPTION_CREATE_LINK, dispos );
162 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
163 if (status) return status;
164 attr->RootDirectory = subkey;
165 while (i < len && buffer[i] == '\\') i++;
167 while (i < len && buffer[i] != '\\') i++;
169 str.Buffer = buffer + pos;
170 str.Length = (i - pos) * sizeof(WCHAR);
171 attr->Attributes = attrs;
172 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, class, options, dispos );
173 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
178 /* wrapper for NtOpenKey to handle Wow6432 nodes */
179 static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
182 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
183 HANDLE subkey, root = attr->RootDirectory;
184 WCHAR *buffer = attr->ObjectName->Buffer;
185 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
188 if (!force_wow32) return NtOpenKey( (HANDLE *)retkey, access, attr );
190 if (len && buffer[0] == '\\') return STATUS_OBJECT_PATH_INVALID;
191 while (i < len && buffer[i] != '\\') i++;
192 attrs = attr->Attributes;
193 attr->Attributes &= ~OBJ_OPENLINK;
194 attr->ObjectName = &str;
198 str.Buffer = buffer + pos;
199 str.Length = (i - pos) * sizeof(WCHAR);
200 if (force_wow32 && pos)
202 if (is_wow6432node( &str )) force_wow32 = FALSE;
203 else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
205 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
206 attr->RootDirectory = subkey;
210 status = NtOpenKey( &subkey, access, attr );
211 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
212 if (status) return status;
213 attr->RootDirectory = subkey;
214 while (i < len && buffer[i] == '\\') i++;
216 while (i < len && buffer[i] != '\\') i++;
218 str.Buffer = buffer + pos;
219 str.Length = (i - pos) * sizeof(WCHAR);
220 attr->Attributes = attrs;
221 status = NtOpenKey( (PHANDLE)retkey, access, attr );
222 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
227 /* create one of the HKEY_* special root keys */
228 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
231 int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
233 if (hkey == HKEY_CURRENT_USER)
235 if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
236 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
238 /* don't cache the key in the table if caching is disabled */
239 if (hkcu_cache_disabled)
244 OBJECT_ATTRIBUTES attr;
247 attr.Length = sizeof(attr);
248 attr.RootDirectory = 0;
249 attr.ObjectName = &name;
251 attr.SecurityDescriptor = NULL;
252 attr.SecurityQualityOfService = NULL;
253 RtlInitUnicodeString( &name, root_key_names[idx] );
254 if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0;
255 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
258 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
261 NtClose( hkey ); /* somebody beat us to it */
265 /* map the hkey from special root to normal key if necessary */
266 static inline HKEY get_special_root_hkey( HKEY hkey )
270 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
272 if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
273 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED );
279 /******************************************************************************
280 * RegOverridePredefKey [ADVAPI32.@]
282 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
287 if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST))
288 return ERROR_INVALID_PARAMETER;
289 idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
293 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
294 GetCurrentProcess(), (HANDLE *)&override,
295 0, 0, DUPLICATE_SAME_ACCESS );
296 if (status) return RtlNtStatusToDosError( status );
299 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
300 if (old_key) NtClose( old_key );
301 return ERROR_SUCCESS;
305 /******************************************************************************
306 * RegCreateKeyExW [ADVAPI32.@]
308 * See RegCreateKeyExA.
310 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
311 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
312 PHKEY retkey, LPDWORD dispos )
314 OBJECT_ATTRIBUTES attr;
315 UNICODE_STRING nameW, classW;
317 if (reserved) return ERROR_INVALID_PARAMETER;
318 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
320 attr.Length = sizeof(attr);
321 attr.RootDirectory = hkey;
322 attr.ObjectName = &nameW;
324 attr.SecurityDescriptor = NULL;
325 attr.SecurityQualityOfService = NULL;
326 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
327 RtlInitUnicodeString( &nameW, name );
328 RtlInitUnicodeString( &classW, class );
330 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
334 /******************************************************************************
335 * RegCreateKeyExA [ADVAPI32.@]
337 * Open a registry key, creating it if it doesn't exist.
340 * hkey [I] Handle of the parent registry key
341 * name [I] Name of the new key to open or create
342 * reserved [I] Reserved, pass 0
343 * class [I] The object type of the new key
344 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
345 * access [I] Access level desired
346 * sa [I] Security attributes for the key
347 * retkey [O] Destination for the resulting handle
348 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
351 * Success: ERROR_SUCCESS.
352 * Failure: A standard Win32 error code. retkey remains untouched.
355 * MAXIMUM_ALLOWED in access mask not supported by server
357 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
358 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
359 PHKEY retkey, LPDWORD dispos )
361 OBJECT_ATTRIBUTES attr;
362 UNICODE_STRING classW;
363 ANSI_STRING nameA, classA;
366 if (reserved) return ERROR_INVALID_PARAMETER;
367 if (!is_version_nt())
369 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
370 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
372 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
374 attr.Length = sizeof(attr);
375 attr.RootDirectory = hkey;
376 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
378 attr.SecurityDescriptor = NULL;
379 attr.SecurityQualityOfService = NULL;
380 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
381 RtlInitAnsiString( &nameA, name );
382 RtlInitAnsiString( &classA, class );
384 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
387 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
389 status = create_key( retkey, access, &attr, &classW, options, dispos );
390 RtlFreeUnicodeString( &classW );
393 return RtlNtStatusToDosError( status );
397 /******************************************************************************
398 * RegCreateKeyW [ADVAPI32.@]
400 * Creates the specified reg key.
403 * hKey [I] Handle to an open key.
404 * lpSubKey [I] Name of a key that will be opened or created.
405 * phkResult [O] Receives a handle to the opened or created key.
408 * Success: ERROR_SUCCESS
409 * Failure: nonzero error code defined in Winerror.h
411 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
413 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
414 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
415 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
416 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
420 /******************************************************************************
421 * RegCreateKeyA [ADVAPI32.@]
425 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
427 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
428 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
433 /******************************************************************************
434 * RegOpenKeyExW [ADVAPI32.@]
438 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
440 OBJECT_ATTRIBUTES attr;
441 UNICODE_STRING nameW;
443 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
444 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
446 if (!retkey) return ERROR_INVALID_PARAMETER;
447 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
449 attr.Length = sizeof(attr);
450 attr.RootDirectory = hkey;
451 attr.ObjectName = &nameW;
453 attr.SecurityDescriptor = NULL;
454 attr.SecurityQualityOfService = NULL;
455 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
456 RtlInitUnicodeString( &nameW, name );
457 return RtlNtStatusToDosError( open_key( retkey, access, &attr ) );
461 /******************************************************************************
462 * RegOpenKeyExA [ADVAPI32.@]
464 * Open a registry key.
467 * hkey [I] Handle of open key
468 * name [I] Name of subkey to open
469 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
470 * access [I] Security access mask
471 * retkey [O] Handle to open key
474 * Success: ERROR_SUCCESS
475 * Failure: A standard Win32 error code. retkey is set to 0.
478 * Unlike RegCreateKeyExA(), this function will not create the key if it
481 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
483 OBJECT_ATTRIBUTES attr;
487 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
490 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
491 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
494 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
496 attr.Length = sizeof(attr);
497 attr.RootDirectory = hkey;
498 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
500 attr.SecurityDescriptor = NULL;
501 attr.SecurityQualityOfService = NULL;
502 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
504 RtlInitAnsiString( &nameA, name );
505 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
508 status = open_key( retkey, access, &attr );
510 return RtlNtStatusToDosError( status );
514 /******************************************************************************
515 * RegOpenKeyW [ADVAPI32.@]
519 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
522 return ERROR_INVALID_PARAMETER;
527 return ERROR_SUCCESS;
529 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
533 /******************************************************************************
534 * RegOpenKeyA [ADVAPI32.@]
536 * Open a registry key.
539 * hkey [I] Handle of parent key to open the new key under
540 * name [I] Name of the key under hkey to open
541 * retkey [O] Destination for the resulting Handle
544 * Success: ERROR_SUCCESS
545 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
547 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
550 return ERROR_INVALID_PARAMETER;
555 return ERROR_SUCCESS;
557 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
561 /******************************************************************************
562 * RegOpenCurrentUser [ADVAPI32.@]
564 * Get a handle to the HKEY_CURRENT_USER key for the user
565 * the current thread is impersonating.
568 * access [I] Desired access rights to the key
569 * retkey [O] Handle to the opened key
572 * Success: ERROR_SUCCESS
573 * Failure: nonzero error code from Winerror.h
576 * This function is supposed to retrieve a handle to the
577 * HKEY_CURRENT_USER for the user the current thread is impersonating.
578 * Since Wine does not currently allow threads to impersonate other users,
579 * this stub should work fine.
581 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
583 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
588 /******************************************************************************
589 * RegEnumKeyExW [ADVAPI32.@]
591 * Enumerate subkeys of the specified open registry key.
594 * hkey [I] Handle to key to enumerate
595 * index [I] Index of subkey to enumerate
596 * name [O] Buffer for subkey name
597 * name_len [O] Size of subkey buffer
598 * reserved [I] Reserved
599 * class [O] Buffer for class string
600 * class_len [O] Size of class buffer
601 * ft [O] Time key last written to
604 * Success: ERROR_SUCCESS
605 * Failure: System error code. If there are no more subkeys available, the
606 * function returns ERROR_NO_MORE_ITEMS.
608 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
609 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
612 char buffer[256], *buf_ptr = buffer;
613 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
616 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
617 name_len ? *name_len : 0, reserved, class, class_len, ft );
619 if (reserved) return ERROR_INVALID_PARAMETER;
620 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
622 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
623 buffer, sizeof(buffer), &total_size );
625 while (status == STATUS_BUFFER_OVERFLOW)
627 /* retry with a dynamically allocated buffer */
628 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
629 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
630 return ERROR_NOT_ENOUGH_MEMORY;
631 info = (KEY_NODE_INFORMATION *)buf_ptr;
632 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
633 buf_ptr, total_size, &total_size );
638 DWORD len = info->NameLength / sizeof(WCHAR);
639 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
641 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
643 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
644 status = STATUS_BUFFER_OVERFLOW;
648 memcpy( name, info->Name, info->NameLength );
652 *class_len = cls_len;
655 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
662 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
663 return RtlNtStatusToDosError( status );
667 /******************************************************************************
668 * RegEnumKeyExA [ADVAPI32.@]
672 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
673 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
676 char buffer[256], *buf_ptr = buffer;
677 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
680 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
681 name_len ? *name_len : 0, reserved, class, class_len, ft );
683 if (reserved) return ERROR_INVALID_PARAMETER;
684 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
686 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
687 buffer, sizeof(buffer), &total_size );
689 while (status == STATUS_BUFFER_OVERFLOW)
691 /* retry with a dynamically allocated buffer */
692 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
693 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
694 return ERROR_NOT_ENOUGH_MEMORY;
695 info = (KEY_NODE_INFORMATION *)buf_ptr;
696 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
697 buf_ptr, total_size, &total_size );
704 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
705 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
707 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
709 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
710 status = STATUS_BUFFER_OVERFLOW;
714 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
718 *class_len = cls_len;
721 RtlUnicodeToMultiByteN( class, cls_len, NULL,
722 (WCHAR *)(buf_ptr + info->ClassOffset),
730 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
731 return RtlNtStatusToDosError( status );
735 /******************************************************************************
736 * RegEnumKeyW [ADVAPI32.@]
738 * Enumerates subkeys of the specified open reg key.
741 * hKey [I] Handle to an open key.
742 * dwIndex [I] Index of the subkey of hKey to retrieve.
743 * lpName [O] Name of the subkey.
744 * cchName [I] Size of lpName in TCHARS.
747 * Success: ERROR_SUCCESS
748 * Failure: system error code. If there are no more subkeys available, the
749 * function returns ERROR_NO_MORE_ITEMS.
751 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
753 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
757 /******************************************************************************
758 * RegEnumKeyA [ADVAPI32.@]
762 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
764 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
768 /******************************************************************************
769 * RegQueryInfoKeyW [ADVAPI32.@]
771 * Retrieves information about the specified registry key.
774 * hkey [I] Handle to key to query
775 * class [O] Buffer for class string
776 * class_len [O] Size of class string buffer
777 * reserved [I] Reserved
778 * subkeys [O] Buffer for number of subkeys
779 * max_subkey [O] Buffer for longest subkey name length
780 * max_class [O] Buffer for longest class string length
781 * values [O] Buffer for number of value entries
782 * max_value [O] Buffer for longest value name length
783 * max_data [O] Buffer for longest value data length
784 * security [O] Buffer for security descriptor length
785 * modif [O] Modification time
788 * Success: ERROR_SUCCESS
789 * Failure: system error code.
792 * - win95 allows class to be valid and class_len to be NULL
793 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
794 * - both allow class to be NULL and class_len to be NULL
795 * (it's hard to test validity, so test !NULL instead)
797 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
798 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
799 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
800 LPDWORD security, FILETIME *modif )
803 char buffer[256], *buf_ptr = buffer;
804 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
807 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
808 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
810 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
811 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
813 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
814 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
818 /* retry with a dynamically allocated buffer */
819 while (status == STATUS_BUFFER_OVERFLOW)
821 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
822 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
823 return ERROR_NOT_ENOUGH_MEMORY;
824 info = (KEY_FULL_INFORMATION *)buf_ptr;
825 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
828 if (status) goto done;
830 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
832 status = STATUS_BUFFER_OVERFLOW;
836 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
837 class[info->ClassLength/sizeof(WCHAR)] = 0;
840 else status = STATUS_SUCCESS;
842 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
843 if (subkeys) *subkeys = info->SubKeys;
844 if (max_subkey) *max_subkey = info->MaxNameLen;
845 if (max_class) *max_class = info->MaxClassLen;
846 if (values) *values = info->Values;
847 if (max_value) *max_value = info->MaxValueNameLen;
848 if (max_data) *max_data = info->MaxValueDataLen;
849 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
852 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
853 return RtlNtStatusToDosError( status );
857 /******************************************************************************
858 * RegQueryMultipleValuesA [ADVAPI32.@]
860 * Retrieves the type and data for a list of value names associated with a key.
863 * hKey [I] Handle to an open key.
864 * val_list [O] Array of VALENT structures that describes the entries.
865 * num_vals [I] Number of elements in val_list.
866 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
867 * ldwTotsize [I/O] Size of lpValueBuf.
870 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
871 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
874 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
875 LPSTR lpValueBuf, LPDWORD ldwTotsize )
878 DWORD maxBytes = *ldwTotsize;
880 LPSTR bufptr = lpValueBuf;
883 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
885 for(i=0; i < num_vals; ++i)
888 val_list[i].ve_valuelen=0;
889 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
890 if(status != ERROR_SUCCESS)
895 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
897 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
898 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
899 if(status != ERROR_SUCCESS)
904 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
906 bufptr += val_list[i].ve_valuelen;
909 *ldwTotsize += val_list[i].ve_valuelen;
911 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
915 /******************************************************************************
916 * RegQueryMultipleValuesW [ADVAPI32.@]
918 * See RegQueryMultipleValuesA.
920 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
921 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
924 DWORD maxBytes = *ldwTotsize;
926 LPSTR bufptr = (LPSTR)lpValueBuf;
929 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
931 for(i=0; i < num_vals; ++i)
933 val_list[i].ve_valuelen=0;
934 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
935 if(status != ERROR_SUCCESS)
940 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
942 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
943 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
944 if(status != ERROR_SUCCESS)
949 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
951 bufptr += val_list[i].ve_valuelen;
954 *ldwTotsize += val_list[i].ve_valuelen;
956 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
959 /******************************************************************************
960 * RegQueryInfoKeyA [ADVAPI32.@]
962 * Retrieves information about a registry key.
965 * hKey [I] Handle to an open key.
966 * lpClass [O] Class string of the key.
967 * lpcClass [I/O] size of lpClass.
968 * lpReserved [I] Reserved; must be NULL.
969 * lpcSubKeys [O] Number of subkeys contained by the key.
970 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
971 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
973 * lpcValues [O] Number of values associated with the key.
974 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
975 * lpcMaxValueLen [O] Longest data component among the key's values
976 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
977 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
980 * Success: ERROR_SUCCESS
981 * Failure: nonzero error code from Winerror.h
983 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
984 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
985 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
986 LPDWORD security, FILETIME *modif )
989 char buffer[256], *buf_ptr = buffer;
990 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
991 DWORD total_size, len;
993 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
994 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
996 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
997 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
999 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
1000 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1002 if (class || class_len)
1004 /* retry with a dynamically allocated buffer */
1005 while (status == STATUS_BUFFER_OVERFLOW)
1007 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1008 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1009 return ERROR_NOT_ENOUGH_MEMORY;
1010 info = (KEY_FULL_INFORMATION *)buf_ptr;
1011 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
1014 if (status) goto done;
1016 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
1019 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
1022 if (class && !status)
1024 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
1025 info->ClassLength );
1029 else status = STATUS_SUCCESS;
1031 if (subkeys) *subkeys = info->SubKeys;
1032 if (max_subkey) *max_subkey = info->MaxNameLen;
1033 if (max_class) *max_class = info->MaxClassLen;
1034 if (values) *values = info->Values;
1035 if (max_value) *max_value = info->MaxValueNameLen;
1036 if (max_data) *max_data = info->MaxValueDataLen;
1037 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
1040 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1041 return RtlNtStatusToDosError( status );
1045 /******************************************************************************
1046 * RegCloseKey [ADVAPI32.@]
1048 * Close an open registry key.
1051 * hkey [I] Handle of key to close
1054 * Success: ERROR_SUCCESS
1055 * Failure: Error code
1057 LSTATUS WINAPI RegCloseKey( HKEY hkey )
1059 if (!hkey) return ERROR_INVALID_HANDLE;
1060 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
1061 return RtlNtStatusToDosError( NtClose( hkey ) );
1065 /******************************************************************************
1066 * RegDeleteKeyExW [ADVAPI32.@]
1068 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
1073 if (!name) return ERROR_INVALID_PARAMETER;
1075 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1077 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1078 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
1080 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1083 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
1088 /******************************************************************************
1089 * RegDeleteKeyW [ADVAPI32.@]
1091 * See RegDeleteKeyA.
1093 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
1095 return RegDeleteKeyExW( hkey, name, 0, 0 );
1099 /******************************************************************************
1100 * RegDeleteKeyExA [ADVAPI32.@]
1102 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1107 if (!name) return ERROR_INVALID_PARAMETER;
1109 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1111 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1112 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1114 if (!is_version_nt()) /* win95 does recursive key deletes */
1116 CHAR name[MAX_PATH];
1118 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
1120 if(RegDeleteKeyExA(tmp, name, access, reserved)) /* recurse */
1124 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1127 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1132 /******************************************************************************
1133 * RegDeleteKeyA [ADVAPI32.@]
1135 * Delete a registry key.
1138 * hkey [I] Handle to parent key containing the key to delete
1139 * name [I] Name of the key user hkey to delete
1143 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1144 * right. In reality, it opens a new handle with DELETE access.
1147 * Success: ERROR_SUCCESS
1148 * Failure: Error code
1150 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1152 return RegDeleteKeyExA( hkey, name, 0, 0 );
1157 /******************************************************************************
1158 * RegSetValueExW [ADVAPI32.@]
1160 * Set the data and contents of a registry value.
1163 * hkey [I] Handle of key to set value for
1164 * name [I] Name of value to set
1165 * reserved [I] Reserved, must be zero
1166 * type [I] Type of the value being set
1167 * data [I] The new contents of the value to set
1168 * count [I] Size of data
1171 * Success: ERROR_SUCCESS
1172 * Failure: Error code
1174 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1175 DWORD type, CONST BYTE *data, DWORD count )
1177 UNICODE_STRING nameW;
1179 /* no need for version check, not implemented on win9x anyway */
1180 if (count && is_string(type))
1182 LPCWSTR str = (LPCWSTR)data;
1183 /* if user forgot to count terminating null, add it (yes NT does this) */
1184 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1185 count += sizeof(WCHAR);
1187 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1189 RtlInitUnicodeString( &nameW, name );
1190 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1194 /******************************************************************************
1195 * RegSetValueExA [ADVAPI32.@]
1197 * See RegSetValueExW.
1200 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1201 * NT does definitely care (aj)
1203 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1204 CONST BYTE *data, DWORD count )
1207 UNICODE_STRING nameW;
1208 WCHAR *dataW = NULL;
1211 if (!is_version_nt()) /* win95 */
1215 if (!data) return ERROR_INVALID_PARAMETER;
1216 count = strlen((const char *)data) + 1;
1219 else if (count && is_string(type))
1221 /* if user forgot to count terminating null, add it (yes NT does this) */
1222 if (data[count-1] && !data[count]) count++;
1225 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1227 if (is_string( type )) /* need to convert to Unicode */
1230 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1231 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1232 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1234 data = (BYTE *)dataW;
1237 RtlInitAnsiString( &nameA, name );
1238 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1240 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1241 RtlFreeUnicodeString( &nameW );
1243 HeapFree( GetProcessHeap(), 0, dataW );
1244 return RtlNtStatusToDosError( status );
1248 /******************************************************************************
1249 * RegSetValueW [ADVAPI32.@]
1251 * Sets the data for the default or unnamed value of a reg key.
1254 * hKey [I] Handle to an open key.
1255 * lpSubKey [I] Name of a subkey of hKey.
1256 * dwType [I] Type of information to store.
1257 * lpData [I] String that contains the data to set for the default value.
1258 * cbData [I] Ignored.
1261 * Success: ERROR_SUCCESS
1262 * Failure: nonzero error code from Winerror.h
1264 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1269 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1271 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1273 if (name && name[0]) /* need to create the subkey */
1275 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1278 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1279 (strlenW( data ) + 1) * sizeof(WCHAR) );
1280 if (subkey != hkey) RegCloseKey( subkey );
1285 /******************************************************************************
1286 * RegSetValueA [ADVAPI32.@]
1290 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1295 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1297 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1299 if (name && name[0]) /* need to create the subkey */
1301 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1303 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1304 if (subkey != hkey) RegCloseKey( subkey );
1310 /******************************************************************************
1311 * RegQueryValueExW [ADVAPI32.@]
1313 * See RegQueryValueExA.
1315 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1316 LPBYTE data, LPDWORD count )
1319 UNICODE_STRING name_str;
1321 char buffer[256], *buf_ptr = buffer;
1322 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1323 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1325 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1326 hkey, debugstr_w(name), reserved, type, data, count,
1327 (count && data) ? *count : 0 );
1329 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1330 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1332 RtlInitUnicodeString( &name_str, name );
1334 if (data) total_size = min( sizeof(buffer), *count + info_size );
1337 total_size = info_size;
1338 if (count) *count = 0;
1341 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1342 buffer, total_size, &total_size );
1343 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1347 /* retry with a dynamically allocated buffer */
1348 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1350 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1351 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1352 return ERROR_NOT_ENOUGH_MEMORY;
1353 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1354 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1355 buf_ptr, total_size, &total_size );
1360 memcpy( data, buf_ptr + info_size, total_size - info_size );
1361 /* if the type is REG_SZ and data is not 0-terminated
1362 * and there is enough space in the buffer NT appends a \0 */
1363 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1365 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1366 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1369 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1371 else status = STATUS_SUCCESS;
1373 if (type) *type = info->Type;
1374 if (count) *count = total_size - info_size;
1377 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1378 return RtlNtStatusToDosError(status);
1382 /******************************************************************************
1383 * RegQueryValueExA [ADVAPI32.@]
1385 * Get the type and contents of a specified value under with a key.
1388 * hkey [I] Handle of the key to query
1389 * name [I] Name of value under hkey to query
1390 * reserved [I] Reserved - must be NULL
1391 * type [O] Destination for the value type, or NULL if not required
1392 * data [O] Destination for the values contents, or NULL if not required
1393 * count [I/O] Size of data, updated with the number of bytes returned
1396 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1397 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1398 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1399 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1402 * MSDN states that if data is too small it is partially filled. In reality
1403 * it remains untouched.
1405 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1406 LPBYTE data, LPDWORD count )
1410 UNICODE_STRING nameW;
1411 DWORD total_size, datalen = 0;
1412 char buffer[256], *buf_ptr = buffer;
1413 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1414 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1416 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1417 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1419 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1420 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1422 if (count) datalen = *count;
1423 if (!data && count) *count = 0;
1425 /* this matches Win9x behaviour - NT sets *type to a random value */
1426 if (type) *type = REG_NONE;
1428 RtlInitAnsiString( &nameA, name );
1429 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1430 return RtlNtStatusToDosError(status);
1432 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1433 buffer, sizeof(buffer), &total_size );
1434 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1436 /* we need to fetch the contents for a string type even if not requested,
1437 * because we need to compute the length of the ASCII string. */
1438 if (data || is_string(info->Type))
1440 /* retry with a dynamically allocated buffer */
1441 while (status == STATUS_BUFFER_OVERFLOW)
1443 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1444 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1446 status = STATUS_NO_MEMORY;
1449 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1450 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1451 buf_ptr, total_size, &total_size );
1454 if (status) goto done;
1456 if (is_string(info->Type))
1460 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1461 total_size - info_size );
1464 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1467 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1468 total_size - info_size );
1469 /* if the type is REG_SZ and data is not 0-terminated
1470 * and there is enough space in the buffer NT appends a \0 */
1471 if (len < datalen && data[len-1]) data[len] = 0;
1474 total_size = len + info_size;
1478 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1479 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1482 else status = STATUS_SUCCESS;
1484 if (type) *type = info->Type;
1485 if (count) *count = total_size - info_size;
1488 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1489 RtlFreeUnicodeString( &nameW );
1490 return RtlNtStatusToDosError(status);
1494 /******************************************************************************
1495 * RegQueryValueW [ADVAPI32.@]
1497 * Retrieves the data associated with the default or unnamed value of a key.
1500 * hkey [I] Handle to an open key.
1501 * name [I] Name of the subkey of hKey.
1502 * data [O] Receives the string associated with the default value
1504 * count [I/O] Size of lpValue in bytes.
1507 * Success: ERROR_SUCCESS
1508 * Failure: nonzero error code from Winerror.h
1510 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1515 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1517 if (name && name[0])
1519 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1521 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1522 if (subkey != hkey) RegCloseKey( subkey );
1523 if (ret == ERROR_FILE_NOT_FOUND)
1525 /* return empty string if default value not found */
1526 if (data) *data = 0;
1527 if (count) *count = sizeof(WCHAR);
1528 ret = ERROR_SUCCESS;
1534 /******************************************************************************
1535 * RegQueryValueA [ADVAPI32.@]
1537 * See RegQueryValueW.
1539 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1544 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1546 if (name && name[0])
1548 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1550 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1551 if (subkey != hkey) RegCloseKey( subkey );
1552 if (ret == ERROR_FILE_NOT_FOUND)
1554 /* return empty string if default value not found */
1555 if (data) *data = 0;
1556 if (count) *count = 1;
1557 ret = ERROR_SUCCESS;
1563 /******************************************************************************
1564 * ADVAPI_ApplyRestrictions [internal]
1566 * Helper function for RegGetValueA/W.
1568 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1569 DWORD cbData, PLONG ret )
1571 /* Check if the type is restricted by the passed flags */
1572 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1578 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1579 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1580 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1581 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1582 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1583 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1584 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1587 if (dwFlags & dwMask)
1589 /* Type is not restricted, check for size mismatch */
1590 if (dwType == REG_BINARY)
1594 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1596 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1599 if (cbExpect && cbData != cbExpect)
1600 *ret = ERROR_DATATYPE_MISMATCH;
1603 else *ret = ERROR_UNSUPPORTED_TYPE;
1608 /******************************************************************************
1609 * RegGetValueW [ADVAPI32.@]
1611 * Retrieves the type and data for a value name associated with a key,
1612 * optionally expanding its content and restricting its type.
1615 * hKey [I] Handle to an open key.
1616 * pszSubKey [I] Name of the subkey of hKey.
1617 * pszValue [I] Name of value under hKey/szSubKey to query.
1618 * dwFlags [I] Flags restricting the value type to retrieve.
1619 * pdwType [O] Destination for the values type, may be NULL.
1620 * pvData [O] Destination for the values content, may be NULL.
1621 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1622 * retrieve the whole content, including the trailing '\0'
1626 * Success: ERROR_SUCCESS
1627 * Failure: nonzero error code from Winerror.h
1630 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1631 * expanded and pdwType is set to REG_SZ instead.
1632 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1633 * without RRF_NOEXPAND is thus not allowed.
1634 * An exception is the case where RRF_RT_ANY is specified, because then
1635 * RRF_NOEXPAND is allowed.
1637 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1638 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1641 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1645 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1646 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1647 pvData, pcbData, cbData);
1649 if (pvData && !pcbData)
1650 return ERROR_INVALID_PARAMETER;
1651 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1652 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1653 return ERROR_INVALID_PARAMETER;
1655 if (pszSubKey && pszSubKey[0])
1657 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1658 if (ret != ERROR_SUCCESS) return ret;
1661 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1663 /* If we are going to expand we need to read in the whole the value even
1664 * if the passed buffer was too small as the expanded string might be
1665 * smaller than the unexpanded one and could fit into cbData bytes. */
1666 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1667 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1670 HeapFree(GetProcessHeap(), 0, pvBuf);
1672 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1675 ret = ERROR_NOT_ENOUGH_MEMORY;
1679 if (ret == ERROR_MORE_DATA || !pvData)
1680 ret = RegQueryValueExW(hKey, pszValue, NULL,
1681 &dwType, pvBuf, &cbData);
1684 /* Even if cbData was large enough we have to copy the
1685 * string since ExpandEnvironmentStrings can't handle
1686 * overlapping buffers. */
1687 CopyMemory(pvBuf, pvData, cbData);
1690 /* Both the type or the value itself could have been modified in
1691 * between so we have to keep retrying until the buffer is large
1692 * enough or we no longer have to expand the value. */
1693 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1695 if (ret == ERROR_SUCCESS)
1697 /* Recheck dwType in case it changed since the first call */
1698 if (dwType == REG_EXPAND_SZ)
1700 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1701 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1703 if(pvData && pcbData && cbData > *pcbData)
1704 ret = ERROR_MORE_DATA;
1707 CopyMemory(pvData, pvBuf, *pcbData);
1710 HeapFree(GetProcessHeap(), 0, pvBuf);
1713 if (pszSubKey && pszSubKey[0])
1716 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1718 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1719 ZeroMemory(pvData, *pcbData);
1721 if (pdwType) *pdwType = dwType;
1722 if (pcbData) *pcbData = cbData;
1728 /******************************************************************************
1729 * RegGetValueA [ADVAPI32.@]
1733 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1734 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1737 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1741 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1742 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1745 if (pvData && !pcbData)
1746 return ERROR_INVALID_PARAMETER;
1747 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1748 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1749 return ERROR_INVALID_PARAMETER;
1751 if (pszSubKey && pszSubKey[0])
1753 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1754 if (ret != ERROR_SUCCESS) return ret;
1757 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1759 /* If we are going to expand we need to read in the whole the value even
1760 * if the passed buffer was too small as the expanded string might be
1761 * smaller than the unexpanded one and could fit into cbData bytes. */
1762 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1763 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1766 HeapFree(GetProcessHeap(), 0, pvBuf);
1768 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1771 ret = ERROR_NOT_ENOUGH_MEMORY;
1775 if (ret == ERROR_MORE_DATA || !pvData)
1776 ret = RegQueryValueExA(hKey, pszValue, NULL,
1777 &dwType, pvBuf, &cbData);
1780 /* Even if cbData was large enough we have to copy the
1781 * string since ExpandEnvironmentStrings can't handle
1782 * overlapping buffers. */
1783 CopyMemory(pvBuf, pvData, cbData);
1786 /* Both the type or the value itself could have been modified in
1787 * between so we have to keep retrying until the buffer is large
1788 * enough or we no longer have to expand the value. */
1789 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1791 if (ret == ERROR_SUCCESS)
1793 /* Recheck dwType in case it changed since the first call */
1794 if (dwType == REG_EXPAND_SZ)
1796 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1797 pcbData ? *pcbData : 0);
1799 if(pvData && pcbData && cbData > *pcbData)
1800 ret = ERROR_MORE_DATA;
1803 CopyMemory(pvData, pvBuf, *pcbData);
1806 HeapFree(GetProcessHeap(), 0, pvBuf);
1809 if (pszSubKey && pszSubKey[0])
1812 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1814 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1815 ZeroMemory(pvData, *pcbData);
1817 if (pdwType) *pdwType = dwType;
1818 if (pcbData) *pcbData = cbData;
1824 /******************************************************************************
1825 * RegEnumValueW [ADVAPI32.@]
1827 * Enumerates the values for the specified open registry key.
1830 * hkey [I] Handle to key to query
1831 * index [I] Index of value to query
1832 * value [O] Value string
1833 * val_count [I/O] Size of value buffer (in wchars)
1834 * reserved [I] Reserved
1835 * type [O] Type code
1836 * data [O] Value data
1837 * count [I/O] Size of data buffer (in bytes)
1840 * Success: ERROR_SUCCESS
1841 * Failure: nonzero error code from Winerror.h
1844 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1845 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1849 char buffer[256], *buf_ptr = buffer;
1850 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1851 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1853 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1854 hkey, index, value, val_count, reserved, type, data, count );
1856 /* NT only checks count, not val_count */
1857 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1858 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1860 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1861 if (data) total_size += *count;
1862 total_size = min( sizeof(buffer), total_size );
1864 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1865 buffer, total_size, &total_size );
1866 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1870 /* retry with a dynamically allocated buffer */
1871 while (status == STATUS_BUFFER_OVERFLOW)
1873 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1874 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1875 return ERROR_NOT_ENOUGH_MEMORY;
1876 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1877 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1878 buf_ptr, total_size, &total_size );
1881 if (status) goto done;
1885 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1887 status = STATUS_BUFFER_OVERFLOW;
1890 memcpy( value, info->Name, info->NameLength );
1891 *val_count = info->NameLength / sizeof(WCHAR);
1892 value[*val_count] = 0;
1897 if (total_size - info->DataOffset > *count)
1899 status = STATUS_BUFFER_OVERFLOW;
1902 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1903 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1905 /* if the type is REG_SZ and data is not 0-terminated
1906 * and there is enough space in the buffer NT appends a \0 */
1907 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1908 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1912 else status = STATUS_SUCCESS;
1915 if (type) *type = info->Type;
1916 if (count) *count = info->DataLength;
1919 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1920 return RtlNtStatusToDosError(status);
1924 /******************************************************************************
1925 * RegEnumValueA [ADVAPI32.@]
1927 * See RegEnumValueW.
1929 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1930 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1934 char buffer[256], *buf_ptr = buffer;
1935 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1936 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1938 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1939 hkey, index, value, val_count, reserved, type, data, count );
1941 /* NT only checks count, not val_count */
1942 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1943 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1945 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1946 if (data) total_size += *count;
1947 total_size = min( sizeof(buffer), total_size );
1949 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1950 buffer, total_size, &total_size );
1951 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1953 /* we need to fetch the contents for a string type even if not requested,
1954 * because we need to compute the length of the ASCII string. */
1955 if (value || data || is_string(info->Type))
1957 /* retry with a dynamically allocated buffer */
1958 while (status == STATUS_BUFFER_OVERFLOW)
1960 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1961 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1962 return ERROR_NOT_ENOUGH_MEMORY;
1963 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1964 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1965 buf_ptr, total_size, &total_size );
1968 if (status) goto done;
1970 if (is_string(info->Type))
1973 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1974 total_size - info->DataOffset );
1977 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1980 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1981 total_size - info->DataOffset );
1982 /* if the type is REG_SZ and data is not 0-terminated
1983 * and there is enough space in the buffer NT appends a \0 */
1984 if (len < *count && data[len-1]) data[len] = 0;
1987 info->DataLength = len;
1991 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1992 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1995 if (value && !status)
1999 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2000 if (len >= *val_count)
2002 status = STATUS_BUFFER_OVERFLOW;
2005 len = *val_count - 1;
2006 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2012 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2018 else status = STATUS_SUCCESS;
2020 if (type) *type = info->Type;
2021 if (count) *count = info->DataLength;
2024 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2025 return RtlNtStatusToDosError(status);
2030 /******************************************************************************
2031 * RegDeleteValueW [ADVAPI32.@]
2033 * See RegDeleteValueA.
2035 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2037 UNICODE_STRING nameW;
2039 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2041 RtlInitUnicodeString( &nameW, name );
2042 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2046 /******************************************************************************
2047 * RegDeleteValueA [ADVAPI32.@]
2049 * Delete a value from the registry.
2052 * hkey [I] Registry handle of the key holding the value
2053 * name [I] Name of the value under hkey to delete
2056 * Success: ERROR_SUCCESS
2057 * Failure: nonzero error code from Winerror.h
2059 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2062 UNICODE_STRING nameW;
2065 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2067 RtlInitAnsiString( &nameA, name );
2068 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2070 status = NtDeleteValueKey( hkey, &nameW );
2071 RtlFreeUnicodeString( &nameW );
2073 return RtlNtStatusToDosError( status );
2077 /******************************************************************************
2078 * RegLoadKeyW [ADVAPI32.@]
2080 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2081 * registration information from a specified file into that subkey.
2084 * hkey [I] Handle of open key
2085 * subkey [I] Address of name of subkey
2086 * filename [I] Address of filename for registry information
2089 * Success: ERROR_SUCCESS
2090 * Failure: nonzero error code from Winerror.h
2092 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2094 OBJECT_ATTRIBUTES destkey, file;
2095 UNICODE_STRING subkeyW, filenameW;
2098 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
2100 destkey.Length = sizeof(destkey);
2101 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2102 destkey.ObjectName = &subkeyW; /* name of the key */
2103 destkey.Attributes = 0;
2104 destkey.SecurityDescriptor = NULL;
2105 destkey.SecurityQualityOfService = NULL;
2106 RtlInitUnicodeString(&subkeyW, subkey);
2108 file.Length = sizeof(file);
2109 file.RootDirectory = NULL;
2110 file.ObjectName = &filenameW; /* file containing the hive */
2111 file.Attributes = OBJ_CASE_INSENSITIVE;
2112 file.SecurityDescriptor = NULL;
2113 file.SecurityQualityOfService = NULL;
2114 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2116 status = NtLoadKey(&destkey, &file);
2117 RtlFreeUnicodeString(&filenameW);
2118 return RtlNtStatusToDosError( status );
2122 /******************************************************************************
2123 * RegLoadKeyA [ADVAPI32.@]
2127 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2129 UNICODE_STRING subkeyW, filenameW;
2130 STRING subkeyA, filenameA;
2134 RtlInitAnsiString(&subkeyA, subkey);
2135 RtlInitAnsiString(&filenameA, filename);
2137 RtlInitUnicodeString(&subkeyW, NULL);
2138 RtlInitUnicodeString(&filenameW, NULL);
2139 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2140 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2142 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2144 else ret = RtlNtStatusToDosError(status);
2145 RtlFreeUnicodeString(&subkeyW);
2146 RtlFreeUnicodeString(&filenameW);
2151 /******************************************************************************
2152 * RegSaveKeyW [ADVAPI32.@]
2154 * Save a key and all of its subkeys and values to a new file in the standard format.
2157 * hkey [I] Handle of key where save begins
2158 * lpFile [I] Address of filename to save to
2159 * sa [I] Address of security structure
2162 * Success: ERROR_SUCCESS
2163 * Failure: nonzero error code from Winerror.h
2165 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2167 static const WCHAR format[] =
2168 {'r','e','g','%','0','4','x','.','t','m','p',0};
2169 WCHAR buffer[MAX_PATH];
2175 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2177 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2178 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2180 err = GetLastError();
2181 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2185 snprintfW( nameW, 16, format, count++ );
2186 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2187 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2188 if (handle != INVALID_HANDLE_VALUE) break;
2189 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2191 /* Something gone haywire ? Please report if this happens abnormally */
2193 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);
2196 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2198 CloseHandle( handle );
2201 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2203 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2205 ret = GetLastError();
2208 if (ret) DeleteFileW( buffer );
2211 SetLastError( err ); /* restore last error code */
2216 /******************************************************************************
2217 * RegSaveKeyA [ADVAPI32.@]
2221 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2223 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2227 RtlInitAnsiString(&fileA, file);
2228 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2229 return RtlNtStatusToDosError( status );
2230 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2234 /******************************************************************************
2235 * RegRestoreKeyW [ADVAPI32.@]
2237 * Read the registry information from a file and copy it over a key.
2240 * hkey [I] Handle of key where restore begins
2241 * lpFile [I] Address of filename containing saved tree
2242 * dwFlags [I] Optional flags
2245 * Success: ERROR_SUCCESS
2246 * Failure: nonzero error code from Winerror.h
2248 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2250 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2252 /* It seems to do this check before the hkey check */
2253 if (!lpFile || !*lpFile)
2254 return ERROR_INVALID_PARAMETER;
2256 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2258 /* Check for file existence */
2260 return ERROR_SUCCESS;
2264 /******************************************************************************
2265 * RegRestoreKeyA [ADVAPI32.@]
2267 * See RegRestoreKeyW.
2269 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2271 UNICODE_STRING lpFileW;
2274 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2275 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2276 RtlFreeUnicodeString( &lpFileW );
2281 /******************************************************************************
2282 * RegUnLoadKeyW [ADVAPI32.@]
2284 * Unload a registry key and its subkeys from the registry.
2287 * hkey [I] Handle of open key
2288 * lpSubKey [I] Address of name of subkey to unload
2291 * Success: ERROR_SUCCESS
2292 * Failure: nonzero error code from Winerror.h
2294 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2298 OBJECT_ATTRIBUTES attr;
2299 UNICODE_STRING subkey;
2301 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2303 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2305 return ERROR_INVALID_PARAMETER;
2307 RtlInitUnicodeString(&subkey, lpSubKey);
2308 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2309 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2317 /******************************************************************************
2318 * RegUnLoadKeyA [ADVAPI32.@]
2320 * See RegUnLoadKeyW.
2322 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2324 UNICODE_STRING lpSubKeyW;
2327 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2328 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2329 RtlFreeUnicodeString( &lpSubKeyW );
2334 /******************************************************************************
2335 * RegReplaceKeyW [ADVAPI32.@]
2337 * Replace the file backing a registry key and all its subkeys with another file.
2340 * hkey [I] Handle of open key
2341 * lpSubKey [I] Address of name of subkey
2342 * lpNewFile [I] Address of filename for file with new data
2343 * lpOldFile [I] Address of filename for backup file
2346 * Success: ERROR_SUCCESS
2347 * Failure: nonzero error code from Winerror.h
2349 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2352 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2353 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2354 return ERROR_SUCCESS;
2358 /******************************************************************************
2359 * RegReplaceKeyA [ADVAPI32.@]
2361 * See RegReplaceKeyW.
2363 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2366 UNICODE_STRING lpSubKeyW;
2367 UNICODE_STRING lpNewFileW;
2368 UNICODE_STRING lpOldFileW;
2371 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2372 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2373 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2374 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2375 RtlFreeUnicodeString( &lpOldFileW );
2376 RtlFreeUnicodeString( &lpNewFileW );
2377 RtlFreeUnicodeString( &lpSubKeyW );
2382 /******************************************************************************
2383 * RegSetKeySecurity [ADVAPI32.@]
2385 * Set the security of an open registry key.
2388 * hkey [I] Open handle of key to set
2389 * SecurityInfo [I] Descriptor contents
2390 * pSecurityDesc [I] Address of descriptor for key
2393 * Success: ERROR_SUCCESS
2394 * Failure: nonzero error code from Winerror.h
2396 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2397 PSECURITY_DESCRIPTOR pSecurityDesc )
2399 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2401 /* It seems to perform this check before the hkey check */
2402 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2403 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2404 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2405 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2408 return ERROR_INVALID_PARAMETER;
2411 return ERROR_INVALID_PARAMETER;
2413 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2415 return ERROR_SUCCESS;
2419 /******************************************************************************
2420 * RegGetKeySecurity [ADVAPI32.@]
2422 * Get a copy of the security descriptor for a given registry key.
2425 * hkey [I] Open handle of key to set
2426 * SecurityInformation [I] Descriptor contents
2427 * pSecurityDescriptor [O] Address of descriptor for key
2428 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2431 * Success: ERROR_SUCCESS
2432 * Failure: Error code
2434 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2435 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2436 LPDWORD lpcbSecurityDescriptor )
2438 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2439 *lpcbSecurityDescriptor);
2441 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2443 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2444 SecurityInformation, pSecurityDescriptor,
2445 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2449 /******************************************************************************
2450 * RegFlushKey [ADVAPI32.@]
2452 * Immediately write a registry key to registry.
2455 * hkey [I] Handle of key to write
2458 * Success: ERROR_SUCCESS
2459 * Failure: Error code
2461 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2463 hkey = get_special_root_hkey( hkey );
2464 if (!hkey) return ERROR_INVALID_HANDLE;
2466 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2470 /******************************************************************************
2471 * RegConnectRegistryW [ADVAPI32.@]
2473 * Establish a connection to a predefined registry key on another computer.
2476 * lpMachineName [I] Address of name of remote computer
2477 * hHey [I] Predefined registry handle
2478 * phkResult [I] Address of buffer for remote registry handle
2481 * Success: ERROR_SUCCESS
2482 * Failure: nonzero error code from Winerror.h
2484 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2489 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2491 if (!lpMachineName || !*lpMachineName) {
2492 /* Use the local machine name */
2493 ret = RegOpenKeyW( hKey, NULL, phkResult );
2496 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2497 DWORD len = sizeof(compName) / sizeof(WCHAR);
2499 /* MSDN says lpMachineName must start with \\ : not so */
2500 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2502 if (GetComputerNameW(compName, &len))
2504 if (!strcmpiW(lpMachineName, compName))
2505 ret = RegOpenKeyW(hKey, NULL, phkResult);
2508 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2509 ret = ERROR_BAD_NETPATH;
2513 ret = GetLastError();
2519 /******************************************************************************
2520 * RegConnectRegistryA [ADVAPI32.@]
2522 * See RegConnectRegistryW.
2524 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2526 UNICODE_STRING machineW;
2529 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2530 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2531 RtlFreeUnicodeString( &machineW );
2536 /******************************************************************************
2537 * RegNotifyChangeKeyValue [ADVAPI32.@]
2539 * Notify the caller about changes to the attributes or contents of a registry key.
2542 * hkey [I] Handle of key to watch
2543 * fWatchSubTree [I] Flag for subkey notification
2544 * fdwNotifyFilter [I] Changes to be reported
2545 * hEvent [I] Handle of signaled event
2546 * fAsync [I] Flag for asynchronous reporting
2549 * Success: ERROR_SUCCESS
2550 * Failure: nonzero error code from Winerror.h
2552 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2553 DWORD fdwNotifyFilter, HANDLE hEvent,
2557 IO_STATUS_BLOCK iosb;
2559 hkey = get_special_root_hkey( hkey );
2560 if (!hkey) return ERROR_INVALID_HANDLE;
2562 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2565 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2566 fdwNotifyFilter, fAsync, NULL, 0,
2569 if (status && status != STATUS_TIMEOUT)
2570 return RtlNtStatusToDosError( status );
2572 return ERROR_SUCCESS;
2575 /******************************************************************************
2576 * RegOpenUserClassesRoot [ADVAPI32.@]
2578 * Open the HKEY_CLASSES_ROOT key for a user.
2581 * hToken [I] Handle of token representing the user
2582 * dwOptions [I] Reserved, must be 0
2583 * samDesired [I] Desired access rights
2584 * phkResult [O] Destination for the resulting key handle
2587 * Success: ERROR_SUCCESS
2588 * Failure: nonzero error code from Winerror.h
2591 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2592 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2593 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2595 LSTATUS WINAPI RegOpenUserClassesRoot(
2602 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2604 *phkResult = HKEY_CLASSES_ROOT;
2605 return ERROR_SUCCESS;
2608 /******************************************************************************
2609 * load_string [Internal]
2611 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2612 * avoid importing user32, which is higher level than advapi32. Helper for
2615 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2622 /* Negative values have to be inverted. */
2623 if (HIWORD(resId) == 0xffff)
2624 resId = (UINT)(-((INT)resId));
2626 /* Load the resource into memory and get a pointer to it. */
2627 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2628 if (!hResource) return 0;
2629 hMemory = LoadResource(hModule, hResource);
2630 if (!hMemory) return 0;
2631 pString = LockResource(hMemory);
2633 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2634 idxString = resId & 0xf;
2635 while (idxString--) pString += *pString + 1;
2637 /* If no buffer is given, return length of the string. */
2638 if (!pwszBuffer) return *pString;
2640 /* Else copy over the string, respecting the buffer size. */
2641 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2642 if (cMaxChars >= 0) {
2643 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2644 pwszBuffer[cMaxChars] = '\0';
2650 /******************************************************************************
2651 * RegLoadMUIStringW [ADVAPI32.@]
2653 * Load the localized version of a string resource from some PE, respective
2654 * id and path of which are given in the registry value in the format
2655 * @[path]\dllname,-resourceId
2658 * hKey [I] Key, of which to load the string value from.
2659 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2660 * pszBuffer [O] Buffer to store the localized string in.
2661 * cbBuffer [I] Size of the destination buffer in bytes.
2662 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2663 * dwFlags [I] None supported yet.
2664 * pszBaseDir [I] Not supported yet.
2667 * Success: ERROR_SUCCESS,
2668 * Failure: nonzero error code from winerror.h
2671 * This is an API of Windows Vista, which wasn't available at the time this code
2672 * was written. We have to check for the correct behaviour once it's available.
2674 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2675 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2677 DWORD dwValueType, cbData;
2678 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2681 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2682 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2683 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2685 /* Parameter sanity checks. */
2686 if (!hKey || !pwszBuffer)
2687 return ERROR_INVALID_PARAMETER;
2689 if (pwszBaseDir && *pwszBaseDir) {
2690 FIXME("BaseDir parameter not yet supported!\n");
2691 return ERROR_INVALID_PARAMETER;
2694 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2695 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2696 if (result != ERROR_SUCCESS) goto cleanup;
2697 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2698 result = ERROR_FILE_NOT_FOUND;
2701 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2702 if (!pwszTempBuffer) {
2703 result = ERROR_NOT_ENOUGH_MEMORY;
2706 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2707 if (result != ERROR_SUCCESS) goto cleanup;
2709 /* Expand environment variables, if appropriate, or copy the original string over. */
2710 if (dwValueType == REG_EXPAND_SZ) {
2711 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2712 if (!cbData) goto cleanup;
2713 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2714 if (!pwszExpandedBuffer) {
2715 result = ERROR_NOT_ENOUGH_MEMORY;
2718 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2720 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2721 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2724 /* If the value references a resource based string, parse the value and load the string.
2725 * Else just copy over the original value. */
2726 result = ERROR_SUCCESS;
2727 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2728 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2730 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2734 /* Format of the expanded value is 'path_to_dll,-resId' */
2735 if (!pComma || pComma[1] != '-') {
2736 result = ERROR_BADKEY;
2740 uiStringId = atoiW(pComma+2);
2743 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2744 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2745 result = ERROR_BADKEY;
2746 FreeLibrary(hModule);
2750 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2751 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2755 /******************************************************************************
2756 * RegLoadMUIStringA [ADVAPI32.@]
2758 * See RegLoadMUIStringW
2760 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2761 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2763 UNICODE_STRING valueW, baseDirW;
2765 DWORD cbData = cbBuffer * sizeof(WCHAR);
2768 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2769 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2770 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2771 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2773 result = ERROR_NOT_ENOUGH_MEMORY;
2777 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2780 if (result == ERROR_SUCCESS) {
2781 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2787 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2788 RtlFreeUnicodeString(&baseDirW);
2789 RtlFreeUnicodeString(&valueW);
2794 /******************************************************************************
2795 * RegDisablePredefinedCache [ADVAPI32.@]
2797 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2803 * Success: ERROR_SUCCESS
2804 * Failure: nonzero error code from Winerror.h
2807 * This is useful for services that use impersonation.
2809 LSTATUS WINAPI RegDisablePredefinedCache(void)
2811 HKEY hkey_current_user;
2812 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2814 /* prevent caching of future requests */
2815 hkcu_cache_disabled = TRUE;
2817 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2819 if (hkey_current_user)
2820 NtClose( hkey_current_user );
2822 return ERROR_SUCCESS;
2825 /******************************************************************************
2826 * RegDeleteTreeW [ADVAPI32.@]
2829 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2832 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2833 DWORD dwMaxLen, dwSize;
2834 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2835 HKEY hSubKey = hKey;
2837 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2841 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2842 if (ret) return ret;
2845 /* Get highest length for keys, values */
2846 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2847 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2848 if (ret) goto cleanup;
2852 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2853 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2855 /* Name too big: alloc a buffer for it */
2856 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2858 ret = ERROR_NOT_ENOUGH_MEMORY;
2864 /* Recursively delete all the subkeys */
2868 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2869 NULL, NULL, NULL)) break;
2871 ret = RegDeleteTreeW(hSubKey, lpszName);
2872 if (ret) goto cleanup;
2876 ret = RegDeleteKeyW(hKey, lpszSubKey);
2881 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2882 NULL, NULL, NULL, NULL)) break;
2884 ret = RegDeleteValueW(hKey, lpszName);
2885 if (ret) goto cleanup;
2889 /* Free buffer if allocated */
2890 if (lpszName != szNameBuf)
2891 HeapFree( GetProcessHeap(), 0, lpszName);
2893 RegCloseKey(hSubKey);
2897 /******************************************************************************
2898 * RegDeleteTreeA [ADVAPI32.@]
2901 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2904 UNICODE_STRING lpszSubKeyW;
2906 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2907 else lpszSubKeyW.Buffer = NULL;
2908 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2909 RtlFreeUnicodeString( &lpszSubKeyW );