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 file is concerned about handle management and interaction with the Wine server.
12 * Registry file I/O is in misc/registry.c.
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #define WIN32_NO_STATUS
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(reg);
47 /* allowed bits for access mask */
48 #define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
50 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
51 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
52 #define NB_SPECIAL_ROOT_KEYS ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
54 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
55 static BOOL hkcu_cache_disabled;
57 static const WCHAR name_CLASSES_ROOT[] =
58 {'M','a','c','h','i','n','e','\\',
59 'S','o','f','t','w','a','r','e','\\',
60 'C','l','a','s','s','e','s',0};
61 static const WCHAR name_LOCAL_MACHINE[] =
62 {'M','a','c','h','i','n','e',0};
63 static const WCHAR name_USERS[] =
65 static const WCHAR name_PERFORMANCE_DATA[] =
66 {'P','e','r','f','D','a','t','a',0};
67 static const WCHAR name_CURRENT_CONFIG[] =
68 {'M','a','c','h','i','n','e','\\',
69 'S','y','s','t','e','m','\\',
70 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
71 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
72 'C','u','r','r','e','n','t',0};
73 static const WCHAR name_DYN_DATA[] =
74 {'D','y','n','D','a','t','a',0};
76 static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] =
79 NULL, /* HKEY_CURRENT_USER is determined dynamically */
82 name_PERFORMANCE_DATA,
88 /* check if value type needs string conversion (Ansi<->Unicode) */
89 static inline int is_string( DWORD type )
91 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
94 /* check if current version is NT or Win95 */
95 static inline int is_version_nt(void)
97 return !(GetVersion() & 0x80000000);
100 /* create one of the HKEY_* special root keys */
101 static HKEY create_special_root_hkey( HANDLE hkey, DWORD access )
104 int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
106 if (hkey == HKEY_CURRENT_USER)
108 if (RtlOpenCurrentUser( access, &hkey )) return 0;
109 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
111 /* don't cache the key in the table if caching is disabled */
112 if (hkcu_cache_disabled)
117 OBJECT_ATTRIBUTES attr;
120 attr.Length = sizeof(attr);
121 attr.RootDirectory = 0;
122 attr.ObjectName = &name;
124 attr.SecurityDescriptor = NULL;
125 attr.SecurityQualityOfService = NULL;
126 RtlInitUnicodeString( &name, root_key_names[idx] );
127 if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
128 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
131 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
134 NtClose( hkey ); /* somebody beat us to it */
138 /* map the hkey from special root to normal key if necessary */
139 static inline HKEY get_special_root_hkey( HKEY hkey )
143 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
145 if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
146 ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
152 /******************************************************************************
153 * RegOverridePredefKey [ADVAPI32.@]
155 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
160 if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST))
161 return ERROR_INVALID_PARAMETER;
162 idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
166 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
167 GetCurrentProcess(), (HANDLE *)&override,
168 0, 0, DUPLICATE_SAME_ACCESS );
169 if (status) return RtlNtStatusToDosError( status );
172 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
173 if (old_key) NtClose( old_key );
174 return ERROR_SUCCESS;
178 /******************************************************************************
179 * RegCreateKeyExW [ADVAPI32.@]
181 * See RegCreateKeyExA.
183 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
184 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
185 PHKEY retkey, LPDWORD dispos )
187 OBJECT_ATTRIBUTES attr;
188 UNICODE_STRING nameW, classW;
190 if (reserved) return ERROR_INVALID_PARAMETER;
191 if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
192 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
194 attr.Length = sizeof(attr);
195 attr.RootDirectory = hkey;
196 attr.ObjectName = &nameW;
198 attr.SecurityDescriptor = NULL;
199 attr.SecurityQualityOfService = NULL;
200 RtlInitUnicodeString( &nameW, name );
201 RtlInitUnicodeString( &classW, class );
203 return RtlNtStatusToDosError( NtCreateKey( (PHANDLE)retkey, access, &attr, 0,
204 &classW, options, dispos ) );
208 /******************************************************************************
209 * RegCreateKeyExA [ADVAPI32.@]
211 * Open a registry key, creating it if it doesn't exist.
214 * hkey [I] Handle of the parent registry key
215 * name [I] Name of the new key to open or create
216 * reserved [I] Reserved, pass 0
217 * class [I] The object type of the new key
218 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
219 * access [I] Access level desired
220 * sa [I] Security attributes for the key
221 * retkey [O] Destination for the resulting handle
222 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
225 * Success: ERROR_SUCCESS.
226 * Failure: A standard Win32 error code. retkey remains untouched.
229 * MAXIMUM_ALLOWED in access mask not supported by server
231 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
232 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
233 PHKEY retkey, LPDWORD dispos )
235 OBJECT_ATTRIBUTES attr;
236 UNICODE_STRING classW;
237 ANSI_STRING nameA, classA;
240 if (reserved) return ERROR_INVALID_PARAMETER;
241 if (!is_version_nt())
243 access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
244 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
246 else if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
247 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
249 attr.Length = sizeof(attr);
250 attr.RootDirectory = hkey;
251 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
253 attr.SecurityDescriptor = NULL;
254 attr.SecurityQualityOfService = NULL;
255 RtlInitAnsiString( &nameA, name );
256 RtlInitAnsiString( &classA, class );
258 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
261 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
263 status = NtCreateKey( (PHANDLE)retkey, access, &attr, 0, &classW, options, dispos );
264 RtlFreeUnicodeString( &classW );
267 return RtlNtStatusToDosError( status );
271 /******************************************************************************
272 * RegCreateKeyW [ADVAPI32.@]
274 * Creates the specified reg key.
277 * hKey [I] Handle to an open key.
278 * lpSubKey [I] Name of a key that will be opened or created.
279 * phkResult [O] Receives a handle to the opened or created key.
282 * Success: ERROR_SUCCESS
283 * Failure: nonzero error code defined in Winerror.h
285 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
287 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
288 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
289 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
290 KEY_ALL_ACCESS, NULL, phkResult, NULL );
294 /******************************************************************************
295 * RegCreateKeyA [ADVAPI32.@]
299 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
301 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
302 KEY_ALL_ACCESS, NULL, phkResult, NULL );
307 /******************************************************************************
308 * RegOpenKeyExW [ADVAPI32.@]
312 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
314 OBJECT_ATTRIBUTES attr;
315 UNICODE_STRING nameW;
317 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
319 attr.Length = sizeof(attr);
320 attr.RootDirectory = hkey;
321 attr.ObjectName = &nameW;
323 attr.SecurityDescriptor = NULL;
324 attr.SecurityQualityOfService = NULL;
325 RtlInitUnicodeString( &nameW, name );
326 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE)retkey, access, &attr ) );
330 /******************************************************************************
331 * RegOpenKeyExA [ADVAPI32.@]
333 * Open a registry key.
336 * hkey [I] Handle of open key
337 * name [I] Name of subkey to open
338 * reserved [I] Reserved - must be zero
339 * access [I] Security access mask
340 * retkey [O] Handle to open key
343 * Success: ERROR_SUCCESS
344 * Failure: A standard Win32 error code. retkey is set to 0.
347 * Unlike RegCreateKeyExA(), this function will not create the key if it
350 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
352 OBJECT_ATTRIBUTES attr;
356 if (!is_version_nt()) access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
358 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
360 attr.Length = sizeof(attr);
361 attr.RootDirectory = hkey;
362 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
364 attr.SecurityDescriptor = NULL;
365 attr.SecurityQualityOfService = NULL;
367 RtlInitAnsiString( &nameA, name );
368 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
371 status = NtOpenKey( (PHANDLE)retkey, access, &attr );
373 return RtlNtStatusToDosError( status );
377 /******************************************************************************
378 * RegOpenKeyW [ADVAPI32.@]
382 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
387 return ERROR_SUCCESS;
389 return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
393 /******************************************************************************
394 * RegOpenKeyA [ADVAPI32.@]
396 * Open a registry key.
399 * hkey [I] Handle of parent key to open the new key under
400 * name [I] Name of the key under hkey to open
401 * retkey [O] Destination for the resulting Handle
404 * Success: ERROR_SUCCESS
405 * Failure: A standard Win32 error code. retkey is set to 0.
407 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
412 return ERROR_SUCCESS;
414 return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
418 /******************************************************************************
419 * RegOpenCurrentUser [ADVAPI32.@]
421 * Get a handle to the HKEY_CURRENT_USER key for the user
422 * the current thread is impersonating.
425 * access [I] Desired access rights to the key
426 * retkey [O] Handle to the opened key
429 * Success: ERROR_SUCCESS
430 * Failure: nonzero error code from Winerror.h
433 * This function is supposed to retrieve a handle to the
434 * HKEY_CURRENT_USER for the user the current thread is impersonating.
435 * Since Wine does not currently allow threads to impersonate other users,
436 * this stub should work fine.
438 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
440 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
445 /******************************************************************************
446 * RegEnumKeyExW [ADVAPI32.@]
448 * Enumerate subkeys of the specified open registry key.
451 * hkey [I] Handle to key to enumerate
452 * index [I] Index of subkey to enumerate
453 * name [O] Buffer for subkey name
454 * name_len [O] Size of subkey buffer
455 * reserved [I] Reserved
456 * class [O] Buffer for class string
457 * class_len [O] Size of class buffer
458 * ft [O] Time key last written to
461 * Success: ERROR_SUCCESS
462 * Failure: System error code. If there are no more subkeys available, the
463 * function returns ERROR_NO_MORE_ITEMS.
465 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
466 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
469 char buffer[256], *buf_ptr = buffer;
470 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
473 TRACE( "(%p,%d,%p,%p(%d),%p,%p,%p,%p)\n", hkey, index, name, name_len,
474 name_len ? *name_len : -1, reserved, class, class_len, ft );
476 if (reserved) return ERROR_INVALID_PARAMETER;
477 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
479 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
480 buffer, sizeof(buffer), &total_size );
482 while (status == STATUS_BUFFER_OVERFLOW)
484 /* retry with a dynamically allocated buffer */
485 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
486 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
487 return ERROR_NOT_ENOUGH_MEMORY;
488 info = (KEY_NODE_INFORMATION *)buf_ptr;
489 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
490 buf_ptr, total_size, &total_size );
495 DWORD len = info->NameLength / sizeof(WCHAR);
496 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
498 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
500 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
501 status = STATUS_BUFFER_OVERFLOW;
505 memcpy( name, info->Name, info->NameLength );
509 *class_len = cls_len;
512 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
519 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
520 return RtlNtStatusToDosError( status );
524 /******************************************************************************
525 * RegEnumKeyExA [ADVAPI32.@]
529 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
530 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
533 char buffer[256], *buf_ptr = buffer;
534 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
537 TRACE( "(%p,%d,%p,%p(%d),%p,%p,%p,%p)\n", hkey, index, name, name_len,
538 name_len ? *name_len : -1, reserved, class, class_len, ft );
540 if (reserved) return ERROR_INVALID_PARAMETER;
541 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
543 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
544 buffer, sizeof(buffer), &total_size );
546 while (status == STATUS_BUFFER_OVERFLOW)
548 /* retry with a dynamically allocated buffer */
549 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
550 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
551 return ERROR_NOT_ENOUGH_MEMORY;
552 info = (KEY_NODE_INFORMATION *)buf_ptr;
553 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
554 buf_ptr, total_size, &total_size );
561 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
562 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
564 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
566 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
567 status = STATUS_BUFFER_OVERFLOW;
571 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
575 *class_len = cls_len;
578 RtlUnicodeToMultiByteN( class, cls_len, NULL,
579 (WCHAR *)(buf_ptr + info->ClassOffset),
587 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
588 return RtlNtStatusToDosError( status );
592 /******************************************************************************
593 * RegEnumKeyW [ADVAPI32.@]
595 * Enumerates subkeys of the specified open reg key.
598 * hKey [I] Handle to an open key.
599 * dwIndex [I] Index of the subkey of hKey to retrieve.
600 * lpName [O] Name of the subkey.
601 * cchName [I] Size of lpName in TCHARS.
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 RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
610 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
614 /******************************************************************************
615 * RegEnumKeyA [ADVAPI32.@]
619 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
621 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
625 /******************************************************************************
626 * RegQueryInfoKeyW [ADVAPI32.@]
628 * Retrieves information about the specified registry key.
631 * hkey [I] Handle to key to query
632 * class [O] Buffer for class string
633 * class_len [O] Size of class string buffer
634 * reserved [I] Reserved
635 * subkeys [O] Buffer for number of subkeys
636 * max_subkey [O] Buffer for longest subkey name length
637 * max_class [O] Buffer for longest class string length
638 * values [O] Buffer for number of value entries
639 * max_value [O] Buffer for longest value name length
640 * max_data [O] Buffer for longest value data length
641 * security [O] Buffer for security descriptor length
642 * modif [O] Modification time
645 * Success: ERROR_SUCCESS
646 * Failure: system error code.
649 * - win95 allows class to be valid and class_len to be NULL
650 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
651 * - both allow class to be NULL and class_len to be NULL
652 * (it's hard to test validity, so test !NULL instead)
654 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
655 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
656 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
657 LPDWORD security, FILETIME *modif )
660 char buffer[256], *buf_ptr = buffer;
661 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
664 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
665 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
667 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
668 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
670 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
671 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
675 /* retry with a dynamically allocated buffer */
676 while (status == STATUS_BUFFER_OVERFLOW)
678 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
679 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
680 return ERROR_NOT_ENOUGH_MEMORY;
681 info = (KEY_FULL_INFORMATION *)buf_ptr;
682 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
685 if (status) goto done;
687 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
689 status = STATUS_BUFFER_OVERFLOW;
693 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
694 class[info->ClassLength/sizeof(WCHAR)] = 0;
697 else status = STATUS_SUCCESS;
699 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
700 if (subkeys) *subkeys = info->SubKeys;
701 if (max_subkey) *max_subkey = info->MaxNameLen;
702 if (max_class) *max_class = info->MaxClassLen;
703 if (values) *values = info->Values;
704 if (max_value) *max_value = info->MaxValueNameLen;
705 if (max_data) *max_data = info->MaxValueDataLen;
706 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
709 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
710 return RtlNtStatusToDosError( status );
714 /******************************************************************************
715 * RegQueryMultipleValuesA [ADVAPI32.@]
717 * Retrieves the type and data for a list of value names associated with a key.
720 * hKey [I] Handle to an open key.
721 * val_list [O] Array of VALENT structures that describes the entries.
722 * num_vals [I] Number of elements in val_list.
723 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
724 * ldwTotsize [I/O] Size of lpValueBuf.
727 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
728 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
731 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
732 LPSTR lpValueBuf, LPDWORD ldwTotsize )
735 DWORD maxBytes = *ldwTotsize;
737 LPSTR bufptr = lpValueBuf;
740 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
742 for(i=0; i < num_vals; ++i)
745 val_list[i].ve_valuelen=0;
746 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
747 if(status != ERROR_SUCCESS)
752 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
754 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
755 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
756 if(status != ERROR_SUCCESS)
761 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
763 bufptr += val_list[i].ve_valuelen;
766 *ldwTotsize += val_list[i].ve_valuelen;
768 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
772 /******************************************************************************
773 * RegQueryMultipleValuesW [ADVAPI32.@]
775 * See RegQueryMultipleValuesA.
777 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
778 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
781 DWORD maxBytes = *ldwTotsize;
783 LPSTR bufptr = (LPSTR)lpValueBuf;
786 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
788 for(i=0; i < num_vals; ++i)
790 val_list[i].ve_valuelen=0;
791 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
792 if(status != ERROR_SUCCESS)
797 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
799 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
800 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
801 if(status != ERROR_SUCCESS)
806 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
808 bufptr += val_list[i].ve_valuelen;
811 *ldwTotsize += val_list[i].ve_valuelen;
813 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
816 /******************************************************************************
817 * RegQueryInfoKeyA [ADVAPI32.@]
819 * Retrieves information about a registry key.
822 * hKey [I] Handle to an open key.
823 * lpClass [O] Class string of the key.
824 * lpcClass [I/O] size of lpClass.
825 * lpReserved [I] Reserved; must be NULL.
826 * lpcSubKeys [O] Number of subkeys contained by the key.
827 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
828 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
830 * lpcValues [O] Number of values associated with the key.
831 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
832 * lpcMaxValueLen [O] Longest data component among the key's values
833 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
834 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
837 * Success: ERROR_SUCCESS
838 * Failure: nonzero error code from Winerror.h
840 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
841 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
842 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
843 LPDWORD security, FILETIME *modif )
846 char buffer[256], *buf_ptr = buffer;
847 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
848 DWORD total_size, len;
850 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
851 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
853 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
854 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
856 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
857 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
859 if (class || class_len)
861 /* retry with a dynamically allocated buffer */
862 while (status == STATUS_BUFFER_OVERFLOW)
864 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
865 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
866 return ERROR_NOT_ENOUGH_MEMORY;
867 info = (KEY_FULL_INFORMATION *)buf_ptr;
868 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
871 if (status) goto done;
873 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
876 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
879 if (class && !status)
881 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
886 else status = STATUS_SUCCESS;
888 if (subkeys) *subkeys = info->SubKeys;
889 if (max_subkey) *max_subkey = info->MaxNameLen;
890 if (max_class) *max_class = info->MaxClassLen;
891 if (values) *values = info->Values;
892 if (max_value) *max_value = info->MaxValueNameLen;
893 if (max_data) *max_data = info->MaxValueDataLen;
894 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
897 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
898 return RtlNtStatusToDosError( status );
902 /******************************************************************************
903 * RegCloseKey [ADVAPI32.@]
905 * Close an open registry key.
908 * hkey [I] Handle of key to close
911 * Success: ERROR_SUCCESS
912 * Failure: Error code
914 LSTATUS WINAPI RegCloseKey( HKEY hkey )
916 if (!hkey) return ERROR_INVALID_HANDLE;
917 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
918 return RtlNtStatusToDosError( NtClose( hkey ) );
922 /******************************************************************************
923 * RegDeleteKeyW [ADVAPI32.@]
927 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
932 if (!name) return ERROR_INVALID_PARAMETER;
934 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
936 if (!(ret = RegOpenKeyExW( hkey, name, 0, DELETE, &tmp )))
938 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
941 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
946 /******************************************************************************
947 * RegDeleteKeyA [ADVAPI32.@]
949 * Delete a registry key.
952 * hkey [I] Handle to parent key containing the key to delete
953 * name [I] Name of the key user hkey to delete
957 * MSDN is wrong when it says that hkey must be opened with the DELETE access
958 * right. In reality, it opens a new handle with DELETE access.
961 * Success: ERROR_SUCCESS
962 * Failure: Error code
964 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
969 if (!name) return ERROR_INVALID_PARAMETER;
971 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
973 if (!(ret = RegOpenKeyExA( hkey, name, 0, DELETE, &tmp )))
975 if (!is_version_nt()) /* win95 does recursive key deletes */
979 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
981 if(RegDeleteKeyA(tmp, name)) /* recurse */
985 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
988 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
994 /******************************************************************************
995 * RegSetValueExW [ADVAPI32.@]
997 * Set the data and contents of a registry value.
1000 * hkey [I] Handle of key to set value for
1001 * name [I] Name of value to set
1002 * reserved [I] Reserved, must be zero
1003 * type [I] Type of the value being set
1004 * data [I] The new contents of the value to set
1005 * count [I] Size of data
1008 * Success: ERROR_SUCCESS
1009 * Failure: Error code
1011 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1012 DWORD type, CONST BYTE *data, DWORD count )
1014 UNICODE_STRING nameW;
1016 /* no need for version check, not implemented on win9x anyway */
1017 if (count && is_string(type))
1019 LPCWSTR str = (LPCWSTR)data;
1020 /* if user forgot to count terminating null, add it (yes NT does this) */
1021 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1022 count += sizeof(WCHAR);
1024 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1026 RtlInitUnicodeString( &nameW, name );
1027 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1031 /******************************************************************************
1032 * RegSetValueExA [ADVAPI32.@]
1034 * See RegSetValueExW.
1037 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1038 * NT does definitely care (aj)
1040 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1041 CONST BYTE *data, DWORD count )
1044 WCHAR *dataW = NULL;
1047 if (!is_version_nt()) /* win95 */
1051 if (!data) return ERROR_INVALID_PARAMETER;
1052 count = strlen((const char *)data) + 1;
1055 else if (count && is_string(type))
1057 /* if user forgot to count terminating null, add it (yes NT does this) */
1058 if (data[count-1] && !data[count]) count++;
1061 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1063 if (is_string( type )) /* need to convert to Unicode */
1066 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1067 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1068 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1070 data = (BYTE *)dataW;
1073 RtlInitAnsiString( &nameA, name );
1074 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1077 status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
1079 HeapFree( GetProcessHeap(), 0, dataW );
1080 return RtlNtStatusToDosError( status );
1084 /******************************************************************************
1085 * RegSetValueW [ADVAPI32.@]
1087 * Sets the data for the default or unnamed value of a reg key.
1090 * hKey [I] Handle to an open key.
1091 * lpSubKey [I] Name of a subkey of hKey.
1092 * dwType [I] Type of information to store.
1093 * lpData [I] String that contains the data to set for the default value.
1094 * cbData [I] Ignored.
1097 * Success: ERROR_SUCCESS
1098 * Failure: nonzero error code from Winerror.h
1100 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1105 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1107 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1109 if (name && name[0]) /* need to create the subkey */
1111 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1114 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1115 (strlenW( data ) + 1) * sizeof(WCHAR) );
1116 if (subkey != hkey) RegCloseKey( subkey );
1121 /******************************************************************************
1122 * RegSetValueA [ADVAPI32.@]
1126 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1131 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1133 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1135 if (name && name[0]) /* need to create the subkey */
1137 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1139 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1140 if (subkey != hkey) RegCloseKey( subkey );
1146 /******************************************************************************
1147 * RegQueryValueExW [ADVAPI32.@]
1149 * See RegQueryValueExA.
1151 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1152 LPBYTE data, LPDWORD count )
1155 UNICODE_STRING name_str;
1157 char buffer[256], *buf_ptr = buffer;
1158 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1159 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1161 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1162 hkey, debugstr_w(name), reserved, type, data, count,
1163 (count && data) ? *count : 0 );
1165 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1166 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1168 RtlInitUnicodeString( &name_str, name );
1170 if (data) total_size = min( sizeof(buffer), *count + info_size );
1173 total_size = info_size;
1174 if (count) *count = 0;
1177 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1178 buffer, total_size, &total_size );
1179 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1183 /* retry with a dynamically allocated buffer */
1184 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1186 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1187 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1188 return ERROR_NOT_ENOUGH_MEMORY;
1189 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1190 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1191 buf_ptr, total_size, &total_size );
1196 memcpy( data, buf_ptr + info_size, total_size - info_size );
1197 /* if the type is REG_SZ and data is not 0-terminated
1198 * and there is enough space in the buffer NT appends a \0 */
1199 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1201 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1202 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1205 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1207 else status = STATUS_SUCCESS;
1209 if (type) *type = info->Type;
1210 if (count) *count = total_size - info_size;
1213 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1214 return RtlNtStatusToDosError(status);
1218 /******************************************************************************
1219 * RegQueryValueExA [ADVAPI32.@]
1221 * Get the type and contents of a specified value under with a key.
1224 * hkey [I] Handle of the key to query
1225 * name [I] Name of value under hkey to query
1226 * reserved [I] Reserved - must be NULL
1227 * type [O] Destination for the value type, or NULL if not required
1228 * data [O] Destination for the values contents, or NULL if not required
1229 * count [I/O] Size of data, updated with the number of bytes returned
1232 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1233 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1234 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1235 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1238 * MSDN states that if data is too small it is partially filled. In reality
1239 * it remains untouched.
1241 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1242 LPBYTE data, LPDWORD count )
1246 DWORD total_size, datalen = 0;
1247 char buffer[256], *buf_ptr = buffer;
1248 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1249 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1251 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1252 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1254 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1255 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1257 if (count) datalen = *count;
1258 if (!data && count) *count = 0;
1260 /* this matches Win9x behaviour - NT sets *type to a random value */
1261 if (type) *type = REG_NONE;
1263 RtlInitAnsiString( &nameA, name );
1264 if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1266 return RtlNtStatusToDosError(status);
1268 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1269 KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
1270 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1272 /* we need to fetch the contents for a string type even if not requested,
1273 * because we need to compute the length of the ASCII string. */
1274 if (data || is_string(info->Type))
1276 /* retry with a dynamically allocated buffer */
1277 while (status == STATUS_BUFFER_OVERFLOW)
1279 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1280 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1282 status = STATUS_NO_MEMORY;
1285 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1286 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1287 KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1290 if (status) goto done;
1292 if (is_string(info->Type))
1296 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1297 total_size - info_size );
1300 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1303 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1304 total_size - info_size );
1305 /* if the type is REG_SZ and data is not 0-terminated
1306 * and there is enough space in the buffer NT appends a \0 */
1307 if (len < datalen && data[len-1]) data[len] = 0;
1310 total_size = len + info_size;
1314 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1315 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1318 else status = STATUS_SUCCESS;
1320 if (type) *type = info->Type;
1321 if (count) *count = total_size - info_size;
1324 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1325 return RtlNtStatusToDosError(status);
1329 /******************************************************************************
1330 * RegQueryValueW [ADVAPI32.@]
1332 * Retrieves the data associated with the default or unnamed value of a key.
1335 * hkey [I] Handle to an open key.
1336 * name [I] Name of the subkey of hKey.
1337 * data [O] Receives the string associated with the default value
1339 * count [I/O] Size of lpValue in bytes.
1342 * Success: ERROR_SUCCESS
1343 * Failure: nonzero error code from Winerror.h
1345 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1350 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1352 if (name && name[0])
1354 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1356 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1357 if (subkey != hkey) RegCloseKey( subkey );
1358 if (ret == ERROR_FILE_NOT_FOUND)
1360 /* return empty string if default value not found */
1361 if (data) *data = 0;
1362 if (count) *count = sizeof(WCHAR);
1363 ret = ERROR_SUCCESS;
1369 /******************************************************************************
1370 * RegQueryValueA [ADVAPI32.@]
1372 * See RegQueryValueW.
1374 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1379 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1381 if (name && name[0])
1383 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1385 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1386 if (subkey != hkey) RegCloseKey( subkey );
1387 if (ret == ERROR_FILE_NOT_FOUND)
1389 /* return empty string if default value not found */
1390 if (data) *data = 0;
1391 if (count) *count = 1;
1392 ret = ERROR_SUCCESS;
1398 /******************************************************************************
1399 * ADVAPI_ApplyRestrictions [internal]
1401 * Helper function for RegGetValueA/W.
1403 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1404 DWORD cbData, PLONG ret )
1406 /* Check if the type is restricted by the passed flags */
1407 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1413 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1414 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1415 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1416 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1417 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1418 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1419 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1422 if (dwFlags & dwMask)
1424 /* Type is not restricted, check for size mismatch */
1425 if (dwType == REG_BINARY)
1429 if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD)
1431 else if ((dwFlags & RRF_RT_QWORD) == RRF_RT_QWORD)
1434 if (cbExpect && cbData != cbExpect)
1435 *ret = ERROR_DATATYPE_MISMATCH;
1438 else *ret = ERROR_UNSUPPORTED_TYPE;
1443 /******************************************************************************
1444 * RegGetValueW [ADVAPI32.@]
1446 * Retrieves the type and data for a value name associated with a key,
1447 * optionally expanding its content and restricting its type.
1450 * hKey [I] Handle to an open key.
1451 * pszSubKey [I] Name of the subkey of hKey.
1452 * pszValue [I] Name of value under hKey/szSubKey to query.
1453 * dwFlags [I] Flags restricting the value type to retrieve.
1454 * pdwType [O] Destination for the values type, may be NULL.
1455 * pvData [O] Destination for the values content, may be NULL.
1456 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1457 * retrieve the whole content, including the trailing '\0'
1461 * Success: ERROR_SUCCESS
1462 * Failure: nonzero error code from Winerror.h
1465 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1466 * expanded and pdwType is set to REG_SZ instead.
1467 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1468 * without RRF_NOEXPAND is thus not allowed.
1470 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1471 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1474 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1478 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1479 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1480 pvData, pcbData, cbData);
1482 if (pvData && !pcbData)
1483 return ERROR_INVALID_PARAMETER;
1484 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
1485 return ERROR_INVALID_PARAMETER;
1487 if (pszSubKey && pszSubKey[0])
1489 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1490 if (ret != ERROR_SUCCESS) return ret;
1493 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1495 /* If we are going to expand we need to read in the whole the value even
1496 * if the passed buffer was too small as the expanded string might be
1497 * smaller than the unexpanded one and could fit into cbData bytes. */
1498 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1499 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1502 HeapFree(GetProcessHeap(), 0, pvBuf);
1504 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1507 ret = ERROR_NOT_ENOUGH_MEMORY;
1511 if (ret == ERROR_MORE_DATA || !pvData)
1512 ret = RegQueryValueExW(hKey, pszValue, NULL,
1513 &dwType, pvBuf, &cbData);
1516 /* Even if cbData was large enough we have to copy the
1517 * string since ExpandEnvironmentStrings can't handle
1518 * overlapping buffers. */
1519 CopyMemory(pvBuf, pvData, cbData);
1522 /* Both the type or the value itself could have been modified in
1523 * between so we have to keep retrying until the buffer is large
1524 * enough or we no longer have to expand the value. */
1525 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1527 if (ret == ERROR_SUCCESS)
1529 /* Recheck dwType in case it changed since the first call */
1530 if (dwType == REG_EXPAND_SZ)
1532 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1533 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1535 if(pvData && pcbData && cbData > *pcbData)
1536 ret = ERROR_MORE_DATA;
1539 CopyMemory(pvData, pvBuf, *pcbData);
1542 HeapFree(GetProcessHeap(), 0, pvBuf);
1545 if (pszSubKey && pszSubKey[0])
1548 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1550 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1551 ZeroMemory(pvData, *pcbData);
1553 if (pdwType) *pdwType = dwType;
1554 if (pcbData) *pcbData = cbData;
1560 /******************************************************************************
1561 * RegGetValueA [ADVAPI32.@]
1565 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1566 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1569 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1573 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1574 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1577 if (pvData && !pcbData)
1578 return ERROR_INVALID_PARAMETER;
1579 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
1580 return ERROR_INVALID_PARAMETER;
1582 if (pszSubKey && pszSubKey[0])
1584 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1585 if (ret != ERROR_SUCCESS) return ret;
1588 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1590 /* If we are going to expand we need to read in the whole the value even
1591 * if the passed buffer was too small as the expanded string might be
1592 * smaller than the unexpanded one and could fit into cbData bytes. */
1593 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1594 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1597 HeapFree(GetProcessHeap(), 0, pvBuf);
1599 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1602 ret = ERROR_NOT_ENOUGH_MEMORY;
1606 if (ret == ERROR_MORE_DATA || !pvData)
1607 ret = RegQueryValueExA(hKey, pszValue, NULL,
1608 &dwType, pvBuf, &cbData);
1611 /* Even if cbData was large enough we have to copy the
1612 * string since ExpandEnvironmentStrings can't handle
1613 * overlapping buffers. */
1614 CopyMemory(pvBuf, pvData, cbData);
1617 /* Both the type or the value itself could have been modified in
1618 * between so we have to keep retrying until the buffer is large
1619 * enough or we no longer have to expand the value. */
1620 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1622 if (ret == ERROR_SUCCESS)
1624 /* Recheck dwType in case it changed since the first call */
1625 if (dwType == REG_EXPAND_SZ)
1627 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1628 pcbData ? *pcbData : 0);
1630 if(pvData && pcbData && cbData > *pcbData)
1631 ret = ERROR_MORE_DATA;
1634 CopyMemory(pvData, pvBuf, *pcbData);
1637 HeapFree(GetProcessHeap(), 0, pvBuf);
1640 if (pszSubKey && pszSubKey[0])
1643 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1645 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1646 ZeroMemory(pvData, *pcbData);
1648 if (pdwType) *pdwType = dwType;
1649 if (pcbData) *pcbData = cbData;
1655 /******************************************************************************
1656 * RegEnumValueW [ADVAPI32.@]
1658 * Enumerates the values for the specified open registry key.
1661 * hkey [I] Handle to key to query
1662 * index [I] Index of value to query
1663 * value [O] Value string
1664 * val_count [I/O] Size of value buffer (in wchars)
1665 * reserved [I] Reserved
1666 * type [O] Type code
1667 * data [O] Value data
1668 * count [I/O] Size of data buffer (in bytes)
1671 * Success: ERROR_SUCCESS
1672 * Failure: nonzero error code from Winerror.h
1675 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1676 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1680 char buffer[256], *buf_ptr = buffer;
1681 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1682 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1684 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1685 hkey, index, value, val_count, reserved, type, data, count );
1687 /* NT only checks count, not val_count */
1688 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1689 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1691 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1692 if (data) total_size += *count;
1693 total_size = min( sizeof(buffer), total_size );
1695 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1696 buffer, total_size, &total_size );
1697 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1701 /* retry with a dynamically allocated buffer */
1702 while (status == STATUS_BUFFER_OVERFLOW)
1704 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1705 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1706 return ERROR_NOT_ENOUGH_MEMORY;
1707 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1708 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1709 buf_ptr, total_size, &total_size );
1712 if (status) goto done;
1716 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1718 status = STATUS_BUFFER_OVERFLOW;
1721 memcpy( value, info->Name, info->NameLength );
1722 *val_count = info->NameLength / sizeof(WCHAR);
1723 value[*val_count] = 0;
1728 if (total_size - info->DataOffset > *count)
1730 status = STATUS_BUFFER_OVERFLOW;
1733 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1734 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1736 /* if the type is REG_SZ and data is not 0-terminated
1737 * and there is enough space in the buffer NT appends a \0 */
1738 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1739 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1743 else status = STATUS_SUCCESS;
1746 if (type) *type = info->Type;
1747 if (count) *count = info->DataLength;
1750 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1751 return RtlNtStatusToDosError(status);
1755 /******************************************************************************
1756 * RegEnumValueA [ADVAPI32.@]
1758 * See RegEnumValueW.
1760 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1761 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1765 char buffer[256], *buf_ptr = buffer;
1766 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1767 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1769 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1770 hkey, index, value, val_count, reserved, type, data, count );
1772 /* NT only checks count, not val_count */
1773 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1774 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1776 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1777 if (data) total_size += *count;
1778 total_size = min( sizeof(buffer), total_size );
1780 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1781 buffer, total_size, &total_size );
1782 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1784 /* we need to fetch the contents for a string type even if not requested,
1785 * because we need to compute the length of the ASCII string. */
1786 if (value || data || is_string(info->Type))
1788 /* retry with a dynamically allocated buffer */
1789 while (status == STATUS_BUFFER_OVERFLOW)
1791 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1792 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1793 return ERROR_NOT_ENOUGH_MEMORY;
1794 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1795 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1796 buf_ptr, total_size, &total_size );
1799 if (status) goto done;
1801 if (is_string(info->Type))
1804 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1805 total_size - info->DataOffset );
1808 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1811 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1812 total_size - info->DataOffset );
1813 /* if the type is REG_SZ and data is not 0-terminated
1814 * and there is enough space in the buffer NT appends a \0 */
1815 if (len < *count && data[len-1]) data[len] = 0;
1818 info->DataLength = len;
1822 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1823 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1826 if (value && !status)
1830 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1831 if (len >= *val_count)
1833 status = STATUS_BUFFER_OVERFLOW;
1836 len = *val_count - 1;
1837 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1843 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1849 else status = STATUS_SUCCESS;
1851 if (type) *type = info->Type;
1852 if (count) *count = info->DataLength;
1855 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1856 return RtlNtStatusToDosError(status);
1861 /******************************************************************************
1862 * RegDeleteValueW [ADVAPI32.@]
1864 * See RegDeleteValueA.
1866 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1868 UNICODE_STRING nameW;
1870 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1872 RtlInitUnicodeString( &nameW, name );
1873 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1877 /******************************************************************************
1878 * RegDeleteValueA [ADVAPI32.@]
1880 * Delete a value from the registry.
1883 * hkey [I] Registry handle of the key holding the value
1884 * name [I] Name of the value under hkey to delete
1887 * Success: ERROR_SUCCESS
1888 * Failure: nonzero error code from Winerror.h
1890 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1895 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1897 RtlInitAnsiString( &nameA, name );
1898 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1900 status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1901 return RtlNtStatusToDosError( status );
1905 /******************************************************************************
1906 * RegLoadKeyW [ADVAPI32.@]
1908 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1909 * registration information from a specified file into that subkey.
1912 * hkey [I] Handle of open key
1913 * subkey [I] Address of name of subkey
1914 * filename [I] Address of filename for registry information
1917 * Success: ERROR_SUCCESS
1918 * Failure: nonzero error code from Winerror.h
1920 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1922 OBJECT_ATTRIBUTES destkey, file;
1923 UNICODE_STRING subkeyW, filenameW;
1926 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
1928 destkey.Length = sizeof(destkey);
1929 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
1930 destkey.ObjectName = &subkeyW; /* name of the key */
1931 destkey.Attributes = 0;
1932 destkey.SecurityDescriptor = NULL;
1933 destkey.SecurityQualityOfService = NULL;
1934 RtlInitUnicodeString(&subkeyW, subkey);
1936 file.Length = sizeof(file);
1937 file.RootDirectory = NULL;
1938 file.ObjectName = &filenameW; /* file containing the hive */
1939 file.Attributes = OBJ_CASE_INSENSITIVE;
1940 file.SecurityDescriptor = NULL;
1941 file.SecurityQualityOfService = NULL;
1942 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
1944 status = NtLoadKey(&destkey, &file);
1945 RtlFreeUnicodeString(&filenameW);
1946 return RtlNtStatusToDosError( status );
1950 /******************************************************************************
1951 * RegLoadKeyA [ADVAPI32.@]
1955 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1957 UNICODE_STRING subkeyW, filenameW;
1958 STRING subkeyA, filenameA;
1962 RtlInitAnsiString(&subkeyA, subkey);
1963 RtlInitAnsiString(&filenameA, filename);
1965 RtlInitUnicodeString(&subkeyW, NULL);
1966 RtlInitUnicodeString(&filenameW, NULL);
1967 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
1968 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
1970 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
1972 else ret = RtlNtStatusToDosError(status);
1973 RtlFreeUnicodeString(&subkeyW);
1974 RtlFreeUnicodeString(&filenameW);
1979 /******************************************************************************
1980 * RegSaveKeyW [ADVAPI32.@]
1982 * Save a key and all of its subkeys and values to a new file in the standard format.
1985 * hkey [I] Handle of key where save begins
1986 * lpFile [I] Address of filename to save to
1987 * sa [I] Address of security structure
1990 * Success: ERROR_SUCCESS
1991 * Failure: nonzero error code from Winerror.h
1993 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1995 static const WCHAR format[] =
1996 {'r','e','g','%','0','4','x','.','t','m','p',0};
1997 WCHAR buffer[MAX_PATH];
2003 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2005 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2006 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2008 err = GetLastError();
2009 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2013 snprintfW( nameW, 16, format, count++ );
2014 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2015 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2016 if (handle != INVALID_HANDLE_VALUE) break;
2017 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2019 /* Something gone haywire ? Please report if this happens abnormally */
2021 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);
2024 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2026 CloseHandle( handle );
2029 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2031 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2033 ret = GetLastError();
2036 if (ret) DeleteFileW( buffer );
2039 SetLastError( err ); /* restore last error code */
2044 /******************************************************************************
2045 * RegSaveKeyA [ADVAPI32.@]
2049 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2051 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2055 RtlInitAnsiString(&fileA, file);
2056 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2057 return RtlNtStatusToDosError( status );
2058 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2062 /******************************************************************************
2063 * RegRestoreKeyW [ADVAPI32.@]
2065 * Read the registry information from a file and copy it over a key.
2068 * hkey [I] Handle of key where restore begins
2069 * lpFile [I] Address of filename containing saved tree
2070 * dwFlags [I] Optional flags
2073 * Success: ERROR_SUCCESS
2074 * Failure: nonzero error code from Winerror.h
2076 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2078 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2080 /* It seems to do this check before the hkey check */
2081 if (!lpFile || !*lpFile)
2082 return ERROR_INVALID_PARAMETER;
2084 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2086 /* Check for file existence */
2088 return ERROR_SUCCESS;
2092 /******************************************************************************
2093 * RegRestoreKeyA [ADVAPI32.@]
2095 * See RegRestoreKeyW.
2097 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2099 UNICODE_STRING lpFileW;
2102 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2103 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2104 RtlFreeUnicodeString( &lpFileW );
2109 /******************************************************************************
2110 * RegUnLoadKeyW [ADVAPI32.@]
2112 * Unload a registry key and its subkeys from the registry.
2115 * hkey [I] Handle of open key
2116 * lpSubKey [I] Address of name of subkey to unload
2119 * Success: ERROR_SUCCESS
2120 * Failure: nonzero error code from Winerror.h
2122 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2126 OBJECT_ATTRIBUTES attr;
2127 UNICODE_STRING subkey;
2129 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2131 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2133 return ERROR_INVALID_PARAMETER;
2135 RtlInitUnicodeString(&subkey, lpSubKey);
2136 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2137 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2145 /******************************************************************************
2146 * RegUnLoadKeyA [ADVAPI32.@]
2148 * See RegUnLoadKeyW.
2150 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2152 UNICODE_STRING lpSubKeyW;
2155 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2156 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2157 RtlFreeUnicodeString( &lpSubKeyW );
2162 /******************************************************************************
2163 * RegReplaceKeyW [ADVAPI32.@]
2165 * Replace the file backing a registry key and all its subkeys with another file.
2168 * hkey [I] Handle of open key
2169 * lpSubKey [I] Address of name of subkey
2170 * lpNewFile [I] Address of filename for file with new data
2171 * lpOldFile [I] Address of filename for backup file
2174 * Success: ERROR_SUCCESS
2175 * Failure: nonzero error code from Winerror.h
2177 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2180 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2181 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2182 return ERROR_SUCCESS;
2186 /******************************************************************************
2187 * RegReplaceKeyA [ADVAPI32.@]
2189 * See RegReplaceKeyW.
2191 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2194 UNICODE_STRING lpSubKeyW;
2195 UNICODE_STRING lpNewFileW;
2196 UNICODE_STRING lpOldFileW;
2199 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2200 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2201 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2202 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2203 RtlFreeUnicodeString( &lpOldFileW );
2204 RtlFreeUnicodeString( &lpNewFileW );
2205 RtlFreeUnicodeString( &lpSubKeyW );
2210 /******************************************************************************
2211 * RegSetKeySecurity [ADVAPI32.@]
2213 * Set the security of an open registry key.
2216 * hkey [I] Open handle of key to set
2217 * SecurityInfo [I] Descriptor contents
2218 * pSecurityDesc [I] Address of descriptor for key
2221 * Success: ERROR_SUCCESS
2222 * Failure: nonzero error code from Winerror.h
2224 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2225 PSECURITY_DESCRIPTOR pSecurityDesc )
2227 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2229 /* It seems to perform this check before the hkey check */
2230 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2231 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2232 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2233 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2236 return ERROR_INVALID_PARAMETER;
2239 return ERROR_INVALID_PARAMETER;
2241 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2243 return ERROR_SUCCESS;
2247 /******************************************************************************
2248 * RegGetKeySecurity [ADVAPI32.@]
2250 * Get a copy of the security descriptor for a given registry key.
2253 * hkey [I] Open handle of key to set
2254 * SecurityInformation [I] Descriptor contents
2255 * pSecurityDescriptor [O] Address of descriptor for key
2256 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2259 * Success: ERROR_SUCCESS
2260 * Failure: Error code
2262 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2263 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2264 LPDWORD lpcbSecurityDescriptor )
2266 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2267 *lpcbSecurityDescriptor);
2269 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2271 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2272 SecurityInformation, pSecurityDescriptor,
2273 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2277 /******************************************************************************
2278 * RegFlushKey [ADVAPI32.@]
2280 * Immediately write a registry key to registry.
2283 * hkey [I] Handle of key to write
2286 * Success: ERROR_SUCCESS
2287 * Failure: Error code
2289 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2291 hkey = get_special_root_hkey( hkey );
2292 if (!hkey) return ERROR_INVALID_HANDLE;
2294 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2298 /******************************************************************************
2299 * RegConnectRegistryW [ADVAPI32.@]
2301 * Establish a connection to a predefined registry key on another computer.
2304 * lpMachineName [I] Address of name of remote computer
2305 * hHey [I] Predefined registry handle
2306 * phkResult [I] Address of buffer for remote registry handle
2309 * Success: ERROR_SUCCESS
2310 * Failure: nonzero error code from Winerror.h
2312 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2317 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2319 if (!lpMachineName || !*lpMachineName) {
2320 /* Use the local machine name */
2321 ret = RegOpenKeyW( hKey, NULL, phkResult );
2324 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2325 DWORD len = sizeof(compName) / sizeof(WCHAR);
2327 /* MSDN says lpMachineName must start with \\ : not so */
2328 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2330 if (GetComputerNameW(compName, &len))
2332 if (!strcmpiW(lpMachineName, compName))
2333 ret = RegOpenKeyW(hKey, NULL, phkResult);
2336 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2337 ret = ERROR_BAD_NETPATH;
2341 ret = GetLastError();
2347 /******************************************************************************
2348 * RegConnectRegistryA [ADVAPI32.@]
2350 * See RegConnectRegistryW.
2352 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2354 UNICODE_STRING machineW;
2357 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2358 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2359 RtlFreeUnicodeString( &machineW );
2364 /******************************************************************************
2365 * RegNotifyChangeKeyValue [ADVAPI32.@]
2367 * Notify the caller about changes to the attributes or contents of a registry key.
2370 * hkey [I] Handle of key to watch
2371 * fWatchSubTree [I] Flag for subkey notification
2372 * fdwNotifyFilter [I] Changes to be reported
2373 * hEvent [I] Handle of signaled event
2374 * fAsync [I] Flag for asynchronous reporting
2377 * Success: ERROR_SUCCESS
2378 * Failure: nonzero error code from Winerror.h
2380 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2381 DWORD fdwNotifyFilter, HANDLE hEvent,
2385 IO_STATUS_BLOCK iosb;
2387 hkey = get_special_root_hkey( hkey );
2388 if (!hkey) return ERROR_INVALID_HANDLE;
2390 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2393 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2394 fdwNotifyFilter, fAsync, NULL, 0,
2397 if (status && status != STATUS_TIMEOUT)
2398 return RtlNtStatusToDosError( status );
2400 return ERROR_SUCCESS;
2403 /******************************************************************************
2404 * RegOpenUserClassesRoot [ADVAPI32.@]
2406 * Open the HKEY_CLASSES_ROOT key for a user.
2409 * hToken [I] Handle of token representing the user
2410 * dwOptions [I] Reserved, must be 0
2411 * samDesired [I] Desired access rights
2412 * phkResult [O] Destination for the resulting key handle
2415 * Success: ERROR_SUCCESS
2416 * Failure: nonzero error code from Winerror.h
2419 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2420 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2421 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2423 LSTATUS WINAPI RegOpenUserClassesRoot(
2430 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2432 *phkResult = HKEY_CLASSES_ROOT;
2433 return ERROR_SUCCESS;
2436 /******************************************************************************
2437 * load_string [Internal]
2439 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2440 * avoid importing user32, which is higher level than advapi32. Helper for
2443 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2450 /* Negative values have to be inverted. */
2451 if (HIWORD(resId) == 0xffff)
2452 resId = (UINT)(-((INT)resId));
2454 /* Load the resource into memory and get a pointer to it. */
2455 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2456 if (!hResource) return 0;
2457 hMemory = LoadResource(hModule, hResource);
2458 if (!hMemory) return 0;
2459 pString = LockResource(hMemory);
2461 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2462 idxString = resId & 0xf;
2463 while (idxString--) pString += *pString + 1;
2465 /* If no buffer is given, return length of the string. */
2466 if (!pwszBuffer) return *pString;
2468 /* Else copy over the string, respecting the buffer size. */
2469 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2470 if (cMaxChars >= 0) {
2471 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2472 pwszBuffer[cMaxChars] = '\0';
2478 /******************************************************************************
2479 * RegLoadMUIStringW [ADVAPI32.@]
2481 * Load the localized version of a string resource from some PE, respective
2482 * id and path of which are given in the registry value in the format
2483 * @[path]\dllname,-resourceId
2486 * hKey [I] Key, of which to load the string value from.
2487 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2488 * pszBuffer [O] Buffer to store the localized string in.
2489 * cbBuffer [I] Size of the destination buffer in bytes.
2490 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2491 * dwFlags [I] None supported yet.
2492 * pszBaseDir [I] Not supported yet.
2495 * Success: ERROR_SUCCESS,
2496 * Failure: nonzero error code from winerror.h
2499 * This is an API of Windows Vista, which wasn't available at the time this code
2500 * was written. We have to check for the correct behaviour once it's available.
2502 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2503 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2505 DWORD dwValueType, cbData;
2506 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2509 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2510 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2511 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2513 /* Parameter sanity checks. */
2514 if (!hKey || !pwszBuffer)
2515 return ERROR_INVALID_PARAMETER;
2517 if (pwszBaseDir && *pwszBaseDir) {
2518 FIXME("BaseDir parameter not yet supported!\n");
2519 return ERROR_INVALID_PARAMETER;
2522 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2523 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2524 if (result != ERROR_SUCCESS) goto cleanup;
2525 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2526 result = ERROR_FILE_NOT_FOUND;
2529 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2530 if (!pwszTempBuffer) {
2531 result = ERROR_NOT_ENOUGH_MEMORY;
2534 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2535 if (result != ERROR_SUCCESS) goto cleanup;
2537 /* Expand environment variables, if appropriate, or copy the original string over. */
2538 if (dwValueType == REG_EXPAND_SZ) {
2539 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2540 if (!cbData) goto cleanup;
2541 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2542 if (!pwszExpandedBuffer) {
2543 result = ERROR_NOT_ENOUGH_MEMORY;
2546 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2548 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2549 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2552 /* If the value references a resource based string, parse the value and load the string.
2553 * Else just copy over the original value. */
2554 result = ERROR_SUCCESS;
2555 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2556 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2558 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2562 /* Format of the expanded value is 'path_to_dll,-resId' */
2563 if (!pComma || pComma[1] != '-') {
2564 result = ERROR_BADKEY;
2568 uiStringId = atoiW(pComma+2);
2571 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2572 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2573 result = ERROR_BADKEY;
2574 FreeLibrary(hModule);
2578 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2579 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2583 /******************************************************************************
2584 * RegLoadMUIStringA [ADVAPI32.@]
2586 * See RegLoadMUIStringW
2588 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2589 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2591 UNICODE_STRING valueW, baseDirW;
2593 DWORD cbData = cbBuffer * sizeof(WCHAR);
2596 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2597 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2598 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2599 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2601 result = ERROR_NOT_ENOUGH_MEMORY;
2605 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2608 if (result == ERROR_SUCCESS) {
2609 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2615 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2616 RtlFreeUnicodeString(&baseDirW);
2617 RtlFreeUnicodeString(&valueW);
2622 /******************************************************************************
2623 * RegDisablePredefinedCache [ADVAPI32.@]
2625 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2631 * Success: ERROR_SUCCESS
2632 * Failure: nonzero error code from Winerror.h
2635 * This is useful for services that use impersonation.
2637 LSTATUS WINAPI RegDisablePredefinedCache(void)
2639 HKEY hkey_current_user;
2640 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2642 /* prevent caching of future requests */
2643 hkcu_cache_disabled = TRUE;
2645 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2647 if (hkey_current_user)
2648 NtClose( hkey_current_user );
2650 return ERROR_SUCCESS;
2653 /******************************************************************************
2654 * RegDeleteTreeW [ADVAPI32.@]
2657 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2660 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2661 DWORD dwMaxLen, dwSize;
2662 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2663 HKEY hSubKey = hKey;
2665 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2669 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2670 if (ret) return ret;
2673 /* Get highest length for keys, values */
2674 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2675 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2676 if (ret) goto cleanup;
2680 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2681 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2683 /* Name too big: alloc a buffer for it */
2684 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2686 ret = ERROR_NOT_ENOUGH_MEMORY;
2692 /* Recursively delete all the subkeys */
2696 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2697 NULL, NULL, NULL)) break;
2699 ret = RegDeleteTreeW(hSubKey, lpszName);
2700 if (ret) goto cleanup;
2704 ret = RegDeleteKeyW(hKey, lpszSubKey);
2709 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2710 NULL, NULL, NULL, NULL)) break;
2712 ret = RegDeleteValueW(hKey, lpszName);
2713 if (ret) goto cleanup;
2717 /* Free buffer if allocated */
2718 if (lpszName != szNameBuf)
2719 HeapFree( GetProcessHeap(), 0, lpszName);
2721 RegCloseKey(hSubKey);
2725 /******************************************************************************
2726 * RegDeleteTreeA [ADVAPI32.@]
2729 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2732 UNICODE_STRING lpszSubKeyW;
2734 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2735 else lpszSubKeyW.Buffer = NULL;
2736 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2737 RtlFreeUnicodeString( &lpszSubKeyW );