comctl32/tests: Run tests again on Win95.
[wine/multimedia.git] / dlls / advapi32 / registry.c
blob4c97ed1338cae332009bc06c9f56b5526db49605
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 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
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38 #include "winerror.h"
39 #include "winternl.h"
40 #include "winuser.h"
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(reg);
47 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
48 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
49 #define NB_SPECIAL_ROOT_KEYS ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
51 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
52 static BOOL hkcu_cache_disabled;
54 static const WCHAR name_CLASSES_ROOT[] =
55 {'M','a','c','h','i','n','e','\\',
56 'S','o','f','t','w','a','r','e','\\',
57 'C','l','a','s','s','e','s',0};
58 static const WCHAR name_LOCAL_MACHINE[] =
59 {'M','a','c','h','i','n','e',0};
60 static const WCHAR name_USERS[] =
61 {'U','s','e','r',0};
62 static const WCHAR name_PERFORMANCE_DATA[] =
63 {'P','e','r','f','D','a','t','a',0};
64 static const WCHAR name_CURRENT_CONFIG[] =
65 {'M','a','c','h','i','n','e','\\',
66 'S','y','s','t','e','m','\\',
67 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
68 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
69 'C','u','r','r','e','n','t',0};
70 static const WCHAR name_DYN_DATA[] =
71 {'D','y','n','D','a','t','a',0};
73 static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] =
75 name_CLASSES_ROOT,
76 NULL, /* HKEY_CURRENT_USER is determined dynamically */
77 name_LOCAL_MACHINE,
78 name_USERS,
79 name_PERFORMANCE_DATA,
80 name_CURRENT_CONFIG,
81 name_DYN_DATA
85 /* check if value type needs string conversion (Ansi<->Unicode) */
86 static inline int is_string( DWORD type )
88 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
91 /* check if current version is NT or Win95 */
92 static inline int is_version_nt(void)
94 return !(GetVersion() & 0x80000000);
97 /* create one of the HKEY_* special root keys */
98 static HKEY create_special_root_hkey( HANDLE hkey, DWORD access )
100 HKEY ret = 0;
101 int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
103 if (hkey == HKEY_CURRENT_USER)
105 if (RtlOpenCurrentUser( access, &hkey )) return 0;
106 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
108 /* don't cache the key in the table if caching is disabled */
109 if (hkcu_cache_disabled)
110 return hkey;
112 else
114 OBJECT_ATTRIBUTES attr;
115 UNICODE_STRING name;
117 attr.Length = sizeof(attr);
118 attr.RootDirectory = 0;
119 attr.ObjectName = &name;
120 attr.Attributes = 0;
121 attr.SecurityDescriptor = NULL;
122 attr.SecurityQualityOfService = NULL;
123 RtlInitUnicodeString( &name, root_key_names[idx] );
124 if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
125 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
128 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
129 ret = hkey;
130 else
131 NtClose( hkey ); /* somebody beat us to it */
132 return ret;
135 /* map the hkey from special root to normal key if necessary */
136 static inline HKEY get_special_root_hkey( HKEY hkey )
138 HKEY ret = hkey;
140 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
142 if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
143 ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
145 return ret;
149 /******************************************************************************
150 * RegOverridePredefKey [ADVAPI32.@]
152 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
154 HKEY old_key;
155 int idx;
157 if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST))
158 return ERROR_INVALID_PARAMETER;
159 idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
161 if (override)
163 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
164 GetCurrentProcess(), (HANDLE *)&override,
165 0, 0, DUPLICATE_SAME_ACCESS );
166 if (status) return RtlNtStatusToDosError( status );
169 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
170 if (old_key) NtClose( old_key );
171 return ERROR_SUCCESS;
175 /******************************************************************************
176 * RegCreateKeyExW [ADVAPI32.@]
178 * See RegCreateKeyExA.
180 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
181 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
182 PHKEY retkey, LPDWORD dispos )
184 OBJECT_ATTRIBUTES attr;
185 UNICODE_STRING nameW, classW;
187 if (reserved) return ERROR_INVALID_PARAMETER;
188 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
190 attr.Length = sizeof(attr);
191 attr.RootDirectory = hkey;
192 attr.ObjectName = &nameW;
193 attr.Attributes = 0;
194 attr.SecurityDescriptor = NULL;
195 attr.SecurityQualityOfService = NULL;
196 RtlInitUnicodeString( &nameW, name );
197 RtlInitUnicodeString( &classW, class );
199 return RtlNtStatusToDosError( NtCreateKey( (PHANDLE)retkey, access, &attr, 0,
200 &classW, options, dispos ) );
204 /******************************************************************************
205 * RegCreateKeyExA [ADVAPI32.@]
207 * Open a registry key, creating it if it doesn't exist.
209 * PARAMS
210 * hkey [I] Handle of the parent registry key
211 * name [I] Name of the new key to open or create
212 * reserved [I] Reserved, pass 0
213 * class [I] The object type of the new key
214 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
215 * access [I] Access level desired
216 * sa [I] Security attributes for the key
217 * retkey [O] Destination for the resulting handle
218 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
220 * RETURNS
221 * Success: ERROR_SUCCESS.
222 * Failure: A standard Win32 error code. retkey remains untouched.
224 * FIXME
225 * MAXIMUM_ALLOWED in access mask not supported by server
227 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
228 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
229 PHKEY retkey, LPDWORD dispos )
231 OBJECT_ATTRIBUTES attr;
232 UNICODE_STRING classW;
233 ANSI_STRING nameA, classA;
234 NTSTATUS status;
236 if (reserved) return ERROR_INVALID_PARAMETER;
237 if (!is_version_nt())
239 access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
240 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
242 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
244 attr.Length = sizeof(attr);
245 attr.RootDirectory = hkey;
246 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
247 attr.Attributes = 0;
248 attr.SecurityDescriptor = NULL;
249 attr.SecurityQualityOfService = NULL;
250 RtlInitAnsiString( &nameA, name );
251 RtlInitAnsiString( &classA, class );
253 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
254 &nameA, FALSE )))
256 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
258 status = NtCreateKey( (PHANDLE)retkey, access, &attr, 0, &classW, options, dispos );
259 RtlFreeUnicodeString( &classW );
262 return RtlNtStatusToDosError( status );
266 /******************************************************************************
267 * RegCreateKeyW [ADVAPI32.@]
269 * Creates the specified reg key.
271 * PARAMS
272 * hKey [I] Handle to an open key.
273 * lpSubKey [I] Name of a key that will be opened or created.
274 * phkResult [O] Receives a handle to the opened or created key.
276 * RETURNS
277 * Success: ERROR_SUCCESS
278 * Failure: nonzero error code defined in Winerror.h
280 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
282 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
283 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
284 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
285 KEY_ALL_ACCESS, NULL, phkResult, NULL );
289 /******************************************************************************
290 * RegCreateKeyA [ADVAPI32.@]
292 * See RegCreateKeyW.
294 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
296 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
297 KEY_ALL_ACCESS, NULL, phkResult, NULL );
302 /******************************************************************************
303 * RegOpenKeyExW [ADVAPI32.@]
305 * See RegOpenKeyExA.
307 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
309 OBJECT_ATTRIBUTES attr;
310 UNICODE_STRING nameW;
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 */
353 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
355 attr.Length = sizeof(attr);
356 attr.RootDirectory = hkey;
357 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
358 attr.Attributes = 0;
359 attr.SecurityDescriptor = NULL;
360 attr.SecurityQualityOfService = NULL;
362 RtlInitAnsiString( &nameA, name );
363 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
364 &nameA, FALSE )))
366 status = NtOpenKey( (PHANDLE)retkey, access, &attr );
368 return RtlNtStatusToDosError( status );
372 /******************************************************************************
373 * RegOpenKeyW [ADVAPI32.@]
375 * See RegOpenKeyA.
377 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
379 if (!name || !*name)
381 *retkey = hkey;
382 return ERROR_SUCCESS;
384 return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
388 /******************************************************************************
389 * RegOpenKeyA [ADVAPI32.@]
391 * Open a registry key.
393 * PARAMS
394 * hkey [I] Handle of parent key to open the new key under
395 * name [I] Name of the key under hkey to open
396 * retkey [O] Destination for the resulting Handle
398 * RETURNS
399 * Success: ERROR_SUCCESS
400 * Failure: A standard Win32 error code. retkey is set to 0.
402 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
404 if (!name || !*name)
406 *retkey = hkey;
407 return ERROR_SUCCESS;
409 return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
413 /******************************************************************************
414 * RegOpenCurrentUser [ADVAPI32.@]
416 * Get a handle to the HKEY_CURRENT_USER key for the user
417 * the current thread is impersonating.
419 * PARAMS
420 * access [I] Desired access rights to the key
421 * retkey [O] Handle to the opened key
423 * RETURNS
424 * Success: ERROR_SUCCESS
425 * Failure: nonzero error code from Winerror.h
427 * FIXME
428 * This function is supposed to retrieve a handle to the
429 * HKEY_CURRENT_USER for the user the current thread is impersonating.
430 * Since Wine does not currently allow threads to impersonate other users,
431 * this stub should work fine.
433 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
435 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
440 /******************************************************************************
441 * RegEnumKeyExW [ADVAPI32.@]
443 * Enumerate subkeys of the specified open registry key.
445 * PARAMS
446 * hkey [I] Handle to key to enumerate
447 * index [I] Index of subkey to enumerate
448 * name [O] Buffer for subkey name
449 * name_len [O] Size of subkey buffer
450 * reserved [I] Reserved
451 * class [O] Buffer for class string
452 * class_len [O] Size of class buffer
453 * ft [O] Time key last written to
455 * RETURNS
456 * Success: ERROR_SUCCESS
457 * Failure: System error code. If there are no more subkeys available, the
458 * function returns ERROR_NO_MORE_ITEMS.
460 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
461 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
463 NTSTATUS status;
464 char buffer[256], *buf_ptr = buffer;
465 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
466 DWORD total_size;
468 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
469 name_len ? *name_len : 0, reserved, class, class_len, ft );
471 if (reserved) return ERROR_INVALID_PARAMETER;
472 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
474 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
475 buffer, sizeof(buffer), &total_size );
477 while (status == STATUS_BUFFER_OVERFLOW)
479 /* retry with a dynamically allocated buffer */
480 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
481 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
482 return ERROR_NOT_ENOUGH_MEMORY;
483 info = (KEY_NODE_INFORMATION *)buf_ptr;
484 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
485 buf_ptr, total_size, &total_size );
488 if (!status)
490 DWORD len = info->NameLength / sizeof(WCHAR);
491 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
493 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
495 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
496 status = STATUS_BUFFER_OVERFLOW;
497 else
499 *name_len = len;
500 memcpy( name, info->Name, info->NameLength );
501 name[len] = 0;
502 if (class_len)
504 *class_len = cls_len;
505 if (class)
507 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
508 class[cls_len] = 0;
514 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
515 return RtlNtStatusToDosError( status );
519 /******************************************************************************
520 * RegEnumKeyExA [ADVAPI32.@]
522 * See RegEnumKeyExW.
524 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
525 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
527 NTSTATUS status;
528 char buffer[256], *buf_ptr = buffer;
529 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
530 DWORD total_size;
532 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
533 name_len ? *name_len : 0, reserved, class, class_len, ft );
535 if (reserved) return ERROR_INVALID_PARAMETER;
536 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
538 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
539 buffer, sizeof(buffer), &total_size );
541 while (status == STATUS_BUFFER_OVERFLOW)
543 /* retry with a dynamically allocated buffer */
544 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
545 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
546 return ERROR_NOT_ENOUGH_MEMORY;
547 info = (KEY_NODE_INFORMATION *)buf_ptr;
548 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
549 buf_ptr, total_size, &total_size );
552 if (!status)
554 DWORD len, cls_len;
556 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
557 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
558 info->ClassLength );
559 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
561 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
562 status = STATUS_BUFFER_OVERFLOW;
563 else
565 *name_len = len;
566 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
567 name[len] = 0;
568 if (class_len)
570 *class_len = cls_len;
571 if (class)
573 RtlUnicodeToMultiByteN( class, cls_len, NULL,
574 (WCHAR *)(buf_ptr + info->ClassOffset),
575 info->ClassLength );
576 class[cls_len] = 0;
582 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
583 return RtlNtStatusToDosError( status );
587 /******************************************************************************
588 * RegEnumKeyW [ADVAPI32.@]
590 * Enumerates subkeys of the specified open reg key.
592 * PARAMS
593 * hKey [I] Handle to an open key.
594 * dwIndex [I] Index of the subkey of hKey to retrieve.
595 * lpName [O] Name of the subkey.
596 * cchName [I] Size of lpName in TCHARS.
598 * RETURNS
599 * Success: ERROR_SUCCESS
600 * Failure: system error code. If there are no more subkeys available, the
601 * function returns ERROR_NO_MORE_ITEMS.
603 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
605 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
609 /******************************************************************************
610 * RegEnumKeyA [ADVAPI32.@]
612 * See RegEnumKeyW.
614 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
616 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
620 /******************************************************************************
621 * RegQueryInfoKeyW [ADVAPI32.@]
623 * Retrieves information about the specified registry key.
625 * PARAMS
626 * hkey [I] Handle to key to query
627 * class [O] Buffer for class string
628 * class_len [O] Size of class string buffer
629 * reserved [I] Reserved
630 * subkeys [O] Buffer for number of subkeys
631 * max_subkey [O] Buffer for longest subkey name length
632 * max_class [O] Buffer for longest class string length
633 * values [O] Buffer for number of value entries
634 * max_value [O] Buffer for longest value name length
635 * max_data [O] Buffer for longest value data length
636 * security [O] Buffer for security descriptor length
637 * modif [O] Modification time
639 * RETURNS
640 * Success: ERROR_SUCCESS
641 * Failure: system error code.
643 * NOTES
644 * - win95 allows class to be valid and class_len to be NULL
645 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
646 * - both allow class to be NULL and class_len to be NULL
647 * (it's hard to test validity, so test !NULL instead)
649 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
650 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
651 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
652 LPDWORD security, FILETIME *modif )
654 NTSTATUS status;
655 char buffer[256], *buf_ptr = buffer;
656 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
657 DWORD total_size;
659 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
660 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
662 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
663 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
665 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
666 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
668 if (class)
670 /* retry with a dynamically allocated buffer */
671 while (status == STATUS_BUFFER_OVERFLOW)
673 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
674 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
675 return ERROR_NOT_ENOUGH_MEMORY;
676 info = (KEY_FULL_INFORMATION *)buf_ptr;
677 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
680 if (status) goto done;
682 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
684 status = STATUS_BUFFER_OVERFLOW;
686 else
688 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
689 class[info->ClassLength/sizeof(WCHAR)] = 0;
692 else status = STATUS_SUCCESS;
694 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
695 if (subkeys) *subkeys = info->SubKeys;
696 if (max_subkey) *max_subkey = info->MaxNameLen;
697 if (max_class) *max_class = info->MaxClassLen;
698 if (values) *values = info->Values;
699 if (max_value) *max_value = info->MaxValueNameLen;
700 if (max_data) *max_data = info->MaxValueDataLen;
701 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
703 done:
704 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
705 return RtlNtStatusToDosError( status );
709 /******************************************************************************
710 * RegQueryMultipleValuesA [ADVAPI32.@]
712 * Retrieves the type and data for a list of value names associated with a key.
714 * PARAMS
715 * hKey [I] Handle to an open key.
716 * val_list [O] Array of VALENT structures that describes the entries.
717 * num_vals [I] Number of elements in val_list.
718 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
719 * ldwTotsize [I/O] Size of lpValueBuf.
721 * RETURNS
722 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
723 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
724 * bytes.
726 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
727 LPSTR lpValueBuf, LPDWORD ldwTotsize )
729 unsigned int i;
730 DWORD maxBytes = *ldwTotsize;
731 HRESULT status;
732 LPSTR bufptr = lpValueBuf;
733 *ldwTotsize = 0;
735 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
737 for(i=0; i < num_vals; ++i)
740 val_list[i].ve_valuelen=0;
741 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
742 if(status != ERROR_SUCCESS)
744 return status;
747 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
749 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
750 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
751 if(status != ERROR_SUCCESS)
753 return status;
756 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
758 bufptr += val_list[i].ve_valuelen;
761 *ldwTotsize += val_list[i].ve_valuelen;
763 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
767 /******************************************************************************
768 * RegQueryMultipleValuesW [ADVAPI32.@]
770 * See RegQueryMultipleValuesA.
772 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
773 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
775 unsigned int i;
776 DWORD maxBytes = *ldwTotsize;
777 HRESULT status;
778 LPSTR bufptr = (LPSTR)lpValueBuf;
779 *ldwTotsize = 0;
781 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
783 for(i=0; i < num_vals; ++i)
785 val_list[i].ve_valuelen=0;
786 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
787 if(status != ERROR_SUCCESS)
789 return status;
792 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
794 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
795 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
796 if(status != ERROR_SUCCESS)
798 return status;
801 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
803 bufptr += val_list[i].ve_valuelen;
806 *ldwTotsize += val_list[i].ve_valuelen;
808 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
811 /******************************************************************************
812 * RegQueryInfoKeyA [ADVAPI32.@]
814 * Retrieves information about a registry key.
816 * PARAMS
817 * hKey [I] Handle to an open key.
818 * lpClass [O] Class string of the key.
819 * lpcClass [I/O] size of lpClass.
820 * lpReserved [I] Reserved; must be NULL.
821 * lpcSubKeys [O] Number of subkeys contained by the key.
822 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
823 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
824 * class in TCHARS.
825 * lpcValues [O] Number of values associated with the key.
826 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
827 * lpcMaxValueLen [O] Longest data component among the key's values
828 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
829 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
831 * RETURNS
832 * Success: ERROR_SUCCESS
833 * Failure: nonzero error code from Winerror.h
835 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
836 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
837 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
838 LPDWORD security, FILETIME *modif )
840 NTSTATUS status;
841 char buffer[256], *buf_ptr = buffer;
842 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
843 DWORD total_size, len;
845 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
846 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
848 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
849 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
851 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
852 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
854 if (class || class_len)
856 /* retry with a dynamically allocated buffer */
857 while (status == STATUS_BUFFER_OVERFLOW)
859 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
860 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
861 return ERROR_NOT_ENOUGH_MEMORY;
862 info = (KEY_FULL_INFORMATION *)buf_ptr;
863 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
866 if (status) goto done;
868 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
869 if (class_len)
871 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
872 *class_len = len;
874 if (class && !status)
876 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
877 info->ClassLength );
878 class[len] = 0;
881 else status = STATUS_SUCCESS;
883 if (subkeys) *subkeys = info->SubKeys;
884 if (max_subkey) *max_subkey = info->MaxNameLen;
885 if (max_class) *max_class = info->MaxClassLen;
886 if (values) *values = info->Values;
887 if (max_value) *max_value = info->MaxValueNameLen;
888 if (max_data) *max_data = info->MaxValueDataLen;
889 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
891 done:
892 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
893 return RtlNtStatusToDosError( status );
897 /******************************************************************************
898 * RegCloseKey [ADVAPI32.@]
900 * Close an open registry key.
902 * PARAMS
903 * hkey [I] Handle of key to close
905 * RETURNS
906 * Success: ERROR_SUCCESS
907 * Failure: Error code
909 LSTATUS WINAPI RegCloseKey( HKEY hkey )
911 if (!hkey) return ERROR_INVALID_HANDLE;
912 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
913 return RtlNtStatusToDosError( NtClose( hkey ) );
917 /******************************************************************************
918 * RegDeleteKeyW [ADVAPI32.@]
920 * See RegDeleteKeyA.
922 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
924 DWORD ret;
925 HKEY tmp;
927 if (!name) return ERROR_INVALID_PARAMETER;
929 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
931 if (!(ret = RegOpenKeyExW( hkey, name, 0, DELETE, &tmp )))
933 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
934 RegCloseKey( tmp );
936 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
937 return ret;
941 /******************************************************************************
942 * RegDeleteKeyA [ADVAPI32.@]
944 * Delete a registry key.
946 * PARAMS
947 * hkey [I] Handle to parent key containing the key to delete
948 * name [I] Name of the key user hkey to delete
950 * NOTES
952 * MSDN is wrong when it says that hkey must be opened with the DELETE access
953 * right. In reality, it opens a new handle with DELETE access.
955 * RETURNS
956 * Success: ERROR_SUCCESS
957 * Failure: Error code
959 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
961 DWORD ret;
962 HKEY tmp;
964 if (!name) return ERROR_INVALID_PARAMETER;
966 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
968 if (!(ret = RegOpenKeyExA( hkey, name, 0, DELETE, &tmp )))
970 if (!is_version_nt()) /* win95 does recursive key deletes */
972 CHAR name[MAX_PATH];
974 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
976 if(RegDeleteKeyA(tmp, name)) /* recurse */
977 break;
980 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
981 RegCloseKey( tmp );
983 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
984 return ret;
989 /******************************************************************************
990 * RegSetValueExW [ADVAPI32.@]
992 * Set the data and contents of a registry value.
994 * PARAMS
995 * hkey [I] Handle of key to set value for
996 * name [I] Name of value to set
997 * reserved [I] Reserved, must be zero
998 * type [I] Type of the value being set
999 * data [I] The new contents of the value to set
1000 * count [I] Size of data
1002 * RETURNS
1003 * Success: ERROR_SUCCESS
1004 * Failure: Error code
1006 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1007 DWORD type, CONST BYTE *data, DWORD count )
1009 UNICODE_STRING nameW;
1011 /* no need for version check, not implemented on win9x anyway */
1012 if (count && is_string(type))
1014 LPCWSTR str = (LPCWSTR)data;
1015 /* if user forgot to count terminating null, add it (yes NT does this) */
1016 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1017 count += sizeof(WCHAR);
1019 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1021 RtlInitUnicodeString( &nameW, name );
1022 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1026 /******************************************************************************
1027 * RegSetValueExA [ADVAPI32.@]
1029 * See RegSetValueExW.
1031 * NOTES
1032 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1033 * NT does definitely care (aj)
1035 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1036 CONST BYTE *data, DWORD count )
1038 ANSI_STRING nameA;
1039 WCHAR *dataW = NULL;
1040 NTSTATUS status;
1042 if (!is_version_nt()) /* win95 */
1044 if (type == REG_SZ)
1046 if (!data) return ERROR_INVALID_PARAMETER;
1047 count = strlen((const char *)data) + 1;
1050 else if (count && is_string(type))
1052 /* if user forgot to count terminating null, add it (yes NT does this) */
1053 if (data[count-1] && !data[count]) count++;
1056 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1058 if (is_string( type )) /* need to convert to Unicode */
1060 DWORD lenW;
1061 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1062 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1063 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1064 count = lenW;
1065 data = (BYTE *)dataW;
1068 RtlInitAnsiString( &nameA, name );
1069 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1070 &nameA, FALSE )))
1072 status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
1074 HeapFree( GetProcessHeap(), 0, dataW );
1075 return RtlNtStatusToDosError( status );
1079 /******************************************************************************
1080 * RegSetValueW [ADVAPI32.@]
1082 * Sets the data for the default or unnamed value of a reg key.
1084 * PARAMS
1085 * hKey [I] Handle to an open key.
1086 * lpSubKey [I] Name of a subkey of hKey.
1087 * dwType [I] Type of information to store.
1088 * lpData [I] String that contains the data to set for the default value.
1089 * cbData [I] Ignored.
1091 * RETURNS
1092 * Success: ERROR_SUCCESS
1093 * Failure: nonzero error code from Winerror.h
1095 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1097 HKEY subkey = hkey;
1098 DWORD ret;
1100 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1102 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1104 if (name && name[0]) /* need to create the subkey */
1106 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1109 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1110 (strlenW( data ) + 1) * sizeof(WCHAR) );
1111 if (subkey != hkey) RegCloseKey( subkey );
1112 return ret;
1116 /******************************************************************************
1117 * RegSetValueA [ADVAPI32.@]
1119 * See RegSetValueW.
1121 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1123 HKEY subkey = hkey;
1124 DWORD ret;
1126 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1128 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1130 if (name && name[0]) /* need to create the subkey */
1132 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1134 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1135 if (subkey != hkey) RegCloseKey( subkey );
1136 return ret;
1141 /******************************************************************************
1142 * RegQueryValueExW [ADVAPI32.@]
1144 * See RegQueryValueExA.
1146 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1147 LPBYTE data, LPDWORD count )
1149 NTSTATUS status;
1150 UNICODE_STRING name_str;
1151 DWORD total_size;
1152 char buffer[256], *buf_ptr = buffer;
1153 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1154 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1156 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1157 hkey, debugstr_w(name), reserved, type, data, count,
1158 (count && data) ? *count : 0 );
1160 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1161 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1163 RtlInitUnicodeString( &name_str, name );
1165 if (data) total_size = min( sizeof(buffer), *count + info_size );
1166 else
1168 total_size = info_size;
1169 if (count) *count = 0;
1172 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1173 buffer, total_size, &total_size );
1174 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1176 if (data)
1178 /* retry with a dynamically allocated buffer */
1179 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1181 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1182 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1183 return ERROR_NOT_ENOUGH_MEMORY;
1184 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1185 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1186 buf_ptr, total_size, &total_size );
1189 if (!status)
1191 memcpy( data, buf_ptr + info_size, total_size - info_size );
1192 /* if the type is REG_SZ and data is not 0-terminated
1193 * and there is enough space in the buffer NT appends a \0 */
1194 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1196 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1197 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1200 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1202 else status = STATUS_SUCCESS;
1204 if (type) *type = info->Type;
1205 if (count) *count = total_size - info_size;
1207 done:
1208 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1209 return RtlNtStatusToDosError(status);
1213 /******************************************************************************
1214 * RegQueryValueExA [ADVAPI32.@]
1216 * Get the type and contents of a specified value under with a key.
1218 * PARAMS
1219 * hkey [I] Handle of the key to query
1220 * name [I] Name of value under hkey to query
1221 * reserved [I] Reserved - must be NULL
1222 * type [O] Destination for the value type, or NULL if not required
1223 * data [O] Destination for the values contents, or NULL if not required
1224 * count [I/O] Size of data, updated with the number of bytes returned
1226 * RETURNS
1227 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1228 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1229 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1230 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1232 * NOTES
1233 * MSDN states that if data is too small it is partially filled. In reality
1234 * it remains untouched.
1236 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1237 LPBYTE data, LPDWORD count )
1239 NTSTATUS status;
1240 ANSI_STRING nameA;
1241 DWORD total_size, datalen = 0;
1242 char buffer[256], *buf_ptr = buffer;
1243 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1244 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1246 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1247 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1249 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1250 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1252 if (count) datalen = *count;
1253 if (!data && count) *count = 0;
1255 /* this matches Win9x behaviour - NT sets *type to a random value */
1256 if (type) *type = REG_NONE;
1258 RtlInitAnsiString( &nameA, name );
1259 if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1260 &nameA, FALSE )))
1261 return RtlNtStatusToDosError(status);
1263 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1264 KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
1265 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1267 /* we need to fetch the contents for a string type even if not requested,
1268 * because we need to compute the length of the ASCII string. */
1269 if (data || is_string(info->Type))
1271 /* retry with a dynamically allocated buffer */
1272 while (status == STATUS_BUFFER_OVERFLOW)
1274 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1275 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1277 status = STATUS_NO_MEMORY;
1278 goto done;
1280 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1281 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1282 KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1285 if (status) goto done;
1287 if (is_string(info->Type))
1289 DWORD len;
1291 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1292 total_size - info_size );
1293 if (data && len)
1295 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1296 else
1298 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1299 total_size - info_size );
1300 /* if the type is REG_SZ and data is not 0-terminated
1301 * and there is enough space in the buffer NT appends a \0 */
1302 if (len < datalen && data[len-1]) data[len] = 0;
1305 total_size = len + info_size;
1307 else if (data)
1309 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1310 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1313 else status = STATUS_SUCCESS;
1315 if (type) *type = info->Type;
1316 if (count) *count = total_size - info_size;
1318 done:
1319 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1320 return RtlNtStatusToDosError(status);
1324 /******************************************************************************
1325 * RegQueryValueW [ADVAPI32.@]
1327 * Retrieves the data associated with the default or unnamed value of a key.
1329 * PARAMS
1330 * hkey [I] Handle to an open key.
1331 * name [I] Name of the subkey of hKey.
1332 * data [O] Receives the string associated with the default value
1333 * of the key.
1334 * count [I/O] Size of lpValue in bytes.
1336 * RETURNS
1337 * Success: ERROR_SUCCESS
1338 * Failure: nonzero error code from Winerror.h
1340 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1342 DWORD ret;
1343 HKEY subkey = hkey;
1345 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1347 if (name && name[0])
1349 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1351 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1352 if (subkey != hkey) RegCloseKey( subkey );
1353 if (ret == ERROR_FILE_NOT_FOUND)
1355 /* return empty string if default value not found */
1356 if (data) *data = 0;
1357 if (count) *count = sizeof(WCHAR);
1358 ret = ERROR_SUCCESS;
1360 return ret;
1364 /******************************************************************************
1365 * RegQueryValueA [ADVAPI32.@]
1367 * See RegQueryValueW.
1369 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1371 DWORD ret;
1372 HKEY subkey = hkey;
1374 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1376 if (name && name[0])
1378 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1380 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1381 if (subkey != hkey) RegCloseKey( subkey );
1382 if (ret == ERROR_FILE_NOT_FOUND)
1384 /* return empty string if default value not found */
1385 if (data) *data = 0;
1386 if (count) *count = 1;
1387 ret = ERROR_SUCCESS;
1389 return ret;
1393 /******************************************************************************
1394 * ADVAPI_ApplyRestrictions [internal]
1396 * Helper function for RegGetValueA/W.
1398 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1399 DWORD cbData, PLONG ret )
1401 /* Check if the type is restricted by the passed flags */
1402 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1404 DWORD dwMask = 0;
1406 switch (dwType)
1408 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1409 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1410 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1411 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1412 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1413 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1414 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1417 if (dwFlags & dwMask)
1419 /* Type is not restricted, check for size mismatch */
1420 if (dwType == REG_BINARY)
1422 DWORD cbExpect = 0;
1424 if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD)
1425 cbExpect = 4;
1426 else if ((dwFlags & RRF_RT_QWORD) == RRF_RT_QWORD)
1427 cbExpect = 8;
1429 if (cbExpect && cbData != cbExpect)
1430 *ret = ERROR_DATATYPE_MISMATCH;
1433 else *ret = ERROR_UNSUPPORTED_TYPE;
1438 /******************************************************************************
1439 * RegGetValueW [ADVAPI32.@]
1441 * Retrieves the type and data for a value name associated with a key,
1442 * optionally expanding its content and restricting its type.
1444 * PARAMS
1445 * hKey [I] Handle to an open key.
1446 * pszSubKey [I] Name of the subkey of hKey.
1447 * pszValue [I] Name of value under hKey/szSubKey to query.
1448 * dwFlags [I] Flags restricting the value type to retrieve.
1449 * pdwType [O] Destination for the values type, may be NULL.
1450 * pvData [O] Destination for the values content, may be NULL.
1451 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1452 * retrieve the whole content, including the trailing '\0'
1453 * for strings.
1455 * RETURNS
1456 * Success: ERROR_SUCCESS
1457 * Failure: nonzero error code from Winerror.h
1459 * NOTES
1460 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1461 * expanded and pdwType is set to REG_SZ instead.
1462 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1463 * without RRF_NOEXPAND is thus not allowed.
1464 * An exception is the case where RRF_RT_ANY is specified, because then
1465 * RRF_NOEXPAND is allowed.
1467 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1468 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1469 LPDWORD pcbData )
1471 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1472 PVOID pvBuf = NULL;
1473 LONG ret;
1475 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1476 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1477 pvData, pcbData, cbData);
1479 if (pvData && !pcbData)
1480 return ERROR_INVALID_PARAMETER;
1481 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1482 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1483 return ERROR_INVALID_PARAMETER;
1485 if (pszSubKey && pszSubKey[0])
1487 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1488 if (ret != ERROR_SUCCESS) return ret;
1491 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1493 /* If we are going to expand we need to read in the whole the value even
1494 * if the passed buffer was too small as the expanded string might be
1495 * smaller than the unexpanded one and could fit into cbData bytes. */
1496 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1497 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1499 do {
1500 HeapFree(GetProcessHeap(), 0, pvBuf);
1502 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1503 if (!pvBuf)
1505 ret = ERROR_NOT_ENOUGH_MEMORY;
1506 break;
1509 if (ret == ERROR_MORE_DATA || !pvData)
1510 ret = RegQueryValueExW(hKey, pszValue, NULL,
1511 &dwType, pvBuf, &cbData);
1512 else
1514 /* Even if cbData was large enough we have to copy the
1515 * string since ExpandEnvironmentStrings can't handle
1516 * overlapping buffers. */
1517 CopyMemory(pvBuf, pvData, cbData);
1520 /* Both the type or the value itself could have been modified in
1521 * between so we have to keep retrying until the buffer is large
1522 * enough or we no longer have to expand the value. */
1523 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1525 if (ret == ERROR_SUCCESS)
1527 /* Recheck dwType in case it changed since the first call */
1528 if (dwType == REG_EXPAND_SZ)
1530 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1531 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1532 dwType = REG_SZ;
1533 if(pvData && pcbData && cbData > *pcbData)
1534 ret = ERROR_MORE_DATA;
1536 else if (pvData)
1537 CopyMemory(pvData, pvBuf, *pcbData);
1540 HeapFree(GetProcessHeap(), 0, pvBuf);
1543 if (pszSubKey && pszSubKey[0])
1544 RegCloseKey(hKey);
1546 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1548 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1549 ZeroMemory(pvData, *pcbData);
1551 if (pdwType) *pdwType = dwType;
1552 if (pcbData) *pcbData = cbData;
1554 return ret;
1558 /******************************************************************************
1559 * RegGetValueA [ADVAPI32.@]
1561 * See RegGetValueW.
1563 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1564 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1565 LPDWORD pcbData )
1567 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1568 PVOID pvBuf = NULL;
1569 LONG ret;
1571 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1572 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1573 cbData);
1575 if (pvData && !pcbData)
1576 return ERROR_INVALID_PARAMETER;
1577 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1578 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1579 return ERROR_INVALID_PARAMETER;
1581 if (pszSubKey && pszSubKey[0])
1583 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1584 if (ret != ERROR_SUCCESS) return ret;
1587 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1589 /* If we are going to expand we need to read in the whole the value even
1590 * if the passed buffer was too small as the expanded string might be
1591 * smaller than the unexpanded one and could fit into cbData bytes. */
1592 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1593 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1595 do {
1596 HeapFree(GetProcessHeap(), 0, pvBuf);
1598 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1599 if (!pvBuf)
1601 ret = ERROR_NOT_ENOUGH_MEMORY;
1602 break;
1605 if (ret == ERROR_MORE_DATA || !pvData)
1606 ret = RegQueryValueExA(hKey, pszValue, NULL,
1607 &dwType, pvBuf, &cbData);
1608 else
1610 /* Even if cbData was large enough we have to copy the
1611 * string since ExpandEnvironmentStrings can't handle
1612 * overlapping buffers. */
1613 CopyMemory(pvBuf, pvData, cbData);
1616 /* Both the type or the value itself could have been modified in
1617 * between so we have to keep retrying until the buffer is large
1618 * enough or we no longer have to expand the value. */
1619 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1621 if (ret == ERROR_SUCCESS)
1623 /* Recheck dwType in case it changed since the first call */
1624 if (dwType == REG_EXPAND_SZ)
1626 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1627 pcbData ? *pcbData : 0);
1628 dwType = REG_SZ;
1629 if(pvData && pcbData && cbData > *pcbData)
1630 ret = ERROR_MORE_DATA;
1632 else if (pvData)
1633 CopyMemory(pvData, pvBuf, *pcbData);
1636 HeapFree(GetProcessHeap(), 0, pvBuf);
1639 if (pszSubKey && pszSubKey[0])
1640 RegCloseKey(hKey);
1642 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1644 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1645 ZeroMemory(pvData, *pcbData);
1647 if (pdwType) *pdwType = dwType;
1648 if (pcbData) *pcbData = cbData;
1650 return ret;
1654 /******************************************************************************
1655 * RegEnumValueW [ADVAPI32.@]
1657 * Enumerates the values for the specified open registry key.
1659 * PARAMS
1660 * hkey [I] Handle to key to query
1661 * index [I] Index of value to query
1662 * value [O] Value string
1663 * val_count [I/O] Size of value buffer (in wchars)
1664 * reserved [I] Reserved
1665 * type [O] Type code
1666 * data [O] Value data
1667 * count [I/O] Size of data buffer (in bytes)
1669 * RETURNS
1670 * Success: ERROR_SUCCESS
1671 * Failure: nonzero error code from Winerror.h
1674 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1675 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1677 NTSTATUS status;
1678 DWORD total_size;
1679 char buffer[256], *buf_ptr = buffer;
1680 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1681 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1683 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1684 hkey, index, value, val_count, reserved, type, data, count );
1686 /* NT only checks count, not val_count */
1687 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1688 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1690 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1691 if (data) total_size += *count;
1692 total_size = min( sizeof(buffer), total_size );
1694 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1695 buffer, total_size, &total_size );
1696 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1698 if (value || data)
1700 /* retry with a dynamically allocated buffer */
1701 while (status == STATUS_BUFFER_OVERFLOW)
1703 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1704 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1705 return ERROR_NOT_ENOUGH_MEMORY;
1706 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1707 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1708 buf_ptr, total_size, &total_size );
1711 if (status) goto done;
1713 if (value)
1715 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1717 status = STATUS_BUFFER_OVERFLOW;
1718 goto overflow;
1720 memcpy( value, info->Name, info->NameLength );
1721 *val_count = info->NameLength / sizeof(WCHAR);
1722 value[*val_count] = 0;
1725 if (data)
1727 if (total_size - info->DataOffset > *count)
1729 status = STATUS_BUFFER_OVERFLOW;
1730 goto overflow;
1732 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1733 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1735 /* if the type is REG_SZ and data is not 0-terminated
1736 * and there is enough space in the buffer NT appends a \0 */
1737 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1738 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1742 else status = STATUS_SUCCESS;
1744 overflow:
1745 if (type) *type = info->Type;
1746 if (count) *count = info->DataLength;
1748 done:
1749 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1750 return RtlNtStatusToDosError(status);
1754 /******************************************************************************
1755 * RegEnumValueA [ADVAPI32.@]
1757 * See RegEnumValueW.
1759 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1760 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1762 NTSTATUS status;
1763 DWORD total_size;
1764 char buffer[256], *buf_ptr = buffer;
1765 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1766 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1768 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1769 hkey, index, value, val_count, reserved, type, data, count );
1771 /* NT only checks count, not val_count */
1772 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1773 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1775 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1776 if (data) total_size += *count;
1777 total_size = min( sizeof(buffer), total_size );
1779 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1780 buffer, total_size, &total_size );
1781 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1783 /* we need to fetch the contents for a string type even if not requested,
1784 * because we need to compute the length of the ASCII string. */
1785 if (value || data || is_string(info->Type))
1787 /* retry with a dynamically allocated buffer */
1788 while (status == STATUS_BUFFER_OVERFLOW)
1790 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1791 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1792 return ERROR_NOT_ENOUGH_MEMORY;
1793 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1794 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1795 buf_ptr, total_size, &total_size );
1798 if (status) goto done;
1800 if (is_string(info->Type))
1802 DWORD len;
1803 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1804 total_size - info->DataOffset );
1805 if (data && len)
1807 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1808 else
1810 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1811 total_size - info->DataOffset );
1812 /* if the type is REG_SZ and data is not 0-terminated
1813 * and there is enough space in the buffer NT appends a \0 */
1814 if (len < *count && data[len-1]) data[len] = 0;
1817 info->DataLength = len;
1819 else if (data)
1821 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1822 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1825 if (value && !status)
1827 DWORD len;
1829 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1830 if (len >= *val_count)
1832 status = STATUS_BUFFER_OVERFLOW;
1833 if (*val_count)
1835 len = *val_count - 1;
1836 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1837 value[len] = 0;
1840 else
1842 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1843 value[len] = 0;
1844 *val_count = len;
1848 else status = STATUS_SUCCESS;
1850 if (type) *type = info->Type;
1851 if (count) *count = info->DataLength;
1853 done:
1854 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1855 return RtlNtStatusToDosError(status);
1860 /******************************************************************************
1861 * RegDeleteValueW [ADVAPI32.@]
1863 * See RegDeleteValueA.
1865 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1867 UNICODE_STRING nameW;
1869 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1871 RtlInitUnicodeString( &nameW, name );
1872 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1876 /******************************************************************************
1877 * RegDeleteValueA [ADVAPI32.@]
1879 * Delete a value from the registry.
1881 * PARAMS
1882 * hkey [I] Registry handle of the key holding the value
1883 * name [I] Name of the value under hkey to delete
1885 * RETURNS
1886 * Success: ERROR_SUCCESS
1887 * Failure: nonzero error code from Winerror.h
1889 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1891 STRING nameA;
1892 NTSTATUS status;
1894 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1896 RtlInitAnsiString( &nameA, name );
1897 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1898 &nameA, FALSE )))
1899 status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1900 return RtlNtStatusToDosError( status );
1904 /******************************************************************************
1905 * RegLoadKeyW [ADVAPI32.@]
1907 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1908 * registration information from a specified file into that subkey.
1910 * PARAMS
1911 * hkey [I] Handle of open key
1912 * subkey [I] Address of name of subkey
1913 * filename [I] Address of filename for registry information
1915 * RETURNS
1916 * Success: ERROR_SUCCESS
1917 * Failure: nonzero error code from Winerror.h
1919 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1921 OBJECT_ATTRIBUTES destkey, file;
1922 UNICODE_STRING subkeyW, filenameW;
1923 NTSTATUS status;
1925 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
1927 destkey.Length = sizeof(destkey);
1928 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
1929 destkey.ObjectName = &subkeyW; /* name of the key */
1930 destkey.Attributes = 0;
1931 destkey.SecurityDescriptor = NULL;
1932 destkey.SecurityQualityOfService = NULL;
1933 RtlInitUnicodeString(&subkeyW, subkey);
1935 file.Length = sizeof(file);
1936 file.RootDirectory = NULL;
1937 file.ObjectName = &filenameW; /* file containing the hive */
1938 file.Attributes = OBJ_CASE_INSENSITIVE;
1939 file.SecurityDescriptor = NULL;
1940 file.SecurityQualityOfService = NULL;
1941 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
1943 status = NtLoadKey(&destkey, &file);
1944 RtlFreeUnicodeString(&filenameW);
1945 return RtlNtStatusToDosError( status );
1949 /******************************************************************************
1950 * RegLoadKeyA [ADVAPI32.@]
1952 * See RegLoadKeyW.
1954 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1956 UNICODE_STRING subkeyW, filenameW;
1957 STRING subkeyA, filenameA;
1958 NTSTATUS status;
1959 LONG ret;
1961 RtlInitAnsiString(&subkeyA, subkey);
1962 RtlInitAnsiString(&filenameA, filename);
1964 RtlInitUnicodeString(&subkeyW, NULL);
1965 RtlInitUnicodeString(&filenameW, NULL);
1966 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
1967 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
1969 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
1971 else ret = RtlNtStatusToDosError(status);
1972 RtlFreeUnicodeString(&subkeyW);
1973 RtlFreeUnicodeString(&filenameW);
1974 return ret;
1978 /******************************************************************************
1979 * RegSaveKeyW [ADVAPI32.@]
1981 * Save a key and all of its subkeys and values to a new file in the standard format.
1983 * PARAMS
1984 * hkey [I] Handle of key where save begins
1985 * lpFile [I] Address of filename to save to
1986 * sa [I] Address of security structure
1988 * RETURNS
1989 * Success: ERROR_SUCCESS
1990 * Failure: nonzero error code from Winerror.h
1992 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1994 static const WCHAR format[] =
1995 {'r','e','g','%','0','4','x','.','t','m','p',0};
1996 WCHAR buffer[MAX_PATH];
1997 int count = 0;
1998 LPWSTR nameW;
1999 DWORD ret, err;
2000 HANDLE handle;
2002 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2004 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2005 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2007 err = GetLastError();
2008 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2010 for (;;)
2012 snprintfW( nameW, 16, format, count++ );
2013 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2014 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2015 if (handle != INVALID_HANDLE_VALUE) break;
2016 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2018 /* Something gone haywire ? Please report if this happens abnormally */
2019 if (count >= 100)
2020 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);
2023 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2025 CloseHandle( handle );
2026 if (!ret)
2028 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2030 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2031 debugstr_w(file) );
2032 ret = GetLastError();
2035 if (ret) DeleteFileW( buffer );
2037 done:
2038 SetLastError( err ); /* restore last error code */
2039 return ret;
2043 /******************************************************************************
2044 * RegSaveKeyA [ADVAPI32.@]
2046 * See RegSaveKeyW.
2048 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2050 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2051 NTSTATUS status;
2052 STRING fileA;
2054 RtlInitAnsiString(&fileA, file);
2055 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2056 return RtlNtStatusToDosError( status );
2057 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2061 /******************************************************************************
2062 * RegRestoreKeyW [ADVAPI32.@]
2064 * Read the registry information from a file and copy it over a key.
2066 * PARAMS
2067 * hkey [I] Handle of key where restore begins
2068 * lpFile [I] Address of filename containing saved tree
2069 * dwFlags [I] Optional flags
2071 * RETURNS
2072 * Success: ERROR_SUCCESS
2073 * Failure: nonzero error code from Winerror.h
2075 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2077 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2079 /* It seems to do this check before the hkey check */
2080 if (!lpFile || !*lpFile)
2081 return ERROR_INVALID_PARAMETER;
2083 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2085 /* Check for file existence */
2087 return ERROR_SUCCESS;
2091 /******************************************************************************
2092 * RegRestoreKeyA [ADVAPI32.@]
2094 * See RegRestoreKeyW.
2096 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2098 UNICODE_STRING lpFileW;
2099 LONG ret;
2101 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2102 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2103 RtlFreeUnicodeString( &lpFileW );
2104 return ret;
2108 /******************************************************************************
2109 * RegUnLoadKeyW [ADVAPI32.@]
2111 * Unload a registry key and its subkeys from the registry.
2113 * PARAMS
2114 * hkey [I] Handle of open key
2115 * lpSubKey [I] Address of name of subkey to unload
2117 * RETURNS
2118 * Success: ERROR_SUCCESS
2119 * Failure: nonzero error code from Winerror.h
2121 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2123 DWORD ret;
2124 HKEY shkey;
2125 OBJECT_ATTRIBUTES attr;
2126 UNICODE_STRING subkey;
2128 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2130 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2131 if( ret )
2132 return ERROR_INVALID_PARAMETER;
2134 RtlInitUnicodeString(&subkey, lpSubKey);
2135 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2136 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2138 RegCloseKey(shkey);
2140 return ret;
2144 /******************************************************************************
2145 * RegUnLoadKeyA [ADVAPI32.@]
2147 * See RegUnLoadKeyW.
2149 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2151 UNICODE_STRING lpSubKeyW;
2152 LONG ret;
2154 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2155 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2156 RtlFreeUnicodeString( &lpSubKeyW );
2157 return ret;
2161 /******************************************************************************
2162 * RegReplaceKeyW [ADVAPI32.@]
2164 * Replace the file backing a registry key and all its subkeys with another file.
2166 * PARAMS
2167 * hkey [I] Handle of open key
2168 * lpSubKey [I] Address of name of subkey
2169 * lpNewFile [I] Address of filename for file with new data
2170 * lpOldFile [I] Address of filename for backup file
2172 * RETURNS
2173 * Success: ERROR_SUCCESS
2174 * Failure: nonzero error code from Winerror.h
2176 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2177 LPCWSTR lpOldFile )
2179 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2180 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2181 return ERROR_SUCCESS;
2185 /******************************************************************************
2186 * RegReplaceKeyA [ADVAPI32.@]
2188 * See RegReplaceKeyW.
2190 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2191 LPCSTR lpOldFile )
2193 UNICODE_STRING lpSubKeyW;
2194 UNICODE_STRING lpNewFileW;
2195 UNICODE_STRING lpOldFileW;
2196 LONG ret;
2198 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2199 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2200 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2201 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2202 RtlFreeUnicodeString( &lpOldFileW );
2203 RtlFreeUnicodeString( &lpNewFileW );
2204 RtlFreeUnicodeString( &lpSubKeyW );
2205 return ret;
2209 /******************************************************************************
2210 * RegSetKeySecurity [ADVAPI32.@]
2212 * Set the security of an open registry key.
2214 * PARAMS
2215 * hkey [I] Open handle of key to set
2216 * SecurityInfo [I] Descriptor contents
2217 * pSecurityDesc [I] Address of descriptor for key
2219 * RETURNS
2220 * Success: ERROR_SUCCESS
2221 * Failure: nonzero error code from Winerror.h
2223 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2224 PSECURITY_DESCRIPTOR pSecurityDesc )
2226 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2228 /* It seems to perform this check before the hkey check */
2229 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2230 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2231 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2232 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2233 /* Param OK */
2234 } else
2235 return ERROR_INVALID_PARAMETER;
2237 if (!pSecurityDesc)
2238 return ERROR_INVALID_PARAMETER;
2240 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2242 return ERROR_SUCCESS;
2246 /******************************************************************************
2247 * RegGetKeySecurity [ADVAPI32.@]
2249 * Get a copy of the security descriptor for a given registry key.
2251 * PARAMS
2252 * hkey [I] Open handle of key to set
2253 * SecurityInformation [I] Descriptor contents
2254 * pSecurityDescriptor [O] Address of descriptor for key
2255 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2257 * RETURNS
2258 * Success: ERROR_SUCCESS
2259 * Failure: Error code
2261 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2262 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2263 LPDWORD lpcbSecurityDescriptor )
2265 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2266 *lpcbSecurityDescriptor);
2268 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2270 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2271 SecurityInformation, pSecurityDescriptor,
2272 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2276 /******************************************************************************
2277 * RegFlushKey [ADVAPI32.@]
2279 * Immediately write a registry key to registry.
2281 * PARAMS
2282 * hkey [I] Handle of key to write
2284 * RETURNS
2285 * Success: ERROR_SUCCESS
2286 * Failure: Error code
2288 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2290 hkey = get_special_root_hkey( hkey );
2291 if (!hkey) return ERROR_INVALID_HANDLE;
2293 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2297 /******************************************************************************
2298 * RegConnectRegistryW [ADVAPI32.@]
2300 * Establish a connection to a predefined registry key on another computer.
2302 * PARAMS
2303 * lpMachineName [I] Address of name of remote computer
2304 * hHey [I] Predefined registry handle
2305 * phkResult [I] Address of buffer for remote registry handle
2307 * RETURNS
2308 * Success: ERROR_SUCCESS
2309 * Failure: nonzero error code from Winerror.h
2311 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2312 PHKEY phkResult )
2314 LONG ret;
2316 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2318 if (!lpMachineName || !*lpMachineName) {
2319 /* Use the local machine name */
2320 ret = RegOpenKeyW( hKey, NULL, phkResult );
2322 else {
2323 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2324 DWORD len = sizeof(compName) / sizeof(WCHAR);
2326 /* MSDN says lpMachineName must start with \\ : not so */
2327 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2328 lpMachineName += 2;
2329 if (GetComputerNameW(compName, &len))
2331 if (!strcmpiW(lpMachineName, compName))
2332 ret = RegOpenKeyW(hKey, NULL, phkResult);
2333 else
2335 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2336 ret = ERROR_BAD_NETPATH;
2339 else
2340 ret = GetLastError();
2342 return ret;
2346 /******************************************************************************
2347 * RegConnectRegistryA [ADVAPI32.@]
2349 * See RegConnectRegistryW.
2351 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2353 UNICODE_STRING machineW;
2354 LONG ret;
2356 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2357 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2358 RtlFreeUnicodeString( &machineW );
2359 return ret;
2363 /******************************************************************************
2364 * RegNotifyChangeKeyValue [ADVAPI32.@]
2366 * Notify the caller about changes to the attributes or contents of a registry key.
2368 * PARAMS
2369 * hkey [I] Handle of key to watch
2370 * fWatchSubTree [I] Flag for subkey notification
2371 * fdwNotifyFilter [I] Changes to be reported
2372 * hEvent [I] Handle of signaled event
2373 * fAsync [I] Flag for asynchronous reporting
2375 * RETURNS
2376 * Success: ERROR_SUCCESS
2377 * Failure: nonzero error code from Winerror.h
2379 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2380 DWORD fdwNotifyFilter, HANDLE hEvent,
2381 BOOL fAsync )
2383 NTSTATUS status;
2384 IO_STATUS_BLOCK iosb;
2386 hkey = get_special_root_hkey( hkey );
2387 if (!hkey) return ERROR_INVALID_HANDLE;
2389 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2390 hEvent, fAsync);
2392 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2393 fdwNotifyFilter, fAsync, NULL, 0,
2394 fWatchSubTree);
2396 if (status && status != STATUS_TIMEOUT)
2397 return RtlNtStatusToDosError( status );
2399 return ERROR_SUCCESS;
2402 /******************************************************************************
2403 * RegOpenUserClassesRoot [ADVAPI32.@]
2405 * Open the HKEY_CLASSES_ROOT key for a user.
2407 * PARAMS
2408 * hToken [I] Handle of token representing the user
2409 * dwOptions [I] Reserved, must be 0
2410 * samDesired [I] Desired access rights
2411 * phkResult [O] Destination for the resulting key handle
2413 * RETURNS
2414 * Success: ERROR_SUCCESS
2415 * Failure: nonzero error code from Winerror.h
2417 * NOTES
2418 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2419 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2420 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2422 LSTATUS WINAPI RegOpenUserClassesRoot(
2423 HANDLE hToken,
2424 DWORD dwOptions,
2425 REGSAM samDesired,
2426 PHKEY phkResult
2429 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2431 *phkResult = HKEY_CLASSES_ROOT;
2432 return ERROR_SUCCESS;
2435 /******************************************************************************
2436 * load_string [Internal]
2438 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2439 * avoid importing user32, which is higher level than advapi32. Helper for
2440 * RegLoadMUIString.
2442 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2444 HGLOBAL hMemory;
2445 HRSRC hResource;
2446 WCHAR *pString;
2447 int idxString;
2449 /* Negative values have to be inverted. */
2450 if (HIWORD(resId) == 0xffff)
2451 resId = (UINT)(-((INT)resId));
2453 /* Load the resource into memory and get a pointer to it. */
2454 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2455 if (!hResource) return 0;
2456 hMemory = LoadResource(hModule, hResource);
2457 if (!hMemory) return 0;
2458 pString = LockResource(hMemory);
2460 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2461 idxString = resId & 0xf;
2462 while (idxString--) pString += *pString + 1;
2464 /* If no buffer is given, return length of the string. */
2465 if (!pwszBuffer) return *pString;
2467 /* Else copy over the string, respecting the buffer size. */
2468 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2469 if (cMaxChars >= 0) {
2470 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2471 pwszBuffer[cMaxChars] = '\0';
2474 return cMaxChars;
2477 /******************************************************************************
2478 * RegLoadMUIStringW [ADVAPI32.@]
2480 * Load the localized version of a string resource from some PE, respective
2481 * id and path of which are given in the registry value in the format
2482 * @[path]\dllname,-resourceId
2484 * PARAMS
2485 * hKey [I] Key, of which to load the string value from.
2486 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2487 * pszBuffer [O] Buffer to store the localized string in.
2488 * cbBuffer [I] Size of the destination buffer in bytes.
2489 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2490 * dwFlags [I] None supported yet.
2491 * pszBaseDir [I] Not supported yet.
2493 * RETURNS
2494 * Success: ERROR_SUCCESS,
2495 * Failure: nonzero error code from winerror.h
2497 * NOTES
2498 * This is an API of Windows Vista, which wasn't available at the time this code
2499 * was written. We have to check for the correct behaviour once it's available.
2501 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2502 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2504 DWORD dwValueType, cbData;
2505 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2506 LONG result;
2508 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2509 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2510 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2512 /* Parameter sanity checks. */
2513 if (!hKey || !pwszBuffer)
2514 return ERROR_INVALID_PARAMETER;
2516 if (pwszBaseDir && *pwszBaseDir) {
2517 FIXME("BaseDir parameter not yet supported!\n");
2518 return ERROR_INVALID_PARAMETER;
2521 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2522 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2523 if (result != ERROR_SUCCESS) goto cleanup;
2524 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2525 result = ERROR_FILE_NOT_FOUND;
2526 goto cleanup;
2528 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2529 if (!pwszTempBuffer) {
2530 result = ERROR_NOT_ENOUGH_MEMORY;
2531 goto cleanup;
2533 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2534 if (result != ERROR_SUCCESS) goto cleanup;
2536 /* Expand environment variables, if appropriate, or copy the original string over. */
2537 if (dwValueType == REG_EXPAND_SZ) {
2538 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2539 if (!cbData) goto cleanup;
2540 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2541 if (!pwszExpandedBuffer) {
2542 result = ERROR_NOT_ENOUGH_MEMORY;
2543 goto cleanup;
2545 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2546 } else {
2547 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2548 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2551 /* If the value references a resource based string, parse the value and load the string.
2552 * Else just copy over the original value. */
2553 result = ERROR_SUCCESS;
2554 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2555 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2556 } else {
2557 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2558 UINT uiStringId;
2559 HMODULE hModule;
2561 /* Format of the expanded value is 'path_to_dll,-resId' */
2562 if (!pComma || pComma[1] != '-') {
2563 result = ERROR_BADKEY;
2564 goto cleanup;
2567 uiStringId = atoiW(pComma+2);
2568 *pComma = '\0';
2570 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2571 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2572 result = ERROR_BADKEY;
2573 FreeLibrary(hModule);
2576 cleanup:
2577 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2578 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2579 return result;
2582 /******************************************************************************
2583 * RegLoadMUIStringA [ADVAPI32.@]
2585 * See RegLoadMUIStringW
2587 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2588 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2590 UNICODE_STRING valueW, baseDirW;
2591 WCHAR *pwszBuffer;
2592 DWORD cbData = cbBuffer * sizeof(WCHAR);
2593 LONG result;
2595 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2596 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2597 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2598 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2600 result = ERROR_NOT_ENOUGH_MEMORY;
2601 goto cleanup;
2604 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2605 baseDirW.Buffer);
2607 if (result == ERROR_SUCCESS) {
2608 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2609 if (pcbData)
2610 *pcbData = cbData;
2613 cleanup:
2614 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2615 RtlFreeUnicodeString(&baseDirW);
2616 RtlFreeUnicodeString(&valueW);
2618 return result;
2621 /******************************************************************************
2622 * RegDisablePredefinedCache [ADVAPI32.@]
2624 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2626 * PARAMS
2627 * None.
2629 * RETURNS
2630 * Success: ERROR_SUCCESS
2631 * Failure: nonzero error code from Winerror.h
2633 * NOTES
2634 * This is useful for services that use impersonation.
2636 LSTATUS WINAPI RegDisablePredefinedCache(void)
2638 HKEY hkey_current_user;
2639 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2641 /* prevent caching of future requests */
2642 hkcu_cache_disabled = TRUE;
2644 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2646 if (hkey_current_user)
2647 NtClose( hkey_current_user );
2649 return ERROR_SUCCESS;
2652 /******************************************************************************
2653 * RegDeleteTreeW [ADVAPI32.@]
2656 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2658 LONG ret;
2659 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2660 DWORD dwMaxLen, dwSize;
2661 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2662 HKEY hSubKey = hKey;
2664 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2666 if(lpszSubKey)
2668 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2669 if (ret) return ret;
2672 /* Get highest length for keys, values */
2673 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2674 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2675 if (ret) goto cleanup;
2677 dwMaxSubkeyLen++;
2678 dwMaxValueLen++;
2679 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2680 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2682 /* Name too big: alloc a buffer for it */
2683 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2685 ret = ERROR_NOT_ENOUGH_MEMORY;
2686 goto cleanup;
2691 /* Recursively delete all the subkeys */
2692 while (TRUE)
2694 dwSize = dwMaxLen;
2695 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2696 NULL, NULL, NULL)) break;
2698 ret = RegDeleteTreeW(hSubKey, lpszName);
2699 if (ret) goto cleanup;
2702 if (lpszSubKey)
2703 ret = RegDeleteKeyW(hKey, lpszSubKey);
2704 else
2705 while (TRUE)
2707 dwSize = dwMaxLen;
2708 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2709 NULL, NULL, NULL, NULL)) break;
2711 ret = RegDeleteValueW(hKey, lpszName);
2712 if (ret) goto cleanup;
2715 cleanup:
2716 /* Free buffer if allocated */
2717 if (lpszName != szNameBuf)
2718 HeapFree( GetProcessHeap(), 0, lpszName);
2719 if(lpszSubKey)
2720 RegCloseKey(hSubKey);
2721 return ret;
2724 /******************************************************************************
2725 * RegDeleteTreeA [ADVAPI32.@]
2728 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2730 LONG ret;
2731 UNICODE_STRING lpszSubKeyW;
2733 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2734 else lpszSubKeyW.Buffer = NULL;
2735 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2736 RtlFreeUnicodeString( &lpszSubKeyW );
2737 return ret;