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 TRACE("(%p %p)\n", hkey, override);
289 if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST))
290 return ERROR_INVALID_PARAMETER;
291 idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
295 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
296 GetCurrentProcess(), (HANDLE *)&override,
297 0, 0, DUPLICATE_SAME_ACCESS );
298 if (status) return RtlNtStatusToDosError( status );
301 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
302 if (old_key) NtClose( old_key );
303 return ERROR_SUCCESS;
307 /******************************************************************************
308 * RegCreateKeyExW [ADVAPI32.@]
310 * See RegCreateKeyExA.
312 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
313 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
314 PHKEY retkey, LPDWORD dispos )
316 OBJECT_ATTRIBUTES attr;
317 UNICODE_STRING nameW, classW;
319 if (reserved) return ERROR_INVALID_PARAMETER;
320 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
322 attr.Length = sizeof(attr);
323 attr.RootDirectory = hkey;
324 attr.ObjectName = &nameW;
326 attr.SecurityDescriptor = NULL;
327 attr.SecurityQualityOfService = NULL;
328 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
329 RtlInitUnicodeString( &nameW, name );
330 RtlInitUnicodeString( &classW, class );
332 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
336 /******************************************************************************
337 * RegCreateKeyExA [ADVAPI32.@]
339 * Open a registry key, creating it if it doesn't exist.
342 * hkey [I] Handle of the parent registry key
343 * name [I] Name of the new key to open or create
344 * reserved [I] Reserved, pass 0
345 * class [I] The object type of the new key
346 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
347 * access [I] Access level desired
348 * sa [I] Security attributes for the key
349 * retkey [O] Destination for the resulting handle
350 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
353 * Success: ERROR_SUCCESS.
354 * Failure: A standard Win32 error code. retkey remains untouched.
357 * MAXIMUM_ALLOWED in access mask not supported by server
359 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
360 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
361 PHKEY retkey, LPDWORD dispos )
363 OBJECT_ATTRIBUTES attr;
364 UNICODE_STRING classW;
365 ANSI_STRING nameA, classA;
368 if (reserved) return ERROR_INVALID_PARAMETER;
369 if (!is_version_nt())
371 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
372 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
374 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
376 attr.Length = sizeof(attr);
377 attr.RootDirectory = hkey;
378 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
380 attr.SecurityDescriptor = NULL;
381 attr.SecurityQualityOfService = NULL;
382 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
383 RtlInitAnsiString( &nameA, name );
384 RtlInitAnsiString( &classA, class );
386 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
389 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
391 status = create_key( retkey, access, &attr, &classW, options, dispos );
392 RtlFreeUnicodeString( &classW );
395 return RtlNtStatusToDosError( status );
399 /******************************************************************************
400 * RegCreateKeyW [ADVAPI32.@]
402 * Creates the specified reg key.
405 * hKey [I] Handle to an open key.
406 * lpSubKey [I] Name of a key that will be opened or created.
407 * phkResult [O] Receives a handle to the opened or created key.
410 * Success: ERROR_SUCCESS
411 * Failure: nonzero error code defined in Winerror.h
413 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
415 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
416 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
417 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
418 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
422 /******************************************************************************
423 * RegCreateKeyA [ADVAPI32.@]
427 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
429 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
430 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
435 /******************************************************************************
436 * RegOpenKeyExW [ADVAPI32.@]
440 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
442 OBJECT_ATTRIBUTES attr;
443 UNICODE_STRING nameW;
445 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
446 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
448 if (!retkey) return ERROR_INVALID_PARAMETER;
449 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
451 attr.Length = sizeof(attr);
452 attr.RootDirectory = hkey;
453 attr.ObjectName = &nameW;
455 attr.SecurityDescriptor = NULL;
456 attr.SecurityQualityOfService = NULL;
457 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
458 RtlInitUnicodeString( &nameW, name );
459 return RtlNtStatusToDosError( open_key( retkey, access, &attr ) );
463 /******************************************************************************
464 * RegOpenKeyExA [ADVAPI32.@]
466 * Open a registry key.
469 * hkey [I] Handle of open key
470 * name [I] Name of subkey to open
471 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
472 * access [I] Security access mask
473 * retkey [O] Handle to open key
476 * Success: ERROR_SUCCESS
477 * Failure: A standard Win32 error code. retkey is set to 0.
480 * Unlike RegCreateKeyExA(), this function will not create the key if it
483 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
485 OBJECT_ATTRIBUTES attr;
489 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
492 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
493 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
496 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
498 attr.Length = sizeof(attr);
499 attr.RootDirectory = hkey;
500 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
502 attr.SecurityDescriptor = NULL;
503 attr.SecurityQualityOfService = NULL;
504 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
506 RtlInitAnsiString( &nameA, name );
507 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
510 status = open_key( retkey, access, &attr );
512 return RtlNtStatusToDosError( status );
516 /******************************************************************************
517 * RegOpenKeyW [ADVAPI32.@]
521 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
524 return ERROR_INVALID_PARAMETER;
529 return ERROR_SUCCESS;
531 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
535 /******************************************************************************
536 * RegOpenKeyA [ADVAPI32.@]
538 * Open a registry key.
541 * hkey [I] Handle of parent key to open the new key under
542 * name [I] Name of the key under hkey to open
543 * retkey [O] Destination for the resulting Handle
546 * Success: ERROR_SUCCESS
547 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
549 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
552 return ERROR_INVALID_PARAMETER;
557 return ERROR_SUCCESS;
559 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
563 /******************************************************************************
564 * RegOpenCurrentUser [ADVAPI32.@]
566 * Get a handle to the HKEY_CURRENT_USER key for the user
567 * the current thread is impersonating.
570 * access [I] Desired access rights to the key
571 * retkey [O] Handle to the opened key
574 * Success: ERROR_SUCCESS
575 * Failure: nonzero error code from Winerror.h
578 * This function is supposed to retrieve a handle to the
579 * HKEY_CURRENT_USER for the user the current thread is impersonating.
580 * Since Wine does not currently allow threads to impersonate other users,
581 * this stub should work fine.
583 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
585 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
590 /******************************************************************************
591 * RegEnumKeyExW [ADVAPI32.@]
593 * Enumerate subkeys of the specified open registry key.
596 * hkey [I] Handle to key to enumerate
597 * index [I] Index of subkey to enumerate
598 * name [O] Buffer for subkey name
599 * name_len [O] Size of subkey buffer
600 * reserved [I] Reserved
601 * class [O] Buffer for class string
602 * class_len [O] Size of class buffer
603 * ft [O] Time key last written to
606 * Success: ERROR_SUCCESS
607 * Failure: System error code. If there are no more subkeys available, the
608 * function returns ERROR_NO_MORE_ITEMS.
610 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
611 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
614 char buffer[256], *buf_ptr = buffer;
615 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
618 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
619 name_len ? *name_len : 0, reserved, class, class_len, ft );
621 if (reserved) return ERROR_INVALID_PARAMETER;
622 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
624 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
625 buffer, sizeof(buffer), &total_size );
627 while (status == STATUS_BUFFER_OVERFLOW)
629 /* retry with a dynamically allocated buffer */
630 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
631 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
632 return ERROR_NOT_ENOUGH_MEMORY;
633 info = (KEY_NODE_INFORMATION *)buf_ptr;
634 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
635 buf_ptr, total_size, &total_size );
640 DWORD len = info->NameLength / sizeof(WCHAR);
641 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
643 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
645 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
646 status = STATUS_BUFFER_OVERFLOW;
650 memcpy( name, info->Name, info->NameLength );
654 *class_len = cls_len;
657 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
664 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
665 return RtlNtStatusToDosError( status );
669 /******************************************************************************
670 * RegEnumKeyExA [ADVAPI32.@]
674 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
675 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
678 char buffer[256], *buf_ptr = buffer;
679 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
682 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
683 name_len ? *name_len : 0, reserved, class, class_len, ft );
685 if (reserved) return ERROR_INVALID_PARAMETER;
686 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
688 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
689 buffer, sizeof(buffer), &total_size );
691 while (status == STATUS_BUFFER_OVERFLOW)
693 /* retry with a dynamically allocated buffer */
694 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
695 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
696 return ERROR_NOT_ENOUGH_MEMORY;
697 info = (KEY_NODE_INFORMATION *)buf_ptr;
698 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
699 buf_ptr, total_size, &total_size );
706 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
707 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
709 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
711 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
712 status = STATUS_BUFFER_OVERFLOW;
716 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
720 *class_len = cls_len;
723 RtlUnicodeToMultiByteN( class, cls_len, NULL,
724 (WCHAR *)(buf_ptr + info->ClassOffset),
732 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
733 return RtlNtStatusToDosError( status );
737 /******************************************************************************
738 * RegEnumKeyW [ADVAPI32.@]
740 * Enumerates subkeys of the specified open reg key.
743 * hKey [I] Handle to an open key.
744 * dwIndex [I] Index of the subkey of hKey to retrieve.
745 * lpName [O] Name of the subkey.
746 * cchName [I] Size of lpName in TCHARS.
749 * Success: ERROR_SUCCESS
750 * Failure: system error code. If there are no more subkeys available, the
751 * function returns ERROR_NO_MORE_ITEMS.
753 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
755 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
759 /******************************************************************************
760 * RegEnumKeyA [ADVAPI32.@]
764 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
766 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
770 /******************************************************************************
771 * RegQueryInfoKeyW [ADVAPI32.@]
773 * Retrieves information about the specified registry key.
776 * hkey [I] Handle to key to query
777 * class [O] Buffer for class string
778 * class_len [O] Size of class string buffer
779 * reserved [I] Reserved
780 * subkeys [O] Buffer for number of subkeys
781 * max_subkey [O] Buffer for longest subkey name length
782 * max_class [O] Buffer for longest class string length
783 * values [O] Buffer for number of value entries
784 * max_value [O] Buffer for longest value name length
785 * max_data [O] Buffer for longest value data length
786 * security [O] Buffer for security descriptor length
787 * modif [O] Modification time
790 * Success: ERROR_SUCCESS
791 * Failure: system error code.
794 * - win95 allows class to be valid and class_len to be NULL
795 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
796 * - both allow class to be NULL and class_len to be NULL
797 * (it's hard to test validity, so test !NULL instead)
799 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
800 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
801 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
802 LPDWORD security, FILETIME *modif )
805 char buffer[256], *buf_ptr = buffer;
806 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
809 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
810 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
812 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
813 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
815 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
816 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
820 /* retry with a dynamically allocated buffer */
821 while (status == STATUS_BUFFER_OVERFLOW)
823 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
824 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
825 return ERROR_NOT_ENOUGH_MEMORY;
826 info = (KEY_FULL_INFORMATION *)buf_ptr;
827 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
830 if (status) goto done;
832 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
834 status = STATUS_BUFFER_OVERFLOW;
838 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
839 class[info->ClassLength/sizeof(WCHAR)] = 0;
842 else status = STATUS_SUCCESS;
844 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
845 if (subkeys) *subkeys = info->SubKeys;
846 if (max_subkey) *max_subkey = info->MaxNameLen;
847 if (max_class) *max_class = info->MaxClassLen;
848 if (values) *values = info->Values;
849 if (max_value) *max_value = info->MaxValueNameLen;
850 if (max_data) *max_data = info->MaxValueDataLen;
851 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
854 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
855 return RtlNtStatusToDosError( status );
859 /******************************************************************************
860 * RegQueryMultipleValuesA [ADVAPI32.@]
862 * Retrieves the type and data for a list of value names associated with a key.
865 * hKey [I] Handle to an open key.
866 * val_list [O] Array of VALENT structures that describes the entries.
867 * num_vals [I] Number of elements in val_list.
868 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
869 * ldwTotsize [I/O] Size of lpValueBuf.
872 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
873 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
876 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
877 LPSTR lpValueBuf, LPDWORD ldwTotsize )
880 DWORD maxBytes = *ldwTotsize;
882 LPSTR bufptr = lpValueBuf;
885 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
887 for(i=0; i < num_vals; ++i)
890 val_list[i].ve_valuelen=0;
891 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
892 if(status != ERROR_SUCCESS)
897 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
899 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
900 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
901 if(status != ERROR_SUCCESS)
906 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
908 bufptr += val_list[i].ve_valuelen;
911 *ldwTotsize += val_list[i].ve_valuelen;
913 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
917 /******************************************************************************
918 * RegQueryMultipleValuesW [ADVAPI32.@]
920 * See RegQueryMultipleValuesA.
922 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
923 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
926 DWORD maxBytes = *ldwTotsize;
928 LPSTR bufptr = (LPSTR)lpValueBuf;
931 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
933 for(i=0; i < num_vals; ++i)
935 val_list[i].ve_valuelen=0;
936 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
937 if(status != ERROR_SUCCESS)
942 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
944 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
945 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
946 if(status != ERROR_SUCCESS)
951 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
953 bufptr += val_list[i].ve_valuelen;
956 *ldwTotsize += val_list[i].ve_valuelen;
958 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
961 /******************************************************************************
962 * RegQueryInfoKeyA [ADVAPI32.@]
964 * Retrieves information about a registry key.
967 * hKey [I] Handle to an open key.
968 * lpClass [O] Class string of the key.
969 * lpcClass [I/O] size of lpClass.
970 * lpReserved [I] Reserved; must be NULL.
971 * lpcSubKeys [O] Number of subkeys contained by the key.
972 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
973 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
975 * lpcValues [O] Number of values associated with the key.
976 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
977 * lpcMaxValueLen [O] Longest data component among the key's values
978 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
979 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
982 * Success: ERROR_SUCCESS
983 * Failure: nonzero error code from Winerror.h
985 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
986 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
987 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
988 LPDWORD security, FILETIME *modif )
991 char buffer[256], *buf_ptr = buffer;
992 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
993 DWORD total_size, len;
995 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
996 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
998 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
999 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1001 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
1002 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1004 if (class || class_len)
1006 /* retry with a dynamically allocated buffer */
1007 while (status == STATUS_BUFFER_OVERFLOW)
1009 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1010 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1011 return ERROR_NOT_ENOUGH_MEMORY;
1012 info = (KEY_FULL_INFORMATION *)buf_ptr;
1013 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
1016 if (status) goto done;
1018 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
1021 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
1024 if (class && !status)
1026 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
1027 info->ClassLength );
1031 else status = STATUS_SUCCESS;
1033 if (subkeys) *subkeys = info->SubKeys;
1034 if (max_subkey) *max_subkey = info->MaxNameLen;
1035 if (max_class) *max_class = info->MaxClassLen;
1036 if (values) *values = info->Values;
1037 if (max_value) *max_value = info->MaxValueNameLen;
1038 if (max_data) *max_data = info->MaxValueDataLen;
1039 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
1042 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1043 return RtlNtStatusToDosError( status );
1047 /******************************************************************************
1048 * RegCloseKey [ADVAPI32.@]
1050 * Close an open registry key.
1053 * hkey [I] Handle of key to close
1056 * Success: ERROR_SUCCESS
1057 * Failure: Error code
1059 LSTATUS WINAPI RegCloseKey( HKEY hkey )
1061 if (!hkey) return ERROR_INVALID_HANDLE;
1062 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
1063 return RtlNtStatusToDosError( NtClose( hkey ) );
1067 /******************************************************************************
1068 * RegDeleteKeyExW [ADVAPI32.@]
1070 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
1075 if (!name) return ERROR_INVALID_PARAMETER;
1077 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1079 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1080 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
1082 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1085 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
1090 /******************************************************************************
1091 * RegDeleteKeyW [ADVAPI32.@]
1093 * See RegDeleteKeyA.
1095 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
1097 return RegDeleteKeyExW( hkey, name, 0, 0 );
1101 /******************************************************************************
1102 * RegDeleteKeyExA [ADVAPI32.@]
1104 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1109 if (!name) return ERROR_INVALID_PARAMETER;
1111 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1113 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1114 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1116 if (!is_version_nt()) /* win95 does recursive key deletes */
1120 while(!RegEnumKeyA(tmp, 0, sub, sizeof(sub)))
1122 if(RegDeleteKeyExA(tmp, sub, access, reserved)) /* recurse */
1126 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1129 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1134 /******************************************************************************
1135 * RegDeleteKeyA [ADVAPI32.@]
1137 * Delete a registry key.
1140 * hkey [I] Handle to parent key containing the key to delete
1141 * name [I] Name of the key user hkey to delete
1145 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1146 * right. In reality, it opens a new handle with DELETE access.
1149 * Success: ERROR_SUCCESS
1150 * Failure: Error code
1152 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1154 return RegDeleteKeyExA( hkey, name, 0, 0 );
1159 /******************************************************************************
1160 * RegSetValueExW [ADVAPI32.@]
1162 * Set the data and contents of a registry value.
1165 * hkey [I] Handle of key to set value for
1166 * name [I] Name of value to set
1167 * reserved [I] Reserved, must be zero
1168 * type [I] Type of the value being set
1169 * data [I] The new contents of the value to set
1170 * count [I] Size of data
1173 * Success: ERROR_SUCCESS
1174 * Failure: Error code
1176 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1177 DWORD type, CONST BYTE *data, DWORD count )
1179 UNICODE_STRING nameW;
1181 /* no need for version check, not implemented on win9x anyway */
1183 if (data && ((ULONG_PTR)data >> 16) == 0) return ERROR_NOACCESS;
1185 if (count && is_string(type))
1187 LPCWSTR str = (LPCWSTR)data;
1188 /* if user forgot to count terminating null, add it (yes NT does this) */
1189 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1190 count += sizeof(WCHAR);
1192 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1194 RtlInitUnicodeString( &nameW, name );
1195 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1199 /******************************************************************************
1200 * RegSetValueExA [ADVAPI32.@]
1202 * See RegSetValueExW.
1205 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1206 * NT does definitely care (aj)
1208 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1209 CONST BYTE *data, DWORD count )
1212 UNICODE_STRING nameW;
1213 WCHAR *dataW = NULL;
1216 if (!is_version_nt()) /* win95 */
1220 if (!data) return ERROR_INVALID_PARAMETER;
1221 count = strlen((const char *)data) + 1;
1224 else if (count && is_string(type))
1226 /* if user forgot to count terminating null, add it (yes NT does this) */
1227 if (data[count-1] && !data[count]) count++;
1230 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1232 if (is_string( type )) /* need to convert to Unicode */
1235 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1236 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1237 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1239 data = (BYTE *)dataW;
1242 RtlInitAnsiString( &nameA, name );
1243 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1245 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1246 RtlFreeUnicodeString( &nameW );
1248 HeapFree( GetProcessHeap(), 0, dataW );
1249 return RtlNtStatusToDosError( status );
1253 /******************************************************************************
1254 * RegSetValueW [ADVAPI32.@]
1256 * Sets the data for the default or unnamed value of a reg key.
1259 * hKey [I] Handle to an open key.
1260 * lpSubKey [I] Name of a subkey of hKey.
1261 * dwType [I] Type of information to store.
1262 * lpData [I] String that contains the data to set for the default value.
1263 * cbData [I] Ignored.
1266 * Success: ERROR_SUCCESS
1267 * Failure: nonzero error code from Winerror.h
1269 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1274 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1276 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1278 if (name && name[0]) /* need to create the subkey */
1280 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1283 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1284 (strlenW( data ) + 1) * sizeof(WCHAR) );
1285 if (subkey != hkey) RegCloseKey( subkey );
1290 /******************************************************************************
1291 * RegSetValueA [ADVAPI32.@]
1295 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1300 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1302 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1304 if (name && name[0]) /* need to create the subkey */
1306 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1308 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1309 if (subkey != hkey) RegCloseKey( subkey );
1315 /******************************************************************************
1316 * RegQueryValueExW [ADVAPI32.@]
1318 * See RegQueryValueExA.
1320 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1321 LPBYTE data, LPDWORD count )
1324 UNICODE_STRING name_str;
1326 char buffer[256], *buf_ptr = buffer;
1327 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1328 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1330 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1331 hkey, debugstr_w(name), reserved, type, data, count,
1332 (count && data) ? *count : 0 );
1334 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1335 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1337 RtlInitUnicodeString( &name_str, name );
1339 if (data) total_size = min( sizeof(buffer), *count + info_size );
1342 total_size = info_size;
1343 if (count) *count = 0;
1346 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1347 buffer, total_size, &total_size );
1348 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1352 /* retry with a dynamically allocated buffer */
1353 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1355 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1356 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1357 return ERROR_NOT_ENOUGH_MEMORY;
1358 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1359 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1360 buf_ptr, total_size, &total_size );
1365 memcpy( data, buf_ptr + info_size, total_size - info_size );
1366 /* if the type is REG_SZ and data is not 0-terminated
1367 * and there is enough space in the buffer NT appends a \0 */
1368 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1370 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1371 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1374 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1376 else status = STATUS_SUCCESS;
1378 if (type) *type = info->Type;
1379 if (count) *count = total_size - info_size;
1382 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1383 return RtlNtStatusToDosError(status);
1387 /******************************************************************************
1388 * RegQueryValueExA [ADVAPI32.@]
1390 * Get the type and contents of a specified value under with a key.
1393 * hkey [I] Handle of the key to query
1394 * name [I] Name of value under hkey to query
1395 * reserved [I] Reserved - must be NULL
1396 * type [O] Destination for the value type, or NULL if not required
1397 * data [O] Destination for the values contents, or NULL if not required
1398 * count [I/O] Size of data, updated with the number of bytes returned
1401 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1402 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1403 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1404 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1407 * MSDN states that if data is too small it is partially filled. In reality
1408 * it remains untouched.
1410 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1411 LPBYTE data, LPDWORD count )
1415 UNICODE_STRING nameW;
1416 DWORD total_size, datalen = 0;
1417 char buffer[256], *buf_ptr = buffer;
1418 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1419 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1421 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1422 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1424 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1425 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1427 if (count) datalen = *count;
1428 if (!data && count) *count = 0;
1430 /* this matches Win9x behaviour - NT sets *type to a random value */
1431 if (type) *type = REG_NONE;
1433 RtlInitAnsiString( &nameA, name );
1434 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1435 return RtlNtStatusToDosError(status);
1437 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1438 buffer, sizeof(buffer), &total_size );
1439 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1441 /* we need to fetch the contents for a string type even if not requested,
1442 * because we need to compute the length of the ASCII string. */
1443 if (data || is_string(info->Type))
1445 /* retry with a dynamically allocated buffer */
1446 while (status == STATUS_BUFFER_OVERFLOW)
1448 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1449 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1451 status = STATUS_NO_MEMORY;
1454 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1455 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1456 buf_ptr, total_size, &total_size );
1459 if (status) goto done;
1461 if (is_string(info->Type))
1465 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1466 total_size - info_size );
1469 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1472 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1473 total_size - info_size );
1474 /* if the type is REG_SZ and data is not 0-terminated
1475 * and there is enough space in the buffer NT appends a \0 */
1476 if (len < datalen && data[len-1]) data[len] = 0;
1479 total_size = len + info_size;
1483 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1484 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1487 else status = STATUS_SUCCESS;
1489 if (type) *type = info->Type;
1490 if (count) *count = total_size - info_size;
1493 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1494 RtlFreeUnicodeString( &nameW );
1495 return RtlNtStatusToDosError(status);
1499 /******************************************************************************
1500 * RegQueryValueW [ADVAPI32.@]
1502 * Retrieves the data associated with the default or unnamed value of a key.
1505 * hkey [I] Handle to an open key.
1506 * name [I] Name of the subkey of hKey.
1507 * data [O] Receives the string associated with the default value
1509 * count [I/O] Size of lpValue in bytes.
1512 * Success: ERROR_SUCCESS
1513 * Failure: nonzero error code from Winerror.h
1515 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1520 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1522 if (name && name[0])
1524 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1526 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1527 if (subkey != hkey) RegCloseKey( subkey );
1528 if (ret == ERROR_FILE_NOT_FOUND)
1530 /* return empty string if default value not found */
1531 if (data) *data = 0;
1532 if (count) *count = sizeof(WCHAR);
1533 ret = ERROR_SUCCESS;
1539 /******************************************************************************
1540 * RegQueryValueA [ADVAPI32.@]
1542 * See RegQueryValueW.
1544 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1549 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1551 if (name && name[0])
1553 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1555 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1556 if (subkey != hkey) RegCloseKey( subkey );
1557 if (ret == ERROR_FILE_NOT_FOUND)
1559 /* return empty string if default value not found */
1560 if (data) *data = 0;
1561 if (count) *count = 1;
1562 ret = ERROR_SUCCESS;
1568 /******************************************************************************
1569 * ADVAPI_ApplyRestrictions [internal]
1571 * Helper function for RegGetValueA/W.
1573 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1574 DWORD cbData, PLONG ret )
1576 /* Check if the type is restricted by the passed flags */
1577 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1583 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1584 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1585 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1586 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1587 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1588 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1589 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1592 if (dwFlags & dwMask)
1594 /* Type is not restricted, check for size mismatch */
1595 if (dwType == REG_BINARY)
1599 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1601 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1604 if (cbExpect && cbData != cbExpect)
1605 *ret = ERROR_DATATYPE_MISMATCH;
1608 else *ret = ERROR_UNSUPPORTED_TYPE;
1613 /******************************************************************************
1614 * RegGetValueW [ADVAPI32.@]
1616 * Retrieves the type and data for a value name associated with a key,
1617 * optionally expanding its content and restricting its type.
1620 * hKey [I] Handle to an open key.
1621 * pszSubKey [I] Name of the subkey of hKey.
1622 * pszValue [I] Name of value under hKey/szSubKey to query.
1623 * dwFlags [I] Flags restricting the value type to retrieve.
1624 * pdwType [O] Destination for the values type, may be NULL.
1625 * pvData [O] Destination for the values content, may be NULL.
1626 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1627 * retrieve the whole content, including the trailing '\0'
1631 * Success: ERROR_SUCCESS
1632 * Failure: nonzero error code from Winerror.h
1635 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1636 * expanded and pdwType is set to REG_SZ instead.
1637 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1638 * without RRF_NOEXPAND is thus not allowed.
1639 * An exception is the case where RRF_RT_ANY is specified, because then
1640 * RRF_NOEXPAND is allowed.
1642 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1643 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1646 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1650 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1651 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1652 pvData, pcbData, cbData);
1654 if (pvData && !pcbData)
1655 return ERROR_INVALID_PARAMETER;
1656 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1657 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1658 return ERROR_INVALID_PARAMETER;
1660 if (pszSubKey && pszSubKey[0])
1662 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1663 if (ret != ERROR_SUCCESS) return ret;
1666 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1668 /* If we are going to expand we need to read in the whole the value even
1669 * if the passed buffer was too small as the expanded string might be
1670 * smaller than the unexpanded one and could fit into cbData bytes. */
1671 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1672 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1675 HeapFree(GetProcessHeap(), 0, pvBuf);
1677 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1680 ret = ERROR_NOT_ENOUGH_MEMORY;
1684 if (ret == ERROR_MORE_DATA || !pvData)
1685 ret = RegQueryValueExW(hKey, pszValue, NULL,
1686 &dwType, pvBuf, &cbData);
1689 /* Even if cbData was large enough we have to copy the
1690 * string since ExpandEnvironmentStrings can't handle
1691 * overlapping buffers. */
1692 CopyMemory(pvBuf, pvData, cbData);
1695 /* Both the type or the value itself could have been modified in
1696 * between so we have to keep retrying until the buffer is large
1697 * enough or we no longer have to expand the value. */
1698 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1700 if (ret == ERROR_SUCCESS)
1702 /* Recheck dwType in case it changed since the first call */
1703 if (dwType == REG_EXPAND_SZ)
1705 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1706 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1708 if(pvData && pcbData && cbData > *pcbData)
1709 ret = ERROR_MORE_DATA;
1712 CopyMemory(pvData, pvBuf, *pcbData);
1715 HeapFree(GetProcessHeap(), 0, pvBuf);
1718 if (pszSubKey && pszSubKey[0])
1721 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1723 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1724 ZeroMemory(pvData, *pcbData);
1726 if (pdwType) *pdwType = dwType;
1727 if (pcbData) *pcbData = cbData;
1733 /******************************************************************************
1734 * RegGetValueA [ADVAPI32.@]
1738 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1739 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1742 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1746 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1747 hKey, debugstr_a(pszSubKey), debugstr_a(pszValue), dwFlags,
1748 pdwType, pvData, pcbData, cbData);
1750 if (pvData && !pcbData)
1751 return ERROR_INVALID_PARAMETER;
1752 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1753 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1754 return ERROR_INVALID_PARAMETER;
1756 if (pszSubKey && pszSubKey[0])
1758 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1759 if (ret != ERROR_SUCCESS) return ret;
1762 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1764 /* If we are going to expand we need to read in the whole the value even
1765 * if the passed buffer was too small as the expanded string might be
1766 * smaller than the unexpanded one and could fit into cbData bytes. */
1767 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1768 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1771 HeapFree(GetProcessHeap(), 0, pvBuf);
1773 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1776 ret = ERROR_NOT_ENOUGH_MEMORY;
1780 if (ret == ERROR_MORE_DATA || !pvData)
1781 ret = RegQueryValueExA(hKey, pszValue, NULL,
1782 &dwType, pvBuf, &cbData);
1785 /* Even if cbData was large enough we have to copy the
1786 * string since ExpandEnvironmentStrings can't handle
1787 * overlapping buffers. */
1788 CopyMemory(pvBuf, pvData, cbData);
1791 /* Both the type or the value itself could have been modified in
1792 * between so we have to keep retrying until the buffer is large
1793 * enough or we no longer have to expand the value. */
1794 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1796 if (ret == ERROR_SUCCESS)
1798 /* Recheck dwType in case it changed since the first call */
1799 if (dwType == REG_EXPAND_SZ)
1801 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1802 pcbData ? *pcbData : 0);
1804 if(pvData && pcbData && cbData > *pcbData)
1805 ret = ERROR_MORE_DATA;
1808 CopyMemory(pvData, pvBuf, *pcbData);
1811 HeapFree(GetProcessHeap(), 0, pvBuf);
1814 if (pszSubKey && pszSubKey[0])
1817 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1819 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1820 ZeroMemory(pvData, *pcbData);
1822 if (pdwType) *pdwType = dwType;
1823 if (pcbData) *pcbData = cbData;
1829 /******************************************************************************
1830 * RegEnumValueW [ADVAPI32.@]
1832 * Enumerates the values for the specified open registry key.
1835 * hkey [I] Handle to key to query
1836 * index [I] Index of value to query
1837 * value [O] Value string
1838 * val_count [I/O] Size of value buffer (in wchars)
1839 * reserved [I] Reserved
1840 * type [O] Type code
1841 * data [O] Value data
1842 * count [I/O] Size of data buffer (in bytes)
1845 * Success: ERROR_SUCCESS
1846 * Failure: nonzero error code from Winerror.h
1849 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1850 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1854 char buffer[256], *buf_ptr = buffer;
1855 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1856 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1858 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1859 hkey, index, value, val_count, reserved, type, data, count );
1861 /* NT only checks count, not val_count */
1862 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1863 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1865 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1866 if (data) total_size += *count;
1867 total_size = min( sizeof(buffer), total_size );
1869 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1870 buffer, total_size, &total_size );
1871 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1875 /* retry with a dynamically allocated buffer */
1876 while (status == STATUS_BUFFER_OVERFLOW)
1878 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1879 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1880 return ERROR_NOT_ENOUGH_MEMORY;
1881 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1882 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1883 buf_ptr, total_size, &total_size );
1886 if (status) goto done;
1890 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1892 status = STATUS_BUFFER_OVERFLOW;
1895 memcpy( value, info->Name, info->NameLength );
1896 *val_count = info->NameLength / sizeof(WCHAR);
1897 value[*val_count] = 0;
1902 if (total_size - info->DataOffset > *count)
1904 status = STATUS_BUFFER_OVERFLOW;
1907 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1908 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1910 /* if the type is REG_SZ and data is not 0-terminated
1911 * and there is enough space in the buffer NT appends a \0 */
1912 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1913 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1917 else status = STATUS_SUCCESS;
1920 if (type) *type = info->Type;
1921 if (count) *count = info->DataLength;
1924 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1925 return RtlNtStatusToDosError(status);
1929 /******************************************************************************
1930 * RegEnumValueA [ADVAPI32.@]
1932 * See RegEnumValueW.
1934 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1935 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1939 char buffer[256], *buf_ptr = buffer;
1940 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1941 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1943 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1944 hkey, index, value, val_count, reserved, type, data, count );
1946 /* NT only checks count, not val_count */
1947 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1948 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1950 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1951 if (data) total_size += *count;
1952 total_size = min( sizeof(buffer), total_size );
1954 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1955 buffer, total_size, &total_size );
1956 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1958 /* we need to fetch the contents for a string type even if not requested,
1959 * because we need to compute the length of the ASCII string. */
1960 if (value || data || is_string(info->Type))
1962 /* retry with a dynamically allocated buffer */
1963 while (status == STATUS_BUFFER_OVERFLOW)
1965 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1966 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1967 return ERROR_NOT_ENOUGH_MEMORY;
1968 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1969 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1970 buf_ptr, total_size, &total_size );
1973 if (status) goto done;
1975 if (is_string(info->Type))
1978 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1979 total_size - info->DataOffset );
1982 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1985 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1986 total_size - info->DataOffset );
1987 /* if the type is REG_SZ and data is not 0-terminated
1988 * and there is enough space in the buffer NT appends a \0 */
1989 if (len < *count && data[len-1]) data[len] = 0;
1992 info->DataLength = len;
1996 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1997 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2000 if (value && !status)
2004 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2005 if (len >= *val_count)
2007 status = STATUS_BUFFER_OVERFLOW;
2010 len = *val_count - 1;
2011 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2017 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2023 else status = STATUS_SUCCESS;
2025 if (type) *type = info->Type;
2026 if (count) *count = info->DataLength;
2029 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2030 return RtlNtStatusToDosError(status);
2035 /******************************************************************************
2036 * RegDeleteValueW [ADVAPI32.@]
2038 * See RegDeleteValueA.
2040 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2042 UNICODE_STRING nameW;
2044 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2046 RtlInitUnicodeString( &nameW, name );
2047 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2051 /******************************************************************************
2052 * RegDeleteValueA [ADVAPI32.@]
2054 * Delete a value from the registry.
2057 * hkey [I] Registry handle of the key holding the value
2058 * name [I] Name of the value under hkey to delete
2061 * Success: ERROR_SUCCESS
2062 * Failure: nonzero error code from Winerror.h
2064 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2067 UNICODE_STRING nameW;
2070 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2072 RtlInitAnsiString( &nameA, name );
2073 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2075 status = NtDeleteValueKey( hkey, &nameW );
2076 RtlFreeUnicodeString( &nameW );
2078 return RtlNtStatusToDosError( status );
2082 /******************************************************************************
2083 * RegLoadKeyW [ADVAPI32.@]
2085 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2086 * registration information from a specified file into that subkey.
2089 * hkey [I] Handle of open key
2090 * subkey [I] Address of name of subkey
2091 * filename [I] Address of filename for registry information
2094 * Success: ERROR_SUCCESS
2095 * Failure: nonzero error code from Winerror.h
2097 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2099 OBJECT_ATTRIBUTES destkey, file;
2100 UNICODE_STRING subkeyW, filenameW;
2103 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
2105 destkey.Length = sizeof(destkey);
2106 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2107 destkey.ObjectName = &subkeyW; /* name of the key */
2108 destkey.Attributes = 0;
2109 destkey.SecurityDescriptor = NULL;
2110 destkey.SecurityQualityOfService = NULL;
2111 RtlInitUnicodeString(&subkeyW, subkey);
2113 file.Length = sizeof(file);
2114 file.RootDirectory = NULL;
2115 file.ObjectName = &filenameW; /* file containing the hive */
2116 file.Attributes = OBJ_CASE_INSENSITIVE;
2117 file.SecurityDescriptor = NULL;
2118 file.SecurityQualityOfService = NULL;
2119 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2121 status = NtLoadKey(&destkey, &file);
2122 RtlFreeUnicodeString(&filenameW);
2123 return RtlNtStatusToDosError( status );
2127 /******************************************************************************
2128 * RegLoadKeyA [ADVAPI32.@]
2132 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2134 UNICODE_STRING subkeyW, filenameW;
2135 STRING subkeyA, filenameA;
2139 RtlInitAnsiString(&subkeyA, subkey);
2140 RtlInitAnsiString(&filenameA, filename);
2142 RtlInitUnicodeString(&subkeyW, NULL);
2143 RtlInitUnicodeString(&filenameW, NULL);
2144 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2145 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2147 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2149 else ret = RtlNtStatusToDosError(status);
2150 RtlFreeUnicodeString(&subkeyW);
2151 RtlFreeUnicodeString(&filenameW);
2156 /******************************************************************************
2157 * RegSaveKeyW [ADVAPI32.@]
2159 * Save a key and all of its subkeys and values to a new file in the standard format.
2162 * hkey [I] Handle of key where save begins
2163 * lpFile [I] Address of filename to save to
2164 * sa [I] Address of security structure
2167 * Success: ERROR_SUCCESS
2168 * Failure: nonzero error code from Winerror.h
2170 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2172 static const WCHAR format[] =
2173 {'r','e','g','%','0','4','x','.','t','m','p',0};
2174 WCHAR buffer[MAX_PATH];
2180 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2182 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2183 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2185 err = GetLastError();
2186 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2190 snprintfW( nameW, 16, format, count++ );
2191 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2192 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2193 if (handle != INVALID_HANDLE_VALUE) break;
2194 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2196 /* Something gone haywire ? Please report if this happens abnormally */
2198 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);
2201 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2203 CloseHandle( handle );
2206 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2208 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2210 ret = GetLastError();
2213 if (ret) DeleteFileW( buffer );
2216 SetLastError( err ); /* restore last error code */
2221 /******************************************************************************
2222 * RegSaveKeyA [ADVAPI32.@]
2226 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2228 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2232 RtlInitAnsiString(&fileA, file);
2233 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2234 return RtlNtStatusToDosError( status );
2235 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2239 /******************************************************************************
2240 * RegRestoreKeyW [ADVAPI32.@]
2242 * Read the registry information from a file and copy it over a key.
2245 * hkey [I] Handle of key where restore begins
2246 * lpFile [I] Address of filename containing saved tree
2247 * dwFlags [I] Optional flags
2250 * Success: ERROR_SUCCESS
2251 * Failure: nonzero error code from Winerror.h
2253 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2255 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2257 /* It seems to do this check before the hkey check */
2258 if (!lpFile || !*lpFile)
2259 return ERROR_INVALID_PARAMETER;
2261 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2263 /* Check for file existence */
2265 return ERROR_SUCCESS;
2269 /******************************************************************************
2270 * RegRestoreKeyA [ADVAPI32.@]
2272 * See RegRestoreKeyW.
2274 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2276 UNICODE_STRING lpFileW;
2279 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2280 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2281 RtlFreeUnicodeString( &lpFileW );
2286 /******************************************************************************
2287 * RegUnLoadKeyW [ADVAPI32.@]
2289 * Unload a registry key and its subkeys from the registry.
2292 * hkey [I] Handle of open key
2293 * lpSubKey [I] Address of name of subkey to unload
2296 * Success: ERROR_SUCCESS
2297 * Failure: nonzero error code from Winerror.h
2299 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2303 OBJECT_ATTRIBUTES attr;
2304 UNICODE_STRING subkey;
2306 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2308 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2310 return ERROR_INVALID_PARAMETER;
2312 RtlInitUnicodeString(&subkey, lpSubKey);
2313 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2314 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2322 /******************************************************************************
2323 * RegUnLoadKeyA [ADVAPI32.@]
2325 * See RegUnLoadKeyW.
2327 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2329 UNICODE_STRING lpSubKeyW;
2332 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2333 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2334 RtlFreeUnicodeString( &lpSubKeyW );
2339 /******************************************************************************
2340 * RegReplaceKeyW [ADVAPI32.@]
2342 * Replace the file backing a registry key and all its subkeys with another file.
2345 * hkey [I] Handle of open key
2346 * lpSubKey [I] Address of name of subkey
2347 * lpNewFile [I] Address of filename for file with new data
2348 * lpOldFile [I] Address of filename for backup file
2351 * Success: ERROR_SUCCESS
2352 * Failure: nonzero error code from Winerror.h
2354 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2357 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2358 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2359 return ERROR_SUCCESS;
2363 /******************************************************************************
2364 * RegReplaceKeyA [ADVAPI32.@]
2366 * See RegReplaceKeyW.
2368 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2371 UNICODE_STRING lpSubKeyW;
2372 UNICODE_STRING lpNewFileW;
2373 UNICODE_STRING lpOldFileW;
2376 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2377 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2378 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2379 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2380 RtlFreeUnicodeString( &lpOldFileW );
2381 RtlFreeUnicodeString( &lpNewFileW );
2382 RtlFreeUnicodeString( &lpSubKeyW );
2387 /******************************************************************************
2388 * RegSetKeySecurity [ADVAPI32.@]
2390 * Set the security of an open registry key.
2393 * hkey [I] Open handle of key to set
2394 * SecurityInfo [I] Descriptor contents
2395 * pSecurityDesc [I] Address of descriptor for key
2398 * Success: ERROR_SUCCESS
2399 * Failure: nonzero error code from Winerror.h
2401 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2402 PSECURITY_DESCRIPTOR pSecurityDesc )
2404 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2406 /* It seems to perform this check before the hkey check */
2407 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2408 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2409 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2410 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2413 return ERROR_INVALID_PARAMETER;
2416 return ERROR_INVALID_PARAMETER;
2418 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2420 return ERROR_SUCCESS;
2424 /******************************************************************************
2425 * RegGetKeySecurity [ADVAPI32.@]
2427 * Get a copy of the security descriptor for a given registry key.
2430 * hkey [I] Open handle of key to set
2431 * SecurityInformation [I] Descriptor contents
2432 * pSecurityDescriptor [O] Address of descriptor for key
2433 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2436 * Success: ERROR_SUCCESS
2437 * Failure: Error code
2439 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2440 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2441 LPDWORD lpcbSecurityDescriptor )
2443 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2444 *lpcbSecurityDescriptor);
2446 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2448 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2449 SecurityInformation, pSecurityDescriptor,
2450 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2454 /******************************************************************************
2455 * RegFlushKey [ADVAPI32.@]
2457 * Immediately write a registry key to registry.
2460 * hkey [I] Handle of key to write
2463 * Success: ERROR_SUCCESS
2464 * Failure: Error code
2466 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2468 hkey = get_special_root_hkey( hkey );
2469 if (!hkey) return ERROR_INVALID_HANDLE;
2471 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2475 /******************************************************************************
2476 * RegConnectRegistryW [ADVAPI32.@]
2478 * Establish a connection to a predefined registry key on another computer.
2481 * lpMachineName [I] Address of name of remote computer
2482 * hHey [I] Predefined registry handle
2483 * phkResult [I] Address of buffer for remote registry handle
2486 * Success: ERROR_SUCCESS
2487 * Failure: nonzero error code from Winerror.h
2489 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2494 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName), hKey, phkResult);
2496 if (!lpMachineName || !*lpMachineName) {
2497 /* Use the local machine name */
2498 ret = RegOpenKeyW( hKey, NULL, phkResult );
2501 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2502 DWORD len = sizeof(compName) / sizeof(WCHAR);
2504 /* MSDN says lpMachineName must start with \\ : not so */
2505 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2507 if (GetComputerNameW(compName, &len))
2509 if (!strcmpiW(lpMachineName, compName))
2510 ret = RegOpenKeyW(hKey, NULL, phkResult);
2513 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2514 ret = ERROR_BAD_NETPATH;
2518 ret = GetLastError();
2524 /******************************************************************************
2525 * RegConnectRegistryA [ADVAPI32.@]
2527 * See RegConnectRegistryW.
2529 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2531 UNICODE_STRING machineW;
2534 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2535 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2536 RtlFreeUnicodeString( &machineW );
2541 /******************************************************************************
2542 * RegNotifyChangeKeyValue [ADVAPI32.@]
2544 * Notify the caller about changes to the attributes or contents of a registry key.
2547 * hkey [I] Handle of key to watch
2548 * fWatchSubTree [I] Flag for subkey notification
2549 * fdwNotifyFilter [I] Changes to be reported
2550 * hEvent [I] Handle of signaled event
2551 * fAsync [I] Flag for asynchronous reporting
2554 * Success: ERROR_SUCCESS
2555 * Failure: nonzero error code from Winerror.h
2557 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2558 DWORD fdwNotifyFilter, HANDLE hEvent,
2562 IO_STATUS_BLOCK iosb;
2564 hkey = get_special_root_hkey( hkey );
2565 if (!hkey) return ERROR_INVALID_HANDLE;
2567 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2570 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2571 fdwNotifyFilter, fAsync, NULL, 0,
2574 if (status && status != STATUS_TIMEOUT)
2575 return RtlNtStatusToDosError( status );
2577 return ERROR_SUCCESS;
2580 /******************************************************************************
2581 * RegOpenUserClassesRoot [ADVAPI32.@]
2583 * Open the HKEY_CLASSES_ROOT key for a user.
2586 * hToken [I] Handle of token representing the user
2587 * dwOptions [I] Reserved, must be 0
2588 * samDesired [I] Desired access rights
2589 * phkResult [O] Destination for the resulting key handle
2592 * Success: ERROR_SUCCESS
2593 * Failure: nonzero error code from Winerror.h
2596 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2597 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2598 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2600 LSTATUS WINAPI RegOpenUserClassesRoot(
2607 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2609 *phkResult = HKEY_CLASSES_ROOT;
2610 return ERROR_SUCCESS;
2613 /******************************************************************************
2614 * load_string [Internal]
2616 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2617 * avoid importing user32, which is higher level than advapi32. Helper for
2620 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2627 /* Negative values have to be inverted. */
2628 if (HIWORD(resId) == 0xffff)
2629 resId = (UINT)(-((INT)resId));
2631 /* Load the resource into memory and get a pointer to it. */
2632 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2633 if (!hResource) return 0;
2634 hMemory = LoadResource(hModule, hResource);
2635 if (!hMemory) return 0;
2636 pString = LockResource(hMemory);
2638 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2639 idxString = resId & 0xf;
2640 while (idxString--) pString += *pString + 1;
2642 /* If no buffer is given, return length of the string. */
2643 if (!pwszBuffer) return *pString;
2645 /* Else copy over the string, respecting the buffer size. */
2646 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2647 if (cMaxChars >= 0) {
2648 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2649 pwszBuffer[cMaxChars] = '\0';
2655 /******************************************************************************
2656 * RegLoadMUIStringW [ADVAPI32.@]
2658 * Load the localized version of a string resource from some PE, respective
2659 * id and path of which are given in the registry value in the format
2660 * @[path]\dllname,-resourceId
2663 * hKey [I] Key, of which to load the string value from.
2664 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2665 * pszBuffer [O] Buffer to store the localized string in.
2666 * cbBuffer [I] Size of the destination buffer in bytes.
2667 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2668 * dwFlags [I] None supported yet.
2669 * pszBaseDir [I] Not supported yet.
2672 * Success: ERROR_SUCCESS,
2673 * Failure: nonzero error code from winerror.h
2676 * This is an API of Windows Vista, which wasn't available at the time this code
2677 * was written. We have to check for the correct behaviour once it's available.
2679 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2680 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2682 DWORD dwValueType, cbData;
2683 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2686 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2687 "dwFlags = %d, pwszBaseDir = %s)\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2688 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2690 /* Parameter sanity checks. */
2691 if (!hKey || !pwszBuffer)
2692 return ERROR_INVALID_PARAMETER;
2694 if (pwszBaseDir && *pwszBaseDir) {
2695 FIXME("BaseDir parameter not yet supported!\n");
2696 return ERROR_INVALID_PARAMETER;
2699 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2700 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2701 if (result != ERROR_SUCCESS) goto cleanup;
2702 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2703 result = ERROR_FILE_NOT_FOUND;
2706 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2707 if (!pwszTempBuffer) {
2708 result = ERROR_NOT_ENOUGH_MEMORY;
2711 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2712 if (result != ERROR_SUCCESS) goto cleanup;
2714 /* Expand environment variables, if appropriate, or copy the original string over. */
2715 if (dwValueType == REG_EXPAND_SZ) {
2716 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2717 if (!cbData) goto cleanup;
2718 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2719 if (!pwszExpandedBuffer) {
2720 result = ERROR_NOT_ENOUGH_MEMORY;
2723 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2725 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2726 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2729 /* If the value references a resource based string, parse the value and load the string.
2730 * Else just copy over the original value. */
2731 result = ERROR_SUCCESS;
2732 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2733 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2735 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2739 /* Format of the expanded value is 'path_to_dll,-resId' */
2740 if (!pComma || pComma[1] != '-') {
2741 result = ERROR_BADKEY;
2745 uiStringId = atoiW(pComma+2);
2748 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2749 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2750 result = ERROR_BADKEY;
2751 FreeLibrary(hModule);
2755 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2756 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2760 /******************************************************************************
2761 * RegLoadMUIStringA [ADVAPI32.@]
2763 * See RegLoadMUIStringW
2765 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2766 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2768 UNICODE_STRING valueW, baseDirW;
2770 DWORD cbData = cbBuffer * sizeof(WCHAR);
2773 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2774 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2775 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2776 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2778 result = ERROR_NOT_ENOUGH_MEMORY;
2782 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2785 if (result == ERROR_SUCCESS) {
2786 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2792 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2793 RtlFreeUnicodeString(&baseDirW);
2794 RtlFreeUnicodeString(&valueW);
2799 /******************************************************************************
2800 * RegDisablePredefinedCache [ADVAPI32.@]
2802 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2808 * Success: ERROR_SUCCESS
2809 * Failure: nonzero error code from Winerror.h
2812 * This is useful for services that use impersonation.
2814 LSTATUS WINAPI RegDisablePredefinedCache(void)
2816 HKEY hkey_current_user;
2817 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2819 /* prevent caching of future requests */
2820 hkcu_cache_disabled = TRUE;
2822 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2824 if (hkey_current_user)
2825 NtClose( hkey_current_user );
2827 return ERROR_SUCCESS;
2830 /******************************************************************************
2831 * RegDeleteTreeW [ADVAPI32.@]
2834 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2837 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2838 DWORD dwMaxLen, dwSize;
2839 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2840 HKEY hSubKey = hKey;
2842 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2846 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2847 if (ret) return ret;
2850 /* Get highest length for keys, values */
2851 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2852 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2853 if (ret) goto cleanup;
2857 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2858 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2860 /* Name too big: alloc a buffer for it */
2861 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2863 ret = ERROR_NOT_ENOUGH_MEMORY;
2869 /* Recursively delete all the subkeys */
2873 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2874 NULL, NULL, NULL)) break;
2876 ret = RegDeleteTreeW(hSubKey, lpszName);
2877 if (ret) goto cleanup;
2881 ret = RegDeleteKeyW(hKey, lpszSubKey);
2886 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2887 NULL, NULL, NULL, NULL)) break;
2889 ret = RegDeleteValueW(hKey, lpszName);
2890 if (ret) goto cleanup;
2894 /* Free buffer if allocated */
2895 if (lpszName != szNameBuf)
2896 HeapFree( GetProcessHeap(), 0, lpszName);
2898 RegCloseKey(hSubKey);
2902 /******************************************************************************
2903 * RegDeleteTreeA [ADVAPI32.@]
2906 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2909 UNICODE_STRING lpszSubKeyW;
2911 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2912 else lpszSubKeyW.Buffer = NULL;
2913 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2914 RtlFreeUnicodeString( &lpszSubKeyW );
2918 /******************************************************************************
2919 * RegDisableReflectionKey [ADVAPI32.@]
2922 LONG WINAPI RegDisableReflectionKey(HKEY base)
2924 FIXME("%p: stub\n", base);
2925 return ERROR_SUCCESS;