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 * RegCreateKeyExW [ADVAPI32.@]
155 * See RegCreateKeyExA.
157 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
158 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
159 PHKEY retkey, LPDWORD dispos )
161 OBJECT_ATTRIBUTES attr;
162 UNICODE_STRING nameW, classW;
164 if (reserved) return ERROR_INVALID_PARAMETER;
165 if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
166 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
168 attr.Length = sizeof(attr);
169 attr.RootDirectory = hkey;
170 attr.ObjectName = &nameW;
172 attr.SecurityDescriptor = NULL;
173 attr.SecurityQualityOfService = NULL;
174 RtlInitUnicodeString( &nameW, name );
175 RtlInitUnicodeString( &classW, class );
177 return RtlNtStatusToDosError( NtCreateKey( (PHANDLE)retkey, access, &attr, 0,
178 &classW, options, dispos ) );
182 /******************************************************************************
183 * RegCreateKeyExA [ADVAPI32.@]
185 * Open a registry key, creating it if it doesn't exist.
188 * hkey [I] Handle of the parent registry key
189 * name [I] Name of the new key to open or create
190 * reserved [I] Reserved, pass 0
191 * class [I] The object type of the new key
192 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
193 * access [I] Access level desired
194 * sa [I] Security attributes for the key
195 * retkey [O] Destination for the resulting handle
196 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
199 * Success: ERROR_SUCCESS.
200 * Failure: A standard Win32 error code. retkey remains untouched.
203 * MAXIMUM_ALLOWED in access mask not supported by server
205 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
206 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
207 PHKEY retkey, LPDWORD dispos )
209 OBJECT_ATTRIBUTES attr;
210 UNICODE_STRING classW;
211 ANSI_STRING nameA, classA;
214 if (reserved) return ERROR_INVALID_PARAMETER;
215 if (!is_version_nt())
217 access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
218 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
220 else if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
221 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
223 attr.Length = sizeof(attr);
224 attr.RootDirectory = hkey;
225 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
227 attr.SecurityDescriptor = NULL;
228 attr.SecurityQualityOfService = NULL;
229 RtlInitAnsiString( &nameA, name );
230 RtlInitAnsiString( &classA, class );
232 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
235 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
237 status = NtCreateKey( (PHANDLE)retkey, access, &attr, 0, &classW, options, dispos );
238 RtlFreeUnicodeString( &classW );
241 return RtlNtStatusToDosError( status );
245 /******************************************************************************
246 * RegCreateKeyW [ADVAPI32.@]
248 * Creates the specified reg key.
251 * hKey [I] Handle to an open key.
252 * lpSubKey [I] Name of a key that will be opened or created.
253 * phkResult [O] Receives a handle to the opened or created key.
256 * Success: ERROR_SUCCESS
257 * Failure: nonzero error code defined in Winerror.h
259 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
261 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
262 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
263 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
264 KEY_ALL_ACCESS, NULL, phkResult, NULL );
268 /******************************************************************************
269 * RegCreateKeyA [ADVAPI32.@]
273 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
275 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
276 KEY_ALL_ACCESS, NULL, phkResult, NULL );
281 /******************************************************************************
282 * RegOpenKeyExW [ADVAPI32.@]
286 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
288 OBJECT_ATTRIBUTES attr;
289 UNICODE_STRING nameW;
291 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
293 attr.Length = sizeof(attr);
294 attr.RootDirectory = hkey;
295 attr.ObjectName = &nameW;
297 attr.SecurityDescriptor = NULL;
298 attr.SecurityQualityOfService = NULL;
299 RtlInitUnicodeString( &nameW, name );
300 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE)retkey, access, &attr ) );
304 /******************************************************************************
305 * RegOpenKeyExA [ADVAPI32.@]
307 * Open a registry key.
310 * hkey [I] Handle of open key
311 * name [I] Name of subkey to open
312 * reserved [I] Reserved - must be zero
313 * access [I] Security access mask
314 * retkey [O] Handle to open key
317 * Success: ERROR_SUCCESS
318 * Failure: A standard Win32 error code. retkey is set to 0.
321 * Unlike RegCreateKeyExA(), this function will not create the key if it
324 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
326 OBJECT_ATTRIBUTES attr;
330 if (!is_version_nt()) access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
332 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
334 attr.Length = sizeof(attr);
335 attr.RootDirectory = hkey;
336 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
338 attr.SecurityDescriptor = NULL;
339 attr.SecurityQualityOfService = NULL;
341 RtlInitAnsiString( &nameA, name );
342 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
345 status = NtOpenKey( (PHANDLE)retkey, access, &attr );
347 return RtlNtStatusToDosError( status );
351 /******************************************************************************
352 * RegOpenKeyW [ADVAPI32.@]
356 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
361 return ERROR_SUCCESS;
363 return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
367 /******************************************************************************
368 * RegOpenKeyA [ADVAPI32.@]
370 * Open a registry key.
373 * hkey [I] Handle of parent key to open the new key under
374 * name [I] Name of the key under hkey to open
375 * retkey [O] Destination for the resulting Handle
378 * Success: ERROR_SUCCESS
379 * Failure: A standard Win32 error code. retkey is set to 0.
381 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
386 return ERROR_SUCCESS;
388 return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
392 /******************************************************************************
393 * RegOpenCurrentUser [ADVAPI32.@]
395 * Get a handle to the HKEY_CURRENT_USER key for the user
396 * the current thread is impersonating.
399 * access [I] Desired access rights to the key
400 * retkey [O] Handle to the opened key
403 * Success: ERROR_SUCCESS
404 * Failure: nonzero error code from Winerror.h
407 * This function is supposed to retrieve a handle to the
408 * HKEY_CURRENT_USER for the user the current thread is impersonating.
409 * Since Wine does not currently allow threads to impersonate other users,
410 * this stub should work fine.
412 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
414 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
419 /******************************************************************************
420 * RegEnumKeyExW [ADVAPI32.@]
422 * Enumerate subkeys of the specified open registry key.
425 * hkey [I] Handle to key to enumerate
426 * index [I] Index of subkey to enumerate
427 * name [O] Buffer for subkey name
428 * name_len [O] Size of subkey buffer
429 * reserved [I] Reserved
430 * class [O] Buffer for class string
431 * class_len [O] Size of class buffer
432 * ft [O] Time key last written to
435 * Success: ERROR_SUCCESS
436 * Failure: System error code. If there are no more subkeys available, the
437 * function returns ERROR_NO_MORE_ITEMS.
439 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
440 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
443 char buffer[256], *buf_ptr = buffer;
444 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
447 TRACE( "(%p,%d,%p,%p(%d),%p,%p,%p,%p)\n", hkey, index, name, name_len,
448 name_len ? *name_len : -1, reserved, class, class_len, ft );
450 if (reserved) return ERROR_INVALID_PARAMETER;
451 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
453 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
454 buffer, sizeof(buffer), &total_size );
456 while (status == STATUS_BUFFER_OVERFLOW)
458 /* retry with a dynamically allocated buffer */
459 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
460 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
461 return ERROR_NOT_ENOUGH_MEMORY;
462 info = (KEY_NODE_INFORMATION *)buf_ptr;
463 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
464 buf_ptr, total_size, &total_size );
469 DWORD len = info->NameLength / sizeof(WCHAR);
470 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
472 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
474 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
475 status = STATUS_BUFFER_OVERFLOW;
479 memcpy( name, info->Name, info->NameLength );
483 *class_len = cls_len;
486 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
493 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
494 return RtlNtStatusToDosError( status );
498 /******************************************************************************
499 * RegEnumKeyExA [ADVAPI32.@]
503 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
504 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
507 char buffer[256], *buf_ptr = buffer;
508 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
511 TRACE( "(%p,%d,%p,%p(%d),%p,%p,%p,%p)\n", hkey, index, name, name_len,
512 name_len ? *name_len : -1, reserved, class, class_len, ft );
514 if (reserved) return ERROR_INVALID_PARAMETER;
515 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
517 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
518 buffer, sizeof(buffer), &total_size );
520 while (status == STATUS_BUFFER_OVERFLOW)
522 /* retry with a dynamically allocated buffer */
523 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
524 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
525 return ERROR_NOT_ENOUGH_MEMORY;
526 info = (KEY_NODE_INFORMATION *)buf_ptr;
527 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
528 buf_ptr, total_size, &total_size );
535 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
536 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
538 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
540 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
541 status = STATUS_BUFFER_OVERFLOW;
545 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
549 *class_len = cls_len;
552 RtlUnicodeToMultiByteN( class, cls_len, NULL,
553 (WCHAR *)(buf_ptr + info->ClassOffset),
561 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
562 return RtlNtStatusToDosError( status );
566 /******************************************************************************
567 * RegEnumKeyW [ADVAPI32.@]
569 * Enumerates subkeys of the specified open reg key.
572 * hKey [I] Handle to an open key.
573 * dwIndex [I] Index of the subkey of hKey to retrieve.
574 * lpName [O] Name of the subkey.
575 * cchName [I] Size of lpName in TCHARS.
578 * Success: ERROR_SUCCESS
579 * Failure: system error code. If there are no more subkeys available, the
580 * function returns ERROR_NO_MORE_ITEMS.
582 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
584 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
588 /******************************************************************************
589 * RegEnumKeyA [ADVAPI32.@]
593 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
595 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
599 /******************************************************************************
600 * RegQueryInfoKeyW [ADVAPI32.@]
602 * Retrieves information about the specified registry key.
605 * hkey [I] Handle to key to query
606 * class [O] Buffer for class string
607 * class_len [O] Size of class string buffer
608 * reserved [I] Reserved
609 * subkeys [O] Buffer for number of subkeys
610 * max_subkey [O] Buffer for longest subkey name length
611 * max_class [O] Buffer for longest class string length
612 * values [O] Buffer for number of value entries
613 * max_value [O] Buffer for longest value name length
614 * max_data [O] Buffer for longest value data length
615 * security [O] Buffer for security descriptor length
616 * modif [O] Modification time
619 * Success: ERROR_SUCCESS
620 * Failure: system error code.
623 * - win95 allows class to be valid and class_len to be NULL
624 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
625 * - both allow class to be NULL and class_len to be NULL
626 * (it's hard to test validity, so test !NULL instead)
628 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
629 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
630 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
631 LPDWORD security, FILETIME *modif )
634 char buffer[256], *buf_ptr = buffer;
635 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
638 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
639 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
641 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
642 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
644 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
645 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
649 /* retry with a dynamically allocated buffer */
650 while (status == STATUS_BUFFER_OVERFLOW)
652 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
653 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
654 return ERROR_NOT_ENOUGH_MEMORY;
655 info = (KEY_FULL_INFORMATION *)buf_ptr;
656 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
659 if (status) goto done;
661 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
663 status = STATUS_BUFFER_OVERFLOW;
667 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
668 class[info->ClassLength/sizeof(WCHAR)] = 0;
671 else status = STATUS_SUCCESS;
673 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
674 if (subkeys) *subkeys = info->SubKeys;
675 if (max_subkey) *max_subkey = info->MaxNameLen;
676 if (max_class) *max_class = info->MaxClassLen;
677 if (values) *values = info->Values;
678 if (max_value) *max_value = info->MaxValueNameLen;
679 if (max_data) *max_data = info->MaxValueDataLen;
680 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
683 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
684 return RtlNtStatusToDosError( status );
688 /******************************************************************************
689 * RegQueryMultipleValuesA [ADVAPI32.@]
691 * Retrieves the type and data for a list of value names associated with a key.
694 * hKey [I] Handle to an open key.
695 * val_list [O] Array of VALENT structures that describes the entries.
696 * num_vals [I] Number of elements in val_list.
697 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
698 * ldwTotsize [I/O] Size of lpValueBuf.
701 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
702 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
705 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
706 LPSTR lpValueBuf, LPDWORD ldwTotsize )
709 DWORD maxBytes = *ldwTotsize;
711 LPSTR bufptr = lpValueBuf;
714 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
716 for(i=0; i < num_vals; ++i)
719 val_list[i].ve_valuelen=0;
720 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
721 if(status != ERROR_SUCCESS)
726 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
728 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
729 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
730 if(status != ERROR_SUCCESS)
735 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
737 bufptr += val_list[i].ve_valuelen;
740 *ldwTotsize += val_list[i].ve_valuelen;
742 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
746 /******************************************************************************
747 * RegQueryMultipleValuesW [ADVAPI32.@]
749 * See RegQueryMultipleValuesA.
751 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
752 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
755 DWORD maxBytes = *ldwTotsize;
757 LPSTR bufptr = (LPSTR)lpValueBuf;
760 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
762 for(i=0; i < num_vals; ++i)
764 val_list[i].ve_valuelen=0;
765 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
766 if(status != ERROR_SUCCESS)
771 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
773 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
774 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
775 if(status != ERROR_SUCCESS)
780 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
782 bufptr += val_list[i].ve_valuelen;
785 *ldwTotsize += val_list[i].ve_valuelen;
787 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
790 /******************************************************************************
791 * RegQueryInfoKeyA [ADVAPI32.@]
793 * Retrieves information about a registry key.
796 * hKey [I] Handle to an open key.
797 * lpClass [O] Class string of the key.
798 * lpcClass [I/O] size of lpClass.
799 * lpReserved [I] Reserved; must be NULL.
800 * lpcSubKeys [O] Number of subkeys contained by the key.
801 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
802 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
804 * lpcValues [O] Number of values associated with the key.
805 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
806 * lpcMaxValueLen [O] Longest data component among the key's values
807 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
808 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
811 * Success: ERROR_SUCCESS
812 * Failure: nonzero error code from Winerror.h
814 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
815 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
816 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
817 LPDWORD security, FILETIME *modif )
820 char buffer[256], *buf_ptr = buffer;
821 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
822 DWORD total_size, len;
824 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
825 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
827 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
828 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
830 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
831 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
833 if (class || class_len)
835 /* retry with a dynamically allocated buffer */
836 while (status == STATUS_BUFFER_OVERFLOW)
838 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
839 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
840 return ERROR_NOT_ENOUGH_MEMORY;
841 info = (KEY_FULL_INFORMATION *)buf_ptr;
842 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
845 if (status) goto done;
847 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
850 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
853 if (class && !status)
855 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
860 else status = STATUS_SUCCESS;
862 if (subkeys) *subkeys = info->SubKeys;
863 if (max_subkey) *max_subkey = info->MaxNameLen;
864 if (max_class) *max_class = info->MaxClassLen;
865 if (values) *values = info->Values;
866 if (max_value) *max_value = info->MaxValueNameLen;
867 if (max_data) *max_data = info->MaxValueDataLen;
868 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
871 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
872 return RtlNtStatusToDosError( status );
876 /******************************************************************************
877 * RegCloseKey [ADVAPI32.@]
879 * Close an open registry key.
882 * hkey [I] Handle of key to close
885 * Success: ERROR_SUCCESS
886 * Failure: Error code
888 LSTATUS WINAPI RegCloseKey( HKEY hkey )
890 if (!hkey) return ERROR_INVALID_HANDLE;
891 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
892 return RtlNtStatusToDosError( NtClose( hkey ) );
896 /******************************************************************************
897 * RegDeleteKeyW [ADVAPI32.@]
901 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
906 if (!name) return ERROR_INVALID_PARAMETER;
908 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
910 if (!(ret = RegOpenKeyExW( hkey, name, 0, DELETE, &tmp )))
912 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
915 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
920 /******************************************************************************
921 * RegDeleteKeyA [ADVAPI32.@]
923 * Delete a registry key.
926 * hkey [I] Handle to parent key containing the key to delete
927 * name [I] Name of the key user hkey to delete
931 * MSDN is wrong when it says that hkey must be opened with the DELETE access
932 * right. In reality, it opens a new handle with DELETE access.
935 * Success: ERROR_SUCCESS
936 * Failure: Error code
938 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
943 if (!name) return ERROR_INVALID_PARAMETER;
945 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
947 if (!(ret = RegOpenKeyExA( hkey, name, 0, DELETE, &tmp )))
949 if (!is_version_nt()) /* win95 does recursive key deletes */
953 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
955 if(RegDeleteKeyA(tmp, name)) /* recurse */
959 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
962 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
968 /******************************************************************************
969 * RegSetValueExW [ADVAPI32.@]
971 * Set the data and contents of a registry value.
974 * hkey [I] Handle of key to set value for
975 * name [I] Name of value to set
976 * reserved [I] Reserved, must be zero
977 * type [I] Type of the value being set
978 * data [I] The new contents of the value to set
979 * count [I] Size of data
982 * Success: ERROR_SUCCESS
983 * Failure: Error code
985 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
986 DWORD type, CONST BYTE *data, DWORD count )
988 UNICODE_STRING nameW;
990 /* no need for version check, not implemented on win9x anyway */
991 if (count && is_string(type))
993 LPCWSTR str = (LPCWSTR)data;
994 /* if user forgot to count terminating null, add it (yes NT does this) */
995 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
996 count += sizeof(WCHAR);
998 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1000 RtlInitUnicodeString( &nameW, name );
1001 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1005 /******************************************************************************
1006 * RegSetValueExA [ADVAPI32.@]
1008 * See RegSetValueExW.
1011 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1012 * NT does definitely care (aj)
1014 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1015 CONST BYTE *data, DWORD count )
1018 WCHAR *dataW = NULL;
1021 if (!is_version_nt()) /* win95 */
1025 if (!data) return ERROR_INVALID_PARAMETER;
1026 count = strlen((const char *)data) + 1;
1029 else if (count && is_string(type))
1031 /* if user forgot to count terminating null, add it (yes NT does this) */
1032 if (data[count-1] && !data[count]) count++;
1035 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1037 if (is_string( type )) /* need to convert to Unicode */
1040 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1041 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1042 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1044 data = (BYTE *)dataW;
1047 RtlInitAnsiString( &nameA, name );
1048 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1051 status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
1053 HeapFree( GetProcessHeap(), 0, dataW );
1054 return RtlNtStatusToDosError( status );
1058 /******************************************************************************
1059 * RegSetValueW [ADVAPI32.@]
1061 * Sets the data for the default or unnamed value of a reg key.
1064 * hKey [I] Handle to an open key.
1065 * lpSubKey [I] Name of a subkey of hKey.
1066 * dwType [I] Type of information to store.
1067 * lpData [I] String that contains the data to set for the default value.
1068 * cbData [I] Size of lpData.
1071 * Success: ERROR_SUCCESS
1072 * Failure: nonzero error code from Winerror.h
1074 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1079 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1081 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1083 if (name && name[0]) /* need to create the subkey */
1085 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1088 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1089 (strlenW( data ) + 1) * sizeof(WCHAR) );
1090 if (subkey != hkey) RegCloseKey( subkey );
1095 /******************************************************************************
1096 * RegSetValueA [ADVAPI32.@]
1100 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1105 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(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 = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1113 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1114 if (subkey != hkey) RegCloseKey( subkey );
1120 /******************************************************************************
1121 * RegQueryValueExW [ADVAPI32.@]
1123 * See RegQueryValueExA.
1125 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1126 LPBYTE data, LPDWORD count )
1129 UNICODE_STRING name_str;
1131 char buffer[256], *buf_ptr = buffer;
1132 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1133 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1135 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1136 hkey, debugstr_w(name), reserved, type, data, count,
1137 (count && data) ? *count : 0 );
1139 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1140 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1142 RtlInitUnicodeString( &name_str, name );
1144 if (data) total_size = min( sizeof(buffer), *count + info_size );
1147 total_size = info_size;
1148 if (count) *count = 0;
1151 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1152 buffer, total_size, &total_size );
1153 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1157 /* retry with a dynamically allocated buffer */
1158 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1160 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1161 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1162 return ERROR_NOT_ENOUGH_MEMORY;
1163 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1164 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1165 buf_ptr, total_size, &total_size );
1170 memcpy( data, buf_ptr + info_size, total_size - info_size );
1171 /* if the type is REG_SZ and data is not 0-terminated
1172 * and there is enough space in the buffer NT appends a \0 */
1173 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1175 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1176 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1179 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1181 else status = STATUS_SUCCESS;
1183 if (type) *type = info->Type;
1184 if (count) *count = total_size - info_size;
1187 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1188 return RtlNtStatusToDosError(status);
1192 /******************************************************************************
1193 * RegQueryValueExA [ADVAPI32.@]
1195 * Get the type and contents of a specified value under with a key.
1198 * hkey [I] Handle of the key to query
1199 * name [I] Name of value under hkey to query
1200 * reserved [I] Reserved - must be NULL
1201 * type [O] Destination for the value type, or NULL if not required
1202 * data [O] Destination for the values contents, or NULL if not required
1203 * count [I/O] Size of data, updated with the number of bytes returned
1206 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1207 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1208 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1209 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1212 * MSDN states that if data is too small it is partially filled. In reality
1213 * it remains untouched.
1215 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1216 LPBYTE data, LPDWORD count )
1220 DWORD total_size, datalen = 0;
1221 char buffer[256], *buf_ptr = buffer;
1222 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1223 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1225 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1226 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1228 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1229 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1231 if (count) datalen = *count;
1232 if (!data && count) *count = 0;
1234 /* this matches Win9x behaviour - NT sets *type to a random value */
1235 if (type) *type = REG_NONE;
1237 RtlInitAnsiString( &nameA, name );
1238 if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1240 return RtlNtStatusToDosError(status);
1242 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1243 KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
1244 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1246 /* we need to fetch the contents for a string type even if not requested,
1247 * because we need to compute the length of the ASCII string. */
1248 if (data || is_string(info->Type))
1250 /* retry with a dynamically allocated buffer */
1251 while (status == STATUS_BUFFER_OVERFLOW)
1253 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1254 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1256 status = STATUS_NO_MEMORY;
1259 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1260 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1261 KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1264 if (status) goto done;
1266 if (is_string(info->Type))
1270 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1271 total_size - info_size );
1274 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1277 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1278 total_size - info_size );
1279 /* if the type is REG_SZ and data is not 0-terminated
1280 * and there is enough space in the buffer NT appends a \0 */
1281 if (len < datalen && data[len-1]) data[len] = 0;
1284 total_size = len + info_size;
1288 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1289 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1292 else status = STATUS_SUCCESS;
1294 if (type) *type = info->Type;
1295 if (count) *count = total_size - info_size;
1298 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1299 return RtlNtStatusToDosError(status);
1303 /******************************************************************************
1304 * RegQueryValueW [ADVAPI32.@]
1306 * Retrieves the data associated with the default or unnamed value of a key.
1309 * hkey [I] Handle to an open key.
1310 * name [I] Name of the subkey of hKey.
1311 * data [O] Receives the string associated with the default value
1313 * count [I/O] Size of lpValue in bytes.
1316 * Success: ERROR_SUCCESS
1317 * Failure: nonzero error code from Winerror.h
1319 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1324 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1326 if (name && name[0])
1328 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1330 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1331 if (subkey != hkey) RegCloseKey( subkey );
1332 if (ret == ERROR_FILE_NOT_FOUND)
1334 /* return empty string if default value not found */
1335 if (data) *data = 0;
1336 if (count) *count = sizeof(WCHAR);
1337 ret = ERROR_SUCCESS;
1343 /******************************************************************************
1344 * RegQueryValueA [ADVAPI32.@]
1346 * See RegQueryValueW.
1348 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1353 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1355 if (name && name[0])
1357 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1359 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1360 if (subkey != hkey) RegCloseKey( subkey );
1361 if (ret == ERROR_FILE_NOT_FOUND)
1363 /* return empty string if default value not found */
1364 if (data) *data = 0;
1365 if (count) *count = 1;
1366 ret = ERROR_SUCCESS;
1372 /******************************************************************************
1373 * ADVAPI_ApplyRestrictions [internal]
1375 * Helper function for RegGetValueA/W.
1377 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1378 DWORD cbData, PLONG ret )
1380 /* Check if the type is restricted by the passed flags */
1381 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1387 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1388 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1389 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1390 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1391 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1392 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1393 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1396 if (dwFlags & dwMask)
1398 /* Type is not restricted, check for size mismatch */
1399 if (dwType == REG_BINARY)
1403 if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD)
1405 else if ((dwFlags & RRF_RT_QWORD) == RRF_RT_QWORD)
1408 if (cbExpect && cbData != cbExpect)
1409 *ret = ERROR_DATATYPE_MISMATCH;
1412 else *ret = ERROR_UNSUPPORTED_TYPE;
1417 /******************************************************************************
1418 * RegGetValueW [ADVAPI32.@]
1420 * Retrieves the type and data for a value name associated with a key,
1421 * optionally expanding its content and restricting its type.
1424 * hKey [I] Handle to an open key.
1425 * pszSubKey [I] Name of the subkey of hKey.
1426 * pszValue [I] Name of value under hKey/szSubKey to query.
1427 * dwFlags [I] Flags restricting the value type to retrieve.
1428 * pdwType [O] Destination for the values type, may be NULL.
1429 * pvData [O] Destination for the values content, may be NULL.
1430 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1431 * retrieve the whole content, including the trailing '\0'
1435 * Success: ERROR_SUCCESS
1436 * Failure: nonzero error code from Winerror.h
1439 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1440 * expanded and pdwType is set to REG_SZ instead.
1441 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1442 * without RRF_NOEXPAND is thus not allowed.
1444 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1445 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1448 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1452 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1453 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1454 pvData, pcbData, cbData);
1456 if (pvData && !pcbData)
1457 return ERROR_INVALID_PARAMETER;
1458 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
1459 return ERROR_INVALID_PARAMETER;
1461 if (pszSubKey && pszSubKey[0])
1463 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1464 if (ret != ERROR_SUCCESS) return ret;
1467 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1469 /* If we are going to expand we need to read in the whole the value even
1470 * if the passed buffer was too small as the expanded string might be
1471 * smaller than the unexpanded one and could fit into cbData bytes. */
1472 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1473 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1476 HeapFree(GetProcessHeap(), 0, pvBuf);
1478 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1481 ret = ERROR_NOT_ENOUGH_MEMORY;
1485 if (ret == ERROR_MORE_DATA || !pvData)
1486 ret = RegQueryValueExW(hKey, pszValue, NULL,
1487 &dwType, pvBuf, &cbData);
1490 /* Even if cbData was large enough we have to copy the
1491 * string since ExpandEnvironmentStrings can't handle
1492 * overlapping buffers. */
1493 CopyMemory(pvBuf, pvData, cbData);
1496 /* Both the type or the value itself could have been modified in
1497 * between so we have to keep retrying until the buffer is large
1498 * enough or we no longer have to expand the value. */
1499 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1501 if (ret == ERROR_SUCCESS)
1503 /* Recheck dwType in case it changed since the first call */
1504 if (dwType == REG_EXPAND_SZ)
1506 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1507 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1509 if(pvData && pcbData && cbData > *pcbData)
1510 ret = ERROR_MORE_DATA;
1513 CopyMemory(pvData, pvBuf, *pcbData);
1516 HeapFree(GetProcessHeap(), 0, pvBuf);
1519 if (pszSubKey && pszSubKey[0])
1522 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1524 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1525 ZeroMemory(pvData, *pcbData);
1527 if (pdwType) *pdwType = dwType;
1528 if (pcbData) *pcbData = cbData;
1534 /******************************************************************************
1535 * RegGetValueA [ADVAPI32.@]
1539 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1540 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1543 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1547 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1548 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1551 if (pvData && !pcbData)
1552 return ERROR_INVALID_PARAMETER;
1553 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
1554 return ERROR_INVALID_PARAMETER;
1556 if (pszSubKey && pszSubKey[0])
1558 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1559 if (ret != ERROR_SUCCESS) return ret;
1562 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1564 /* If we are going to expand we need to read in the whole the value even
1565 * if the passed buffer was too small as the expanded string might be
1566 * smaller than the unexpanded one and could fit into cbData bytes. */
1567 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1568 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1571 HeapFree(GetProcessHeap(), 0, pvBuf);
1573 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1576 ret = ERROR_NOT_ENOUGH_MEMORY;
1580 if (ret == ERROR_MORE_DATA || !pvData)
1581 ret = RegQueryValueExA(hKey, pszValue, NULL,
1582 &dwType, pvBuf, &cbData);
1585 /* Even if cbData was large enough we have to copy the
1586 * string since ExpandEnvironmentStrings can't handle
1587 * overlapping buffers. */
1588 CopyMemory(pvBuf, pvData, cbData);
1591 /* Both the type or the value itself could have been modified in
1592 * between so we have to keep retrying until the buffer is large
1593 * enough or we no longer have to expand the value. */
1594 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1596 if (ret == ERROR_SUCCESS)
1598 /* Recheck dwType in case it changed since the first call */
1599 if (dwType == REG_EXPAND_SZ)
1601 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1602 pcbData ? *pcbData : 0);
1604 if(pvData && pcbData && cbData > *pcbData)
1605 ret = ERROR_MORE_DATA;
1608 CopyMemory(pvData, pvBuf, *pcbData);
1611 HeapFree(GetProcessHeap(), 0, pvBuf);
1614 if (pszSubKey && pszSubKey[0])
1617 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1619 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1620 ZeroMemory(pvData, *pcbData);
1622 if (pdwType) *pdwType = dwType;
1623 if (pcbData) *pcbData = cbData;
1629 /******************************************************************************
1630 * RegEnumValueW [ADVAPI32.@]
1632 * Enumerates the values for the specified open registry key.
1635 * hkey [I] Handle to key to query
1636 * index [I] Index of value to query
1637 * value [O] Value string
1638 * val_count [I/O] Size of value buffer (in wchars)
1639 * reserved [I] Reserved
1640 * type [O] Type code
1641 * data [O] Value data
1642 * count [I/O] Size of data buffer (in bytes)
1645 * Success: ERROR_SUCCESS
1646 * Failure: nonzero error code from Winerror.h
1649 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1650 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1654 char buffer[256], *buf_ptr = buffer;
1655 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1656 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1658 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1659 hkey, index, value, val_count, reserved, type, data, count );
1661 /* NT only checks count, not val_count */
1662 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1663 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1665 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1666 if (data) total_size += *count;
1667 total_size = min( sizeof(buffer), total_size );
1669 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1670 buffer, total_size, &total_size );
1671 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1675 /* retry with a dynamically allocated buffer */
1676 while (status == STATUS_BUFFER_OVERFLOW)
1678 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1679 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1680 return ERROR_NOT_ENOUGH_MEMORY;
1681 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1682 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1683 buf_ptr, total_size, &total_size );
1686 if (status) goto done;
1690 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1692 status = STATUS_BUFFER_OVERFLOW;
1695 memcpy( value, info->Name, info->NameLength );
1696 *val_count = info->NameLength / sizeof(WCHAR);
1697 value[*val_count] = 0;
1702 if (total_size - info->DataOffset > *count)
1704 status = STATUS_BUFFER_OVERFLOW;
1707 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1708 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1710 /* if the type is REG_SZ and data is not 0-terminated
1711 * and there is enough space in the buffer NT appends a \0 */
1712 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1713 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1717 else status = STATUS_SUCCESS;
1720 if (type) *type = info->Type;
1721 if (count) *count = info->DataLength;
1724 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1725 return RtlNtStatusToDosError(status);
1729 /******************************************************************************
1730 * RegEnumValueA [ADVAPI32.@]
1732 * See RegEnumValueW.
1734 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1735 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1739 char buffer[256], *buf_ptr = buffer;
1740 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1741 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1743 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1744 hkey, index, value, val_count, reserved, type, data, count );
1746 /* NT only checks count, not val_count */
1747 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1748 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1750 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1751 if (data) total_size += *count;
1752 total_size = min( sizeof(buffer), total_size );
1754 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1755 buffer, total_size, &total_size );
1756 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1758 /* we need to fetch the contents for a string type even if not requested,
1759 * because we need to compute the length of the ASCII string. */
1760 if (value || data || is_string(info->Type))
1762 /* retry with a dynamically allocated buffer */
1763 while (status == STATUS_BUFFER_OVERFLOW)
1765 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1766 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1767 return ERROR_NOT_ENOUGH_MEMORY;
1768 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1769 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1770 buf_ptr, total_size, &total_size );
1773 if (status) goto done;
1775 if (is_string(info->Type))
1778 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1779 total_size - info->DataOffset );
1782 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1785 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1786 total_size - info->DataOffset );
1787 /* if the type is REG_SZ and data is not 0-terminated
1788 * and there is enough space in the buffer NT appends a \0 */
1789 if (len < *count && data[len-1]) data[len] = 0;
1792 info->DataLength = len;
1796 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1797 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1800 if (value && !status)
1804 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1805 if (len >= *val_count)
1807 status = STATUS_BUFFER_OVERFLOW;
1810 len = *val_count - 1;
1811 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1817 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1823 else status = STATUS_SUCCESS;
1825 if (type) *type = info->Type;
1826 if (count) *count = info->DataLength;
1829 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1830 return RtlNtStatusToDosError(status);
1835 /******************************************************************************
1836 * RegDeleteValueW [ADVAPI32.@]
1838 * See RegDeleteValueA.
1840 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1842 UNICODE_STRING nameW;
1844 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1846 RtlInitUnicodeString( &nameW, name );
1847 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1851 /******************************************************************************
1852 * RegDeleteValueA [ADVAPI32.@]
1854 * Delete a value from the registry.
1857 * hkey [I] Registry handle of the key holding the value
1858 * name [I] Name of the value under hkey to delete
1861 * Success: ERROR_SUCCESS
1862 * Failure: nonzero error code from Winerror.h
1864 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1869 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1871 RtlInitAnsiString( &nameA, name );
1872 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1874 status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1875 return RtlNtStatusToDosError( status );
1879 /******************************************************************************
1880 * RegLoadKeyW [ADVAPI32.@]
1882 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1883 * registration information from a specified file into that subkey.
1886 * hkey [I] Handle of open key
1887 * subkey [I] Address of name of subkey
1888 * filename [I] Address of filename for registry information
1891 * Success: ERROR_SUCCESS
1892 * Failure: nonzero error code from Winerror.h
1894 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1896 OBJECT_ATTRIBUTES destkey, file;
1897 UNICODE_STRING subkeyW, filenameW;
1900 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
1902 destkey.Length = sizeof(destkey);
1903 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
1904 destkey.ObjectName = &subkeyW; /* name of the key */
1905 destkey.Attributes = 0;
1906 destkey.SecurityDescriptor = NULL;
1907 destkey.SecurityQualityOfService = NULL;
1908 RtlInitUnicodeString(&subkeyW, subkey);
1910 file.Length = sizeof(file);
1911 file.RootDirectory = NULL;
1912 file.ObjectName = &filenameW; /* file containing the hive */
1913 file.Attributes = OBJ_CASE_INSENSITIVE;
1914 file.SecurityDescriptor = NULL;
1915 file.SecurityQualityOfService = NULL;
1916 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
1918 status = NtLoadKey(&destkey, &file);
1919 RtlFreeUnicodeString(&filenameW);
1920 return RtlNtStatusToDosError( status );
1924 /******************************************************************************
1925 * RegLoadKeyA [ADVAPI32.@]
1929 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1931 UNICODE_STRING subkeyW, filenameW;
1932 STRING subkeyA, filenameA;
1936 RtlInitAnsiString(&subkeyA, subkey);
1937 RtlInitAnsiString(&filenameA, filename);
1939 RtlInitUnicodeString(&subkeyW, NULL);
1940 RtlInitUnicodeString(&filenameW, NULL);
1941 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
1942 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
1944 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
1946 else ret = RtlNtStatusToDosError(status);
1947 RtlFreeUnicodeString(&subkeyW);
1948 RtlFreeUnicodeString(&filenameW);
1953 /******************************************************************************
1954 * RegSaveKeyW [ADVAPI32.@]
1956 * Save a key and all of its subkeys and values to a new file in the standard format.
1959 * hkey [I] Handle of key where save begins
1960 * lpFile [I] Address of filename to save to
1961 * sa [I] Address of security structure
1964 * Success: ERROR_SUCCESS
1965 * Failure: nonzero error code from Winerror.h
1967 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1969 static const WCHAR format[] =
1970 {'r','e','g','%','0','4','x','.','t','m','p',0};
1971 WCHAR buffer[MAX_PATH];
1977 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
1979 if (!file || !*file) return ERROR_INVALID_PARAMETER;
1980 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1982 err = GetLastError();
1983 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
1987 snprintfW( nameW, 16, format, count++ );
1988 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1989 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1990 if (handle != INVALID_HANDLE_VALUE) break;
1991 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
1993 /* Something gone haywire ? Please report if this happens abnormally */
1995 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);
1998 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2000 CloseHandle( handle );
2003 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2005 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2007 ret = GetLastError();
2010 if (ret) DeleteFileW( buffer );
2013 SetLastError( err ); /* restore last error code */
2018 /******************************************************************************
2019 * RegSaveKeyA [ADVAPI32.@]
2023 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2025 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2029 RtlInitAnsiString(&fileA, file);
2030 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2031 return RtlNtStatusToDosError( status );
2032 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2036 /******************************************************************************
2037 * RegRestoreKeyW [ADVAPI32.@]
2039 * Read the registry information from a file and copy it over a key.
2042 * hkey [I] Handle of key where restore begins
2043 * lpFile [I] Address of filename containing saved tree
2044 * dwFlags [I] Optional flags
2047 * Success: ERROR_SUCCESS
2048 * Failure: nonzero error code from Winerror.h
2050 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2052 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2054 /* It seems to do this check before the hkey check */
2055 if (!lpFile || !*lpFile)
2056 return ERROR_INVALID_PARAMETER;
2058 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2060 /* Check for file existence */
2062 return ERROR_SUCCESS;
2066 /******************************************************************************
2067 * RegRestoreKeyA [ADVAPI32.@]
2069 * See RegRestoreKeyW.
2071 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2073 UNICODE_STRING lpFileW;
2076 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2077 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2078 RtlFreeUnicodeString( &lpFileW );
2083 /******************************************************************************
2084 * RegUnLoadKeyW [ADVAPI32.@]
2086 * Unload a registry key and its subkeys from the registry.
2089 * hkey [I] Handle of open key
2090 * lpSubKey [I] Address of name of subkey to unload
2093 * Success: ERROR_SUCCESS
2094 * Failure: nonzero error code from Winerror.h
2096 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2100 OBJECT_ATTRIBUTES attr;
2101 UNICODE_STRING subkey;
2103 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2105 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2107 return ERROR_INVALID_PARAMETER;
2109 RtlInitUnicodeString(&subkey, lpSubKey);
2110 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2111 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2119 /******************************************************************************
2120 * RegUnLoadKeyA [ADVAPI32.@]
2122 * See RegUnLoadKeyW.
2124 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2126 UNICODE_STRING lpSubKeyW;
2129 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2130 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2131 RtlFreeUnicodeString( &lpSubKeyW );
2136 /******************************************************************************
2137 * RegReplaceKeyW [ADVAPI32.@]
2139 * Replace the file backing a registry key and all its subkeys with another file.
2142 * hkey [I] Handle of open key
2143 * lpSubKey [I] Address of name of subkey
2144 * lpNewFile [I] Address of filename for file with new data
2145 * lpOldFile [I] Address of filename for backup file
2148 * Success: ERROR_SUCCESS
2149 * Failure: nonzero error code from Winerror.h
2151 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2154 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2155 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2156 return ERROR_SUCCESS;
2160 /******************************************************************************
2161 * RegReplaceKeyA [ADVAPI32.@]
2163 * See RegReplaceKeyW.
2165 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2168 UNICODE_STRING lpSubKeyW;
2169 UNICODE_STRING lpNewFileW;
2170 UNICODE_STRING lpOldFileW;
2173 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2174 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2175 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2176 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2177 RtlFreeUnicodeString( &lpOldFileW );
2178 RtlFreeUnicodeString( &lpNewFileW );
2179 RtlFreeUnicodeString( &lpSubKeyW );
2184 /******************************************************************************
2185 * RegSetKeySecurity [ADVAPI32.@]
2187 * Set the security of an open registry key.
2190 * hkey [I] Open handle of key to set
2191 * SecurityInfo [I] Descriptor contents
2192 * pSecurityDesc [I] Address of descriptor for key
2195 * Success: ERROR_SUCCESS
2196 * Failure: nonzero error code from Winerror.h
2198 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2199 PSECURITY_DESCRIPTOR pSecurityDesc )
2201 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2203 /* It seems to perform this check before the hkey check */
2204 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2205 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2206 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2207 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2210 return ERROR_INVALID_PARAMETER;
2213 return ERROR_INVALID_PARAMETER;
2215 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2217 return ERROR_SUCCESS;
2221 /******************************************************************************
2222 * RegGetKeySecurity [ADVAPI32.@]
2224 * Get a copy of the security descriptor for a given registry key.
2227 * hkey [I] Open handle of key to set
2228 * SecurityInformation [I] Descriptor contents
2229 * pSecurityDescriptor [O] Address of descriptor for key
2230 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2233 * Success: ERROR_SUCCESS
2234 * Failure: Error code
2236 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2237 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2238 LPDWORD lpcbSecurityDescriptor )
2240 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2241 *lpcbSecurityDescriptor);
2243 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2245 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2246 SecurityInformation, pSecurityDescriptor,
2247 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2251 /******************************************************************************
2252 * RegFlushKey [ADVAPI32.@]
2254 * Immediately write a registry key to registry.
2257 * hkey [I] Handle of key to write
2260 * Success: ERROR_SUCCESS
2261 * Failure: Error code
2263 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2265 hkey = get_special_root_hkey( hkey );
2266 if (!hkey) return ERROR_INVALID_HANDLE;
2268 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2272 /******************************************************************************
2273 * RegConnectRegistryW [ADVAPI32.@]
2275 * Establish a connection to a predefined registry key on another computer.
2278 * lpMachineName [I] Address of name of remote computer
2279 * hHey [I] Predefined registry handle
2280 * phkResult [I] Address of buffer for remote registry handle
2283 * Success: ERROR_SUCCESS
2284 * Failure: nonzero error code from Winerror.h
2286 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2291 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2293 if (!lpMachineName || !*lpMachineName) {
2294 /* Use the local machine name */
2295 ret = RegOpenKeyW( hKey, NULL, phkResult );
2298 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2299 DWORD len = sizeof(compName) / sizeof(WCHAR);
2301 /* MSDN says lpMachineName must start with \\ : not so */
2302 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2304 if (GetComputerNameW(compName, &len))
2306 if (!strcmpiW(lpMachineName, compName))
2307 ret = RegOpenKeyW(hKey, NULL, phkResult);
2310 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2311 ret = ERROR_BAD_NETPATH;
2315 ret = GetLastError();
2321 /******************************************************************************
2322 * RegConnectRegistryA [ADVAPI32.@]
2324 * See RegConnectRegistryW.
2326 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2328 UNICODE_STRING machineW;
2331 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2332 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2333 RtlFreeUnicodeString( &machineW );
2338 /******************************************************************************
2339 * RegNotifyChangeKeyValue [ADVAPI32.@]
2341 * Notify the caller about changes to the attributes or contents of a registry key.
2344 * hkey [I] Handle of key to watch
2345 * fWatchSubTree [I] Flag for subkey notification
2346 * fdwNotifyFilter [I] Changes to be reported
2347 * hEvent [I] Handle of signaled event
2348 * fAsync [I] Flag for asynchronous reporting
2351 * Success: ERROR_SUCCESS
2352 * Failure: nonzero error code from Winerror.h
2354 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2355 DWORD fdwNotifyFilter, HANDLE hEvent,
2359 IO_STATUS_BLOCK iosb;
2361 hkey = get_special_root_hkey( hkey );
2362 if (!hkey) return ERROR_INVALID_HANDLE;
2364 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2367 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2368 fdwNotifyFilter, fAsync, NULL, 0,
2371 if (status && status != STATUS_TIMEOUT)
2372 return RtlNtStatusToDosError( status );
2374 return ERROR_SUCCESS;
2377 /******************************************************************************
2378 * RegOpenUserClassesRoot [ADVAPI32.@]
2380 * Open the HKEY_CLASSES_ROOT key for a user.
2383 * hToken [I] Handle of token representing the user
2384 * dwOptions [I] Reserved, must be 0
2385 * samDesired [I] Desired access rights
2386 * phkResult [O] Destination for the resulting key handle
2389 * Success: ERROR_SUCCESS
2390 * Failure: nonzero error code from Winerror.h
2393 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2394 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2395 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2397 LSTATUS WINAPI RegOpenUserClassesRoot(
2404 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2406 *phkResult = HKEY_CLASSES_ROOT;
2407 return ERROR_SUCCESS;
2410 /******************************************************************************
2411 * load_string [Internal]
2413 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2414 * avoid importing user32, which is higher level than advapi32. Helper for
2417 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2424 /* Negative values have to be inverted. */
2425 if (HIWORD(resId) == 0xffff)
2426 resId = (UINT)(-((INT)resId));
2428 /* Load the resource into memory and get a pointer to it. */
2429 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2430 if (!hResource) return 0;
2431 hMemory = LoadResource(hModule, hResource);
2432 if (!hMemory) return 0;
2433 pString = LockResource(hMemory);
2435 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2436 idxString = resId & 0xf;
2437 while (idxString--) pString += *pString + 1;
2439 /* If no buffer is given, return length of the string. */
2440 if (!pwszBuffer) return *pString;
2442 /* Else copy over the string, respecting the buffer size. */
2443 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2444 if (cMaxChars >= 0) {
2445 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2446 pwszBuffer[cMaxChars] = '\0';
2452 /******************************************************************************
2453 * RegLoadMUIStringW [ADVAPI32.@]
2455 * Load the localized version of a string resource from some PE, respective
2456 * id and path of which are given in the registry value in the format
2457 * @[path]\dllname,-resourceId
2460 * hKey [I] Key, of which to load the string value from.
2461 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2462 * pszBuffer [O] Buffer to store the localized string in.
2463 * cbBuffer [I] Size of the destination buffer in bytes.
2464 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2465 * dwFlags [I] None supported yet.
2466 * pszBaseDir [I] Not supported yet.
2469 * Success: ERROR_SUCCESS,
2470 * Failure: nonzero error code from winerror.h
2473 * This is an API of Windows Vista, which wasn't available at the time this code
2474 * was written. We have to check for the correct behaviour once it's available.
2476 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2477 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2479 DWORD dwValueType, cbData;
2480 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2483 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2484 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2485 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2487 /* Parameter sanity checks. */
2488 if (!hKey || !pwszBuffer)
2489 return ERROR_INVALID_PARAMETER;
2491 if (pwszBaseDir && *pwszBaseDir) {
2492 FIXME("BaseDir parameter not yet supported!\n");
2493 return ERROR_INVALID_PARAMETER;
2496 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2497 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2498 if (result != ERROR_SUCCESS) goto cleanup;
2499 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2500 result = ERROR_FILE_NOT_FOUND;
2503 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2504 if (!pwszTempBuffer) {
2505 result = ERROR_NOT_ENOUGH_MEMORY;
2508 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2509 if (result != ERROR_SUCCESS) goto cleanup;
2511 /* Expand environment variables, if appropriate, or copy the original string over. */
2512 if (dwValueType == REG_EXPAND_SZ) {
2513 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2514 if (!cbData) goto cleanup;
2515 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2516 if (!pwszExpandedBuffer) {
2517 result = ERROR_NOT_ENOUGH_MEMORY;
2520 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2522 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2523 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2526 /* If the value references a resource based string, parse the value and load the string.
2527 * Else just copy over the original value. */
2528 result = ERROR_SUCCESS;
2529 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2530 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2532 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2536 /* Format of the expanded value is 'path_to_dll,-resId' */
2537 if (!pComma || pComma[1] != '-') {
2538 result = ERROR_BADKEY;
2542 uiStringId = atoiW(pComma+2);
2545 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2546 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2547 result = ERROR_BADKEY;
2548 FreeLibrary(hModule);
2552 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2553 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2557 /******************************************************************************
2558 * RegLoadMUIStringA [ADVAPI32.@]
2560 * See RegLoadMUIStringW
2562 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2563 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2565 UNICODE_STRING valueW, baseDirW;
2567 DWORD cbData = cbBuffer * sizeof(WCHAR);
2570 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2571 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2572 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2573 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2575 result = ERROR_NOT_ENOUGH_MEMORY;
2579 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2582 if (result == ERROR_SUCCESS) {
2583 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2589 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2590 RtlFreeUnicodeString(&baseDirW);
2591 RtlFreeUnicodeString(&valueW);
2596 /******************************************************************************
2597 * RegDisablePredefinedCache [ADVAPI32.@]
2599 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2605 * Success: ERROR_SUCCESS
2606 * Failure: nonzero error code from Winerror.h
2609 * This is useful for services that use impersonation.
2611 LSTATUS WINAPI RegDisablePredefinedCache(void)
2613 HKEY hkey_current_user;
2614 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2616 /* prevent caching of future requests */
2617 hkcu_cache_disabled = TRUE;
2619 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2621 if (hkey_current_user)
2622 NtClose( hkey_current_user );
2624 return ERROR_SUCCESS;
2627 /******************************************************************************
2628 * RegDeleteTreeW [ADVAPI32.@]
2631 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2634 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2635 DWORD dwMaxLen, dwSize;
2636 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2637 HKEY hSubKey = hKey;
2639 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2643 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2644 if (ret) return ret;
2647 /* Get highest length for keys, values */
2648 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2649 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2650 if (ret) goto cleanup;
2654 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2655 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2657 /* Name too big: alloc a buffer for it */
2658 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2660 ret = ERROR_NOT_ENOUGH_MEMORY;
2666 /* Recursively delete all the subkeys */
2670 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2671 NULL, NULL, NULL)) break;
2673 ret = RegDeleteTreeW(hSubKey, lpszName);
2674 if (ret) goto cleanup;
2678 ret = RegDeleteKeyW(hKey, lpszSubKey);
2683 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2684 NULL, NULL, NULL, NULL)) break;
2686 ret = RegDeleteValueW(hKey, lpszName);
2687 if (ret) goto cleanup;
2691 /* Free buffer if allocated */
2692 if (lpszName != szNameBuf)
2693 HeapFree( GetProcessHeap(), 0, lpszName);
2695 RegCloseKey(hSubKey);
2699 /******************************************************************************
2700 * RegDeleteTreeA [ADVAPI32.@]
2703 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2706 UNICODE_STRING lpszSubKeyW;
2708 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2709 else lpszSubKeyW.Buffer = NULL;
2710 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2711 RtlFreeUnicodeString( &lpszSubKeyW );