winspool/tests: Run more tests on Win64.
[wine/hacks.git] / dlls / advapi32 / registry.c
blob52de6c5d427f99ab9cc456c24c67a67234fbb93c
1 /*
2 * Registry management
4 * Copyright (C) 1999 Alexandre Julliard
6 * Based on misc/registry.c code
7 * Copyright (C) 1996 Marcus Meissner
8 * Copyright (C) 1998 Matthew Becker
9 * Copyright (C) 1999 Sylvain St-Germain
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <stdio.h>
30 #include "ntstatus.h"
31 #define WIN32_NO_STATUS
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winreg.h"
35 #include "winerror.h"
36 #include "winternl.h"
37 #include "winuser.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(reg);
44 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
45 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
46 #define NB_SPECIAL_ROOT_KEYS ((UINT_PTR)HKEY_SPECIAL_ROOT_LAST - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST + 1)
48 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
49 static BOOL hkcu_cache_disabled;
51 static const WCHAR name_CLASSES_ROOT[] =
52 {'M','a','c','h','i','n','e','\\',
53 'S','o','f','t','w','a','r','e','\\',
54 'C','l','a','s','s','e','s',0};
55 static const WCHAR name_LOCAL_MACHINE[] =
56 {'M','a','c','h','i','n','e',0};
57 static const WCHAR name_USERS[] =
58 {'U','s','e','r',0};
59 static const WCHAR name_PERFORMANCE_DATA[] =
60 {'P','e','r','f','D','a','t','a',0};
61 static const WCHAR name_CURRENT_CONFIG[] =
62 {'M','a','c','h','i','n','e','\\',
63 'S','y','s','t','e','m','\\',
64 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
65 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
66 'C','u','r','r','e','n','t',0};
67 static const WCHAR name_DYN_DATA[] =
68 {'D','y','n','D','a','t','a',0};
70 static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] =
72 name_CLASSES_ROOT,
73 NULL, /* HKEY_CURRENT_USER is determined dynamically */
74 name_LOCAL_MACHINE,
75 name_USERS,
76 name_PERFORMANCE_DATA,
77 name_CURRENT_CONFIG,
78 name_DYN_DATA
82 /* check if value type needs string conversion (Ansi<->Unicode) */
83 static inline int is_string( DWORD type )
85 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
88 /* check if current version is NT or Win95 */
89 static inline int is_version_nt(void)
91 return !(GetVersion() & 0x80000000);
94 /* create one of the HKEY_* special root keys */
95 static HKEY create_special_root_hkey( HANDLE hkey, DWORD access )
97 HKEY ret = 0;
98 int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
100 if (hkey == HKEY_CURRENT_USER)
102 if (RtlOpenCurrentUser( access, &hkey )) return 0;
103 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
105 /* don't cache the key in the table if caching is disabled */
106 if (hkcu_cache_disabled)
107 return hkey;
109 else
111 OBJECT_ATTRIBUTES attr;
112 UNICODE_STRING name;
114 attr.Length = sizeof(attr);
115 attr.RootDirectory = 0;
116 attr.ObjectName = &name;
117 attr.Attributes = 0;
118 attr.SecurityDescriptor = NULL;
119 attr.SecurityQualityOfService = NULL;
120 RtlInitUnicodeString( &name, root_key_names[idx] );
121 if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
122 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
125 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
126 ret = hkey;
127 else
128 NtClose( hkey ); /* somebody beat us to it */
129 return ret;
132 /* map the hkey from special root to normal key if necessary */
133 static inline HKEY get_special_root_hkey( HKEY hkey )
135 HKEY ret = hkey;
137 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
139 if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
140 ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
142 return ret;
146 /******************************************************************************
147 * RegOverridePredefKey [ADVAPI32.@]
149 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
151 HKEY old_key;
152 int idx;
154 if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST))
155 return ERROR_INVALID_PARAMETER;
156 idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
158 if (override)
160 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
161 GetCurrentProcess(), (HANDLE *)&override,
162 0, 0, DUPLICATE_SAME_ACCESS );
163 if (status) return RtlNtStatusToDosError( status );
166 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
167 if (old_key) NtClose( old_key );
168 return ERROR_SUCCESS;
172 /******************************************************************************
173 * RegCreateKeyExW [ADVAPI32.@]
175 * See RegCreateKeyExA.
177 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
178 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
179 PHKEY retkey, LPDWORD dispos )
181 OBJECT_ATTRIBUTES attr;
182 UNICODE_STRING nameW, classW;
184 if (reserved) return ERROR_INVALID_PARAMETER;
185 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
187 attr.Length = sizeof(attr);
188 attr.RootDirectory = hkey;
189 attr.ObjectName = &nameW;
190 attr.Attributes = 0;
191 attr.SecurityDescriptor = NULL;
192 attr.SecurityQualityOfService = NULL;
193 RtlInitUnicodeString( &nameW, name );
194 RtlInitUnicodeString( &classW, class );
196 return RtlNtStatusToDosError( NtCreateKey( (PHANDLE)retkey, access, &attr, 0,
197 &classW, options, dispos ) );
201 /******************************************************************************
202 * RegCreateKeyExA [ADVAPI32.@]
204 * Open a registry key, creating it if it doesn't exist.
206 * PARAMS
207 * hkey [I] Handle of the parent registry key
208 * name [I] Name of the new key to open or create
209 * reserved [I] Reserved, pass 0
210 * class [I] The object type of the new key
211 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
212 * access [I] Access level desired
213 * sa [I] Security attributes for the key
214 * retkey [O] Destination for the resulting handle
215 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
217 * RETURNS
218 * Success: ERROR_SUCCESS.
219 * Failure: A standard Win32 error code. retkey remains untouched.
221 * FIXME
222 * MAXIMUM_ALLOWED in access mask not supported by server
224 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
225 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
226 PHKEY retkey, LPDWORD dispos )
228 OBJECT_ATTRIBUTES attr;
229 UNICODE_STRING classW;
230 ANSI_STRING nameA, classA;
231 NTSTATUS status;
233 if (reserved) return ERROR_INVALID_PARAMETER;
234 if (!is_version_nt())
236 access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
237 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
239 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
241 attr.Length = sizeof(attr);
242 attr.RootDirectory = hkey;
243 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
244 attr.Attributes = 0;
245 attr.SecurityDescriptor = NULL;
246 attr.SecurityQualityOfService = NULL;
247 RtlInitAnsiString( &nameA, name );
248 RtlInitAnsiString( &classA, class );
250 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
251 &nameA, FALSE )))
253 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
255 status = NtCreateKey( (PHANDLE)retkey, access, &attr, 0, &classW, options, dispos );
256 RtlFreeUnicodeString( &classW );
259 return RtlNtStatusToDosError( status );
263 /******************************************************************************
264 * RegCreateKeyW [ADVAPI32.@]
266 * Creates the specified reg key.
268 * PARAMS
269 * hKey [I] Handle to an open key.
270 * lpSubKey [I] Name of a key that will be opened or created.
271 * phkResult [O] Receives a handle to the opened or created key.
273 * RETURNS
274 * Success: ERROR_SUCCESS
275 * Failure: nonzero error code defined in Winerror.h
277 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
279 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
280 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
281 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
282 KEY_ALL_ACCESS, NULL, phkResult, NULL );
286 /******************************************************************************
287 * RegCreateKeyA [ADVAPI32.@]
289 * See RegCreateKeyW.
291 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
293 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
294 KEY_ALL_ACCESS, NULL, phkResult, NULL );
299 /******************************************************************************
300 * RegOpenKeyExW [ADVAPI32.@]
302 * See RegOpenKeyExA.
304 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
306 OBJECT_ATTRIBUTES attr;
307 UNICODE_STRING nameW;
309 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
310 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
312 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
314 attr.Length = sizeof(attr);
315 attr.RootDirectory = hkey;
316 attr.ObjectName = &nameW;
317 attr.Attributes = 0;
318 attr.SecurityDescriptor = NULL;
319 attr.SecurityQualityOfService = NULL;
320 RtlInitUnicodeString( &nameW, name );
321 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE)retkey, access, &attr ) );
325 /******************************************************************************
326 * RegOpenKeyExA [ADVAPI32.@]
328 * Open a registry key.
330 * PARAMS
331 * hkey [I] Handle of open key
332 * name [I] Name of subkey to open
333 * reserved [I] Reserved - must be zero
334 * access [I] Security access mask
335 * retkey [O] Handle to open key
337 * RETURNS
338 * Success: ERROR_SUCCESS
339 * Failure: A standard Win32 error code. retkey is set to 0.
341 * NOTES
342 * Unlike RegCreateKeyExA(), this function will not create the key if it
343 * does not exist.
345 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
347 OBJECT_ATTRIBUTES attr;
348 STRING nameA;
349 NTSTATUS status;
351 if (!is_version_nt()) access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
352 else
354 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
355 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
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;
363 attr.Attributes = 0;
364 attr.SecurityDescriptor = NULL;
365 attr.SecurityQualityOfService = NULL;
367 RtlInitAnsiString( &nameA, name );
368 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
369 &nameA, FALSE )))
371 status = NtOpenKey( (PHANDLE)retkey, access, &attr );
373 return RtlNtStatusToDosError( status );
377 /******************************************************************************
378 * RegOpenKeyW [ADVAPI32.@]
380 * See RegOpenKeyA.
382 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
384 if (!name || !*name)
386 *retkey = hkey;
387 return ERROR_SUCCESS;
389 return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
393 /******************************************************************************
394 * RegOpenKeyA [ADVAPI32.@]
396 * Open a registry key.
398 * PARAMS
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
403 * RETURNS
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 )
409 if (!name || !*name)
411 *retkey = hkey;
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.
424 * PARAMS
425 * access [I] Desired access rights to the key
426 * retkey [O] Handle to the opened key
428 * RETURNS
429 * Success: ERROR_SUCCESS
430 * Failure: nonzero error code from Winerror.h
432 * FIXME
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.
450 * PARAMS
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
460 * RETURNS
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 )
468 NTSTATUS status;
469 char buffer[256], *buf_ptr = buffer;
470 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
471 DWORD total_size;
473 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
474 name_len ? *name_len : 0, 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 );
493 if (!status)
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;
502 else
504 *name_len = len;
505 memcpy( name, info->Name, info->NameLength );
506 name[len] = 0;
507 if (class_len)
509 *class_len = cls_len;
510 if (class)
512 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
513 class[cls_len] = 0;
519 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
520 return RtlNtStatusToDosError( status );
524 /******************************************************************************
525 * RegEnumKeyExA [ADVAPI32.@]
527 * See RegEnumKeyExW.
529 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
530 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
532 NTSTATUS status;
533 char buffer[256], *buf_ptr = buffer;
534 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
535 DWORD total_size;
537 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
538 name_len ? *name_len : 0, 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 );
557 if (!status)
559 DWORD len, cls_len;
561 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
562 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
563 info->ClassLength );
564 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
566 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
567 status = STATUS_BUFFER_OVERFLOW;
568 else
570 *name_len = len;
571 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
572 name[len] = 0;
573 if (class_len)
575 *class_len = cls_len;
576 if (class)
578 RtlUnicodeToMultiByteN( class, cls_len, NULL,
579 (WCHAR *)(buf_ptr + info->ClassOffset),
580 info->ClassLength );
581 class[cls_len] = 0;
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.
597 * PARAMS
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.
603 * RETURNS
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.@]
617 * See RegEnumKeyW.
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.
630 * PARAMS
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
644 * RETURNS
645 * Success: ERROR_SUCCESS
646 * Failure: system error code.
648 * NOTES
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 )
659 NTSTATUS status;
660 char buffer[256], *buf_ptr = buffer;
661 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
662 DWORD total_size;
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;
673 if (class)
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;
691 else
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;
708 done:
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.
719 * PARAMS
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.
726 * RETURNS
727 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
728 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
729 * bytes.
731 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
732 LPSTR lpValueBuf, LPDWORD ldwTotsize )
734 unsigned int i;
735 DWORD maxBytes = *ldwTotsize;
736 HRESULT status;
737 LPSTR bufptr = lpValueBuf;
738 *ldwTotsize = 0;
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)
749 return status;
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)
758 return status;
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 )
780 unsigned int i;
781 DWORD maxBytes = *ldwTotsize;
782 HRESULT status;
783 LPSTR bufptr = (LPSTR)lpValueBuf;
784 *ldwTotsize = 0;
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)
794 return status;
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)
803 return status;
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.
821 * PARAMS
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
829 * class in TCHARS.
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.
836 * RETURNS
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 )
845 NTSTATUS status;
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);
874 if (class_len)
876 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
877 *class_len = len;
879 if (class && !status)
881 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
882 info->ClassLength );
883 class[len] = 0;
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;
896 done:
897 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
898 return RtlNtStatusToDosError( status );
902 /******************************************************************************
903 * RegCloseKey [ADVAPI32.@]
905 * Close an open registry key.
907 * PARAMS
908 * hkey [I] Handle of key to close
910 * RETURNS
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.@]
925 * See RegDeleteKeyA.
927 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
929 DWORD ret;
930 HKEY tmp;
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 ) );
939 RegCloseKey( tmp );
941 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
942 return ret;
946 /******************************************************************************
947 * RegDeleteKeyA [ADVAPI32.@]
949 * Delete a registry key.
951 * PARAMS
952 * hkey [I] Handle to parent key containing the key to delete
953 * name [I] Name of the key user hkey to delete
955 * NOTES
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.
960 * RETURNS
961 * Success: ERROR_SUCCESS
962 * Failure: Error code
964 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
966 DWORD ret;
967 HKEY tmp;
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 */
977 CHAR name[MAX_PATH];
979 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
981 if(RegDeleteKeyA(tmp, name)) /* recurse */
982 break;
985 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
986 RegCloseKey( tmp );
988 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
989 return ret;
994 /******************************************************************************
995 * RegSetValueExW [ADVAPI32.@]
997 * Set the data and contents of a registry value.
999 * PARAMS
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
1007 * RETURNS
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.
1036 * NOTES
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 )
1043 ANSI_STRING nameA;
1044 WCHAR *dataW = NULL;
1045 NTSTATUS status;
1047 if (!is_version_nt()) /* win95 */
1049 if (type == REG_SZ)
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 */
1065 DWORD lenW;
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 );
1069 count = lenW;
1070 data = (BYTE *)dataW;
1073 RtlInitAnsiString( &nameA, name );
1074 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1075 &nameA, FALSE )))
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.
1089 * PARAMS
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.
1096 * RETURNS
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 )
1102 HKEY subkey = hkey;
1103 DWORD ret;
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 );
1117 return ret;
1121 /******************************************************************************
1122 * RegSetValueA [ADVAPI32.@]
1124 * See RegSetValueW.
1126 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1128 HKEY subkey = hkey;
1129 DWORD ret;
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 );
1141 return ret;
1146 /******************************************************************************
1147 * RegQueryValueExW [ADVAPI32.@]
1149 * See RegQueryValueExA.
1151 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1152 LPBYTE data, LPDWORD count )
1154 NTSTATUS status;
1155 UNICODE_STRING name_str;
1156 DWORD total_size;
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 );
1171 else
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;
1181 if (data)
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 );
1194 if (!status)
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;
1212 done:
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.
1223 * PARAMS
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
1231 * RETURNS
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.
1237 * NOTES
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 )
1244 NTSTATUS status;
1245 ANSI_STRING nameA;
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,
1265 &nameA, FALSE )))
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;
1283 goto done;
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))
1294 DWORD len;
1296 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1297 total_size - info_size );
1298 if (data && len)
1300 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1301 else
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;
1312 else if (data)
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;
1323 done:
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.
1334 * PARAMS
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
1338 * of the key.
1339 * count [I/O] Size of lpValue in bytes.
1341 * RETURNS
1342 * Success: ERROR_SUCCESS
1343 * Failure: nonzero error code from Winerror.h
1345 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1347 DWORD ret;
1348 HKEY subkey = hkey;
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;
1365 return ret;
1369 /******************************************************************************
1370 * RegQueryValueA [ADVAPI32.@]
1372 * See RegQueryValueW.
1374 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1376 DWORD ret;
1377 HKEY subkey = hkey;
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;
1394 return ret;
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)
1409 DWORD dwMask = 0;
1411 switch (dwType)
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)
1427 DWORD cbExpect = 0;
1429 if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD)
1430 cbExpect = 4;
1431 else if ((dwFlags & RRF_RT_QWORD) == RRF_RT_QWORD)
1432 cbExpect = 8;
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.
1449 * PARAMS
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'
1458 * for strings.
1460 * RETURNS
1461 * Success: ERROR_SUCCESS
1462 * Failure: nonzero error code from Winerror.h
1464 * NOTES
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.
1469 * An exception is the case where RRF_RT_ANY is specified, because then
1470 * RRF_NOEXPAND is allowed.
1472 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1473 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1474 LPDWORD pcbData )
1476 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1477 PVOID pvBuf = NULL;
1478 LONG ret;
1480 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1481 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1482 pvData, pcbData, cbData);
1484 if (pvData && !pcbData)
1485 return ERROR_INVALID_PARAMETER;
1486 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1487 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1488 return ERROR_INVALID_PARAMETER;
1490 if (pszSubKey && pszSubKey[0])
1492 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1493 if (ret != ERROR_SUCCESS) return ret;
1496 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1498 /* If we are going to expand we need to read in the whole the value even
1499 * if the passed buffer was too small as the expanded string might be
1500 * smaller than the unexpanded one and could fit into cbData bytes. */
1501 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1502 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1504 do {
1505 HeapFree(GetProcessHeap(), 0, pvBuf);
1507 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1508 if (!pvBuf)
1510 ret = ERROR_NOT_ENOUGH_MEMORY;
1511 break;
1514 if (ret == ERROR_MORE_DATA || !pvData)
1515 ret = RegQueryValueExW(hKey, pszValue, NULL,
1516 &dwType, pvBuf, &cbData);
1517 else
1519 /* Even if cbData was large enough we have to copy the
1520 * string since ExpandEnvironmentStrings can't handle
1521 * overlapping buffers. */
1522 CopyMemory(pvBuf, pvData, cbData);
1525 /* Both the type or the value itself could have been modified in
1526 * between so we have to keep retrying until the buffer is large
1527 * enough or we no longer have to expand the value. */
1528 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1530 if (ret == ERROR_SUCCESS)
1532 /* Recheck dwType in case it changed since the first call */
1533 if (dwType == REG_EXPAND_SZ)
1535 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1536 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1537 dwType = REG_SZ;
1538 if(pvData && pcbData && cbData > *pcbData)
1539 ret = ERROR_MORE_DATA;
1541 else if (pvData)
1542 CopyMemory(pvData, pvBuf, *pcbData);
1545 HeapFree(GetProcessHeap(), 0, pvBuf);
1548 if (pszSubKey && pszSubKey[0])
1549 RegCloseKey(hKey);
1551 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1553 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1554 ZeroMemory(pvData, *pcbData);
1556 if (pdwType) *pdwType = dwType;
1557 if (pcbData) *pcbData = cbData;
1559 return ret;
1563 /******************************************************************************
1564 * RegGetValueA [ADVAPI32.@]
1566 * See RegGetValueW.
1568 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1569 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1570 LPDWORD pcbData )
1572 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1573 PVOID pvBuf = NULL;
1574 LONG ret;
1576 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1577 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1578 cbData);
1580 if (pvData && !pcbData)
1581 return ERROR_INVALID_PARAMETER;
1582 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1583 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1584 return ERROR_INVALID_PARAMETER;
1586 if (pszSubKey && pszSubKey[0])
1588 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1589 if (ret != ERROR_SUCCESS) return ret;
1592 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1594 /* If we are going to expand we need to read in the whole the value even
1595 * if the passed buffer was too small as the expanded string might be
1596 * smaller than the unexpanded one and could fit into cbData bytes. */
1597 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1598 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1600 do {
1601 HeapFree(GetProcessHeap(), 0, pvBuf);
1603 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1604 if (!pvBuf)
1606 ret = ERROR_NOT_ENOUGH_MEMORY;
1607 break;
1610 if (ret == ERROR_MORE_DATA || !pvData)
1611 ret = RegQueryValueExA(hKey, pszValue, NULL,
1612 &dwType, pvBuf, &cbData);
1613 else
1615 /* Even if cbData was large enough we have to copy the
1616 * string since ExpandEnvironmentStrings can't handle
1617 * overlapping buffers. */
1618 CopyMemory(pvBuf, pvData, cbData);
1621 /* Both the type or the value itself could have been modified in
1622 * between so we have to keep retrying until the buffer is large
1623 * enough or we no longer have to expand the value. */
1624 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1626 if (ret == ERROR_SUCCESS)
1628 /* Recheck dwType in case it changed since the first call */
1629 if (dwType == REG_EXPAND_SZ)
1631 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1632 pcbData ? *pcbData : 0);
1633 dwType = REG_SZ;
1634 if(pvData && pcbData && cbData > *pcbData)
1635 ret = ERROR_MORE_DATA;
1637 else if (pvData)
1638 CopyMemory(pvData, pvBuf, *pcbData);
1641 HeapFree(GetProcessHeap(), 0, pvBuf);
1644 if (pszSubKey && pszSubKey[0])
1645 RegCloseKey(hKey);
1647 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1649 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1650 ZeroMemory(pvData, *pcbData);
1652 if (pdwType) *pdwType = dwType;
1653 if (pcbData) *pcbData = cbData;
1655 return ret;
1659 /******************************************************************************
1660 * RegEnumValueW [ADVAPI32.@]
1662 * Enumerates the values for the specified open registry key.
1664 * PARAMS
1665 * hkey [I] Handle to key to query
1666 * index [I] Index of value to query
1667 * value [O] Value string
1668 * val_count [I/O] Size of value buffer (in wchars)
1669 * reserved [I] Reserved
1670 * type [O] Type code
1671 * data [O] Value data
1672 * count [I/O] Size of data buffer (in bytes)
1674 * RETURNS
1675 * Success: ERROR_SUCCESS
1676 * Failure: nonzero error code from Winerror.h
1679 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1680 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1682 NTSTATUS status;
1683 DWORD total_size;
1684 char buffer[256], *buf_ptr = buffer;
1685 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1686 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1688 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1689 hkey, index, value, val_count, reserved, type, data, count );
1691 /* NT only checks count, not val_count */
1692 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1693 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1695 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1696 if (data) total_size += *count;
1697 total_size = min( sizeof(buffer), total_size );
1699 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1700 buffer, total_size, &total_size );
1701 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1703 if (value || data)
1705 /* retry with a dynamically allocated buffer */
1706 while (status == STATUS_BUFFER_OVERFLOW)
1708 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1709 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1710 return ERROR_NOT_ENOUGH_MEMORY;
1711 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1712 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1713 buf_ptr, total_size, &total_size );
1716 if (status) goto done;
1718 if (value)
1720 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1722 status = STATUS_BUFFER_OVERFLOW;
1723 goto overflow;
1725 memcpy( value, info->Name, info->NameLength );
1726 *val_count = info->NameLength / sizeof(WCHAR);
1727 value[*val_count] = 0;
1730 if (data)
1732 if (total_size - info->DataOffset > *count)
1734 status = STATUS_BUFFER_OVERFLOW;
1735 goto overflow;
1737 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1738 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1740 /* if the type is REG_SZ and data is not 0-terminated
1741 * and there is enough space in the buffer NT appends a \0 */
1742 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1743 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1747 else status = STATUS_SUCCESS;
1749 overflow:
1750 if (type) *type = info->Type;
1751 if (count) *count = info->DataLength;
1753 done:
1754 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1755 return RtlNtStatusToDosError(status);
1759 /******************************************************************************
1760 * RegEnumValueA [ADVAPI32.@]
1762 * See RegEnumValueW.
1764 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1765 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1767 NTSTATUS status;
1768 DWORD total_size;
1769 char buffer[256], *buf_ptr = buffer;
1770 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1771 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1773 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1774 hkey, index, value, val_count, reserved, type, data, count );
1776 /* NT only checks count, not val_count */
1777 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1778 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1780 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1781 if (data) total_size += *count;
1782 total_size = min( sizeof(buffer), total_size );
1784 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1785 buffer, total_size, &total_size );
1786 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1788 /* we need to fetch the contents for a string type even if not requested,
1789 * because we need to compute the length of the ASCII string. */
1790 if (value || data || is_string(info->Type))
1792 /* retry with a dynamically allocated buffer */
1793 while (status == STATUS_BUFFER_OVERFLOW)
1795 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1796 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1797 return ERROR_NOT_ENOUGH_MEMORY;
1798 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1799 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1800 buf_ptr, total_size, &total_size );
1803 if (status) goto done;
1805 if (is_string(info->Type))
1807 DWORD len;
1808 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1809 total_size - info->DataOffset );
1810 if (data && len)
1812 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1813 else
1815 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1816 total_size - info->DataOffset );
1817 /* if the type is REG_SZ and data is not 0-terminated
1818 * and there is enough space in the buffer NT appends a \0 */
1819 if (len < *count && data[len-1]) data[len] = 0;
1822 info->DataLength = len;
1824 else if (data)
1826 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1827 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1830 if (value && !status)
1832 DWORD len;
1834 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1835 if (len >= *val_count)
1837 status = STATUS_BUFFER_OVERFLOW;
1838 if (*val_count)
1840 len = *val_count - 1;
1841 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1842 value[len] = 0;
1845 else
1847 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1848 value[len] = 0;
1849 *val_count = len;
1853 else status = STATUS_SUCCESS;
1855 if (type) *type = info->Type;
1856 if (count) *count = info->DataLength;
1858 done:
1859 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1860 return RtlNtStatusToDosError(status);
1865 /******************************************************************************
1866 * RegDeleteValueW [ADVAPI32.@]
1868 * See RegDeleteValueA.
1870 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1872 UNICODE_STRING nameW;
1874 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1876 RtlInitUnicodeString( &nameW, name );
1877 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1881 /******************************************************************************
1882 * RegDeleteValueA [ADVAPI32.@]
1884 * Delete a value from the registry.
1886 * PARAMS
1887 * hkey [I] Registry handle of the key holding the value
1888 * name [I] Name of the value under hkey to delete
1890 * RETURNS
1891 * Success: ERROR_SUCCESS
1892 * Failure: nonzero error code from Winerror.h
1894 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1896 STRING nameA;
1897 NTSTATUS status;
1899 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1901 RtlInitAnsiString( &nameA, name );
1902 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1903 &nameA, FALSE )))
1904 status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1905 return RtlNtStatusToDosError( status );
1909 /******************************************************************************
1910 * RegLoadKeyW [ADVAPI32.@]
1912 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1913 * registration information from a specified file into that subkey.
1915 * PARAMS
1916 * hkey [I] Handle of open key
1917 * subkey [I] Address of name of subkey
1918 * filename [I] Address of filename for registry information
1920 * RETURNS
1921 * Success: ERROR_SUCCESS
1922 * Failure: nonzero error code from Winerror.h
1924 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1926 OBJECT_ATTRIBUTES destkey, file;
1927 UNICODE_STRING subkeyW, filenameW;
1928 NTSTATUS status;
1930 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
1932 destkey.Length = sizeof(destkey);
1933 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
1934 destkey.ObjectName = &subkeyW; /* name of the key */
1935 destkey.Attributes = 0;
1936 destkey.SecurityDescriptor = NULL;
1937 destkey.SecurityQualityOfService = NULL;
1938 RtlInitUnicodeString(&subkeyW, subkey);
1940 file.Length = sizeof(file);
1941 file.RootDirectory = NULL;
1942 file.ObjectName = &filenameW; /* file containing the hive */
1943 file.Attributes = OBJ_CASE_INSENSITIVE;
1944 file.SecurityDescriptor = NULL;
1945 file.SecurityQualityOfService = NULL;
1946 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
1948 status = NtLoadKey(&destkey, &file);
1949 RtlFreeUnicodeString(&filenameW);
1950 return RtlNtStatusToDosError( status );
1954 /******************************************************************************
1955 * RegLoadKeyA [ADVAPI32.@]
1957 * See RegLoadKeyW.
1959 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1961 UNICODE_STRING subkeyW, filenameW;
1962 STRING subkeyA, filenameA;
1963 NTSTATUS status;
1964 LONG ret;
1966 RtlInitAnsiString(&subkeyA, subkey);
1967 RtlInitAnsiString(&filenameA, filename);
1969 RtlInitUnicodeString(&subkeyW, NULL);
1970 RtlInitUnicodeString(&filenameW, NULL);
1971 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
1972 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
1974 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
1976 else ret = RtlNtStatusToDosError(status);
1977 RtlFreeUnicodeString(&subkeyW);
1978 RtlFreeUnicodeString(&filenameW);
1979 return ret;
1983 /******************************************************************************
1984 * RegSaveKeyW [ADVAPI32.@]
1986 * Save a key and all of its subkeys and values to a new file in the standard format.
1988 * PARAMS
1989 * hkey [I] Handle of key where save begins
1990 * lpFile [I] Address of filename to save to
1991 * sa [I] Address of security structure
1993 * RETURNS
1994 * Success: ERROR_SUCCESS
1995 * Failure: nonzero error code from Winerror.h
1997 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1999 static const WCHAR format[] =
2000 {'r','e','g','%','0','4','x','.','t','m','p',0};
2001 WCHAR buffer[MAX_PATH];
2002 int count = 0;
2003 LPWSTR nameW;
2004 DWORD ret, err;
2005 HANDLE handle;
2007 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2009 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2010 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2012 err = GetLastError();
2013 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2015 for (;;)
2017 snprintfW( nameW, 16, format, count++ );
2018 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2019 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2020 if (handle != INVALID_HANDLE_VALUE) break;
2021 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2023 /* Something gone haywire ? Please report if this happens abnormally */
2024 if (count >= 100)
2025 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);
2028 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2030 CloseHandle( handle );
2031 if (!ret)
2033 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2035 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2036 debugstr_w(file) );
2037 ret = GetLastError();
2040 if (ret) DeleteFileW( buffer );
2042 done:
2043 SetLastError( err ); /* restore last error code */
2044 return ret;
2048 /******************************************************************************
2049 * RegSaveKeyA [ADVAPI32.@]
2051 * See RegSaveKeyW.
2053 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2055 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2056 NTSTATUS status;
2057 STRING fileA;
2059 RtlInitAnsiString(&fileA, file);
2060 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2061 return RtlNtStatusToDosError( status );
2062 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2066 /******************************************************************************
2067 * RegRestoreKeyW [ADVAPI32.@]
2069 * Read the registry information from a file and copy it over a key.
2071 * PARAMS
2072 * hkey [I] Handle of key where restore begins
2073 * lpFile [I] Address of filename containing saved tree
2074 * dwFlags [I] Optional flags
2076 * RETURNS
2077 * Success: ERROR_SUCCESS
2078 * Failure: nonzero error code from Winerror.h
2080 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2082 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2084 /* It seems to do this check before the hkey check */
2085 if (!lpFile || !*lpFile)
2086 return ERROR_INVALID_PARAMETER;
2088 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2090 /* Check for file existence */
2092 return ERROR_SUCCESS;
2096 /******************************************************************************
2097 * RegRestoreKeyA [ADVAPI32.@]
2099 * See RegRestoreKeyW.
2101 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2103 UNICODE_STRING lpFileW;
2104 LONG ret;
2106 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2107 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2108 RtlFreeUnicodeString( &lpFileW );
2109 return ret;
2113 /******************************************************************************
2114 * RegUnLoadKeyW [ADVAPI32.@]
2116 * Unload a registry key and its subkeys from the registry.
2118 * PARAMS
2119 * hkey [I] Handle of open key
2120 * lpSubKey [I] Address of name of subkey to unload
2122 * RETURNS
2123 * Success: ERROR_SUCCESS
2124 * Failure: nonzero error code from Winerror.h
2126 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2128 DWORD ret;
2129 HKEY shkey;
2130 OBJECT_ATTRIBUTES attr;
2131 UNICODE_STRING subkey;
2133 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2135 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2136 if( ret )
2137 return ERROR_INVALID_PARAMETER;
2139 RtlInitUnicodeString(&subkey, lpSubKey);
2140 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2141 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2143 RegCloseKey(shkey);
2145 return ret;
2149 /******************************************************************************
2150 * RegUnLoadKeyA [ADVAPI32.@]
2152 * See RegUnLoadKeyW.
2154 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2156 UNICODE_STRING lpSubKeyW;
2157 LONG ret;
2159 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2160 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2161 RtlFreeUnicodeString( &lpSubKeyW );
2162 return ret;
2166 /******************************************************************************
2167 * RegReplaceKeyW [ADVAPI32.@]
2169 * Replace the file backing a registry key and all its subkeys with another file.
2171 * PARAMS
2172 * hkey [I] Handle of open key
2173 * lpSubKey [I] Address of name of subkey
2174 * lpNewFile [I] Address of filename for file with new data
2175 * lpOldFile [I] Address of filename for backup file
2177 * RETURNS
2178 * Success: ERROR_SUCCESS
2179 * Failure: nonzero error code from Winerror.h
2181 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2182 LPCWSTR lpOldFile )
2184 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2185 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2186 return ERROR_SUCCESS;
2190 /******************************************************************************
2191 * RegReplaceKeyA [ADVAPI32.@]
2193 * See RegReplaceKeyW.
2195 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2196 LPCSTR lpOldFile )
2198 UNICODE_STRING lpSubKeyW;
2199 UNICODE_STRING lpNewFileW;
2200 UNICODE_STRING lpOldFileW;
2201 LONG ret;
2203 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2204 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2205 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2206 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2207 RtlFreeUnicodeString( &lpOldFileW );
2208 RtlFreeUnicodeString( &lpNewFileW );
2209 RtlFreeUnicodeString( &lpSubKeyW );
2210 return ret;
2214 /******************************************************************************
2215 * RegSetKeySecurity [ADVAPI32.@]
2217 * Set the security of an open registry key.
2219 * PARAMS
2220 * hkey [I] Open handle of key to set
2221 * SecurityInfo [I] Descriptor contents
2222 * pSecurityDesc [I] Address of descriptor for key
2224 * RETURNS
2225 * Success: ERROR_SUCCESS
2226 * Failure: nonzero error code from Winerror.h
2228 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2229 PSECURITY_DESCRIPTOR pSecurityDesc )
2231 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2233 /* It seems to perform this check before the hkey check */
2234 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2235 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2236 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2237 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2238 /* Param OK */
2239 } else
2240 return ERROR_INVALID_PARAMETER;
2242 if (!pSecurityDesc)
2243 return ERROR_INVALID_PARAMETER;
2245 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2247 return ERROR_SUCCESS;
2251 /******************************************************************************
2252 * RegGetKeySecurity [ADVAPI32.@]
2254 * Get a copy of the security descriptor for a given registry key.
2256 * PARAMS
2257 * hkey [I] Open handle of key to set
2258 * SecurityInformation [I] Descriptor contents
2259 * pSecurityDescriptor [O] Address of descriptor for key
2260 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2262 * RETURNS
2263 * Success: ERROR_SUCCESS
2264 * Failure: Error code
2266 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2267 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2268 LPDWORD lpcbSecurityDescriptor )
2270 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2271 *lpcbSecurityDescriptor);
2273 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2275 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2276 SecurityInformation, pSecurityDescriptor,
2277 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2281 /******************************************************************************
2282 * RegFlushKey [ADVAPI32.@]
2284 * Immediately write a registry key to registry.
2286 * PARAMS
2287 * hkey [I] Handle of key to write
2289 * RETURNS
2290 * Success: ERROR_SUCCESS
2291 * Failure: Error code
2293 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2295 hkey = get_special_root_hkey( hkey );
2296 if (!hkey) return ERROR_INVALID_HANDLE;
2298 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2302 /******************************************************************************
2303 * RegConnectRegistryW [ADVAPI32.@]
2305 * Establish a connection to a predefined registry key on another computer.
2307 * PARAMS
2308 * lpMachineName [I] Address of name of remote computer
2309 * hHey [I] Predefined registry handle
2310 * phkResult [I] Address of buffer for remote registry handle
2312 * RETURNS
2313 * Success: ERROR_SUCCESS
2314 * Failure: nonzero error code from Winerror.h
2316 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2317 PHKEY phkResult )
2319 LONG ret;
2321 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2323 if (!lpMachineName || !*lpMachineName) {
2324 /* Use the local machine name */
2325 ret = RegOpenKeyW( hKey, NULL, phkResult );
2327 else {
2328 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2329 DWORD len = sizeof(compName) / sizeof(WCHAR);
2331 /* MSDN says lpMachineName must start with \\ : not so */
2332 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2333 lpMachineName += 2;
2334 if (GetComputerNameW(compName, &len))
2336 if (!strcmpiW(lpMachineName, compName))
2337 ret = RegOpenKeyW(hKey, NULL, phkResult);
2338 else
2340 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2341 ret = ERROR_BAD_NETPATH;
2344 else
2345 ret = GetLastError();
2347 return ret;
2351 /******************************************************************************
2352 * RegConnectRegistryA [ADVAPI32.@]
2354 * See RegConnectRegistryW.
2356 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2358 UNICODE_STRING machineW;
2359 LONG ret;
2361 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2362 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2363 RtlFreeUnicodeString( &machineW );
2364 return ret;
2368 /******************************************************************************
2369 * RegNotifyChangeKeyValue [ADVAPI32.@]
2371 * Notify the caller about changes to the attributes or contents of a registry key.
2373 * PARAMS
2374 * hkey [I] Handle of key to watch
2375 * fWatchSubTree [I] Flag for subkey notification
2376 * fdwNotifyFilter [I] Changes to be reported
2377 * hEvent [I] Handle of signaled event
2378 * fAsync [I] Flag for asynchronous reporting
2380 * RETURNS
2381 * Success: ERROR_SUCCESS
2382 * Failure: nonzero error code from Winerror.h
2384 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2385 DWORD fdwNotifyFilter, HANDLE hEvent,
2386 BOOL fAsync )
2388 NTSTATUS status;
2389 IO_STATUS_BLOCK iosb;
2391 hkey = get_special_root_hkey( hkey );
2392 if (!hkey) return ERROR_INVALID_HANDLE;
2394 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2395 hEvent, fAsync);
2397 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2398 fdwNotifyFilter, fAsync, NULL, 0,
2399 fWatchSubTree);
2401 if (status && status != STATUS_TIMEOUT)
2402 return RtlNtStatusToDosError( status );
2404 return ERROR_SUCCESS;
2407 /******************************************************************************
2408 * RegOpenUserClassesRoot [ADVAPI32.@]
2410 * Open the HKEY_CLASSES_ROOT key for a user.
2412 * PARAMS
2413 * hToken [I] Handle of token representing the user
2414 * dwOptions [I] Reserved, must be 0
2415 * samDesired [I] Desired access rights
2416 * phkResult [O] Destination for the resulting key handle
2418 * RETURNS
2419 * Success: ERROR_SUCCESS
2420 * Failure: nonzero error code from Winerror.h
2422 * NOTES
2423 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2424 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2425 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2427 LSTATUS WINAPI RegOpenUserClassesRoot(
2428 HANDLE hToken,
2429 DWORD dwOptions,
2430 REGSAM samDesired,
2431 PHKEY phkResult
2434 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2436 *phkResult = HKEY_CLASSES_ROOT;
2437 return ERROR_SUCCESS;
2440 /******************************************************************************
2441 * load_string [Internal]
2443 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2444 * avoid importing user32, which is higher level than advapi32. Helper for
2445 * RegLoadMUIString.
2447 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2449 HGLOBAL hMemory;
2450 HRSRC hResource;
2451 WCHAR *pString;
2452 int idxString;
2454 /* Negative values have to be inverted. */
2455 if (HIWORD(resId) == 0xffff)
2456 resId = (UINT)(-((INT)resId));
2458 /* Load the resource into memory and get a pointer to it. */
2459 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2460 if (!hResource) return 0;
2461 hMemory = LoadResource(hModule, hResource);
2462 if (!hMemory) return 0;
2463 pString = LockResource(hMemory);
2465 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2466 idxString = resId & 0xf;
2467 while (idxString--) pString += *pString + 1;
2469 /* If no buffer is given, return length of the string. */
2470 if (!pwszBuffer) return *pString;
2472 /* Else copy over the string, respecting the buffer size. */
2473 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2474 if (cMaxChars >= 0) {
2475 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2476 pwszBuffer[cMaxChars] = '\0';
2479 return cMaxChars;
2482 /******************************************************************************
2483 * RegLoadMUIStringW [ADVAPI32.@]
2485 * Load the localized version of a string resource from some PE, respective
2486 * id and path of which are given in the registry value in the format
2487 * @[path]\dllname,-resourceId
2489 * PARAMS
2490 * hKey [I] Key, of which to load the string value from.
2491 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2492 * pszBuffer [O] Buffer to store the localized string in.
2493 * cbBuffer [I] Size of the destination buffer in bytes.
2494 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2495 * dwFlags [I] None supported yet.
2496 * pszBaseDir [I] Not supported yet.
2498 * RETURNS
2499 * Success: ERROR_SUCCESS,
2500 * Failure: nonzero error code from winerror.h
2502 * NOTES
2503 * This is an API of Windows Vista, which wasn't available at the time this code
2504 * was written. We have to check for the correct behaviour once it's available.
2506 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2507 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2509 DWORD dwValueType, cbData;
2510 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2511 LONG result;
2513 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2514 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2515 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2517 /* Parameter sanity checks. */
2518 if (!hKey || !pwszBuffer)
2519 return ERROR_INVALID_PARAMETER;
2521 if (pwszBaseDir && *pwszBaseDir) {
2522 FIXME("BaseDir parameter not yet supported!\n");
2523 return ERROR_INVALID_PARAMETER;
2526 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2527 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2528 if (result != ERROR_SUCCESS) goto cleanup;
2529 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2530 result = ERROR_FILE_NOT_FOUND;
2531 goto cleanup;
2533 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2534 if (!pwszTempBuffer) {
2535 result = ERROR_NOT_ENOUGH_MEMORY;
2536 goto cleanup;
2538 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2539 if (result != ERROR_SUCCESS) goto cleanup;
2541 /* Expand environment variables, if appropriate, or copy the original string over. */
2542 if (dwValueType == REG_EXPAND_SZ) {
2543 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2544 if (!cbData) goto cleanup;
2545 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2546 if (!pwszExpandedBuffer) {
2547 result = ERROR_NOT_ENOUGH_MEMORY;
2548 goto cleanup;
2550 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2551 } else {
2552 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2553 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2556 /* If the value references a resource based string, parse the value and load the string.
2557 * Else just copy over the original value. */
2558 result = ERROR_SUCCESS;
2559 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2560 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2561 } else {
2562 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2563 UINT uiStringId;
2564 HMODULE hModule;
2566 /* Format of the expanded value is 'path_to_dll,-resId' */
2567 if (!pComma || pComma[1] != '-') {
2568 result = ERROR_BADKEY;
2569 goto cleanup;
2572 uiStringId = atoiW(pComma+2);
2573 *pComma = '\0';
2575 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2576 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2577 result = ERROR_BADKEY;
2578 FreeLibrary(hModule);
2581 cleanup:
2582 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2583 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2584 return result;
2587 /******************************************************************************
2588 * RegLoadMUIStringA [ADVAPI32.@]
2590 * See RegLoadMUIStringW
2592 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2593 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2595 UNICODE_STRING valueW, baseDirW;
2596 WCHAR *pwszBuffer;
2597 DWORD cbData = cbBuffer * sizeof(WCHAR);
2598 LONG result;
2600 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2601 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2602 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2603 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2605 result = ERROR_NOT_ENOUGH_MEMORY;
2606 goto cleanup;
2609 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2610 baseDirW.Buffer);
2612 if (result == ERROR_SUCCESS) {
2613 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2614 if (pcbData)
2615 *pcbData = cbData;
2618 cleanup:
2619 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2620 RtlFreeUnicodeString(&baseDirW);
2621 RtlFreeUnicodeString(&valueW);
2623 return result;
2626 /******************************************************************************
2627 * RegDisablePredefinedCache [ADVAPI32.@]
2629 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2631 * PARAMS
2632 * None.
2634 * RETURNS
2635 * Success: ERROR_SUCCESS
2636 * Failure: nonzero error code from Winerror.h
2638 * NOTES
2639 * This is useful for services that use impersonation.
2641 LSTATUS WINAPI RegDisablePredefinedCache(void)
2643 HKEY hkey_current_user;
2644 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2646 /* prevent caching of future requests */
2647 hkcu_cache_disabled = TRUE;
2649 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2651 if (hkey_current_user)
2652 NtClose( hkey_current_user );
2654 return ERROR_SUCCESS;
2657 /******************************************************************************
2658 * RegDeleteTreeW [ADVAPI32.@]
2661 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2663 LONG ret;
2664 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2665 DWORD dwMaxLen, dwSize;
2666 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2667 HKEY hSubKey = hKey;
2669 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2671 if(lpszSubKey)
2673 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2674 if (ret) return ret;
2677 /* Get highest length for keys, values */
2678 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2679 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2680 if (ret) goto cleanup;
2682 dwMaxSubkeyLen++;
2683 dwMaxValueLen++;
2684 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2685 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2687 /* Name too big: alloc a buffer for it */
2688 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2690 ret = ERROR_NOT_ENOUGH_MEMORY;
2691 goto cleanup;
2696 /* Recursively delete all the subkeys */
2697 while (TRUE)
2699 dwSize = dwMaxLen;
2700 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2701 NULL, NULL, NULL)) break;
2703 ret = RegDeleteTreeW(hSubKey, lpszName);
2704 if (ret) goto cleanup;
2707 if (lpszSubKey)
2708 ret = RegDeleteKeyW(hKey, lpszSubKey);
2709 else
2710 while (TRUE)
2712 dwSize = dwMaxLen;
2713 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2714 NULL, NULL, NULL, NULL)) break;
2716 ret = RegDeleteValueW(hKey, lpszName);
2717 if (ret) goto cleanup;
2720 cleanup:
2721 /* Free buffer if allocated */
2722 if (lpszName != szNameBuf)
2723 HeapFree( GetProcessHeap(), 0, lpszName);
2724 if(lpszSubKey)
2725 RegCloseKey(hSubKey);
2726 return ret;
2729 /******************************************************************************
2730 * RegDeleteTreeA [ADVAPI32.@]
2733 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2735 LONG ret;
2736 UNICODE_STRING lpszSubKeyW;
2738 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2739 else lpszSubKeyW.Buffer = NULL;
2740 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2741 RtlFreeUnicodeString( &lpszSubKeyW );
2742 return ret;