jscript: Added RegExp contruction implementation.
[wine.git] / dlls / advapi32 / registry.c
blobff574b28ffde3dc8e9ceaf71f8e482604ce6ea68
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)HKEY_SPECIAL_ROOT_LAST - (UINT)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 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
311 attr.Length = sizeof(attr);
312 attr.RootDirectory = hkey;
313 attr.ObjectName = &nameW;
314 attr.Attributes = 0;
315 attr.SecurityDescriptor = NULL;
316 attr.SecurityQualityOfService = NULL;
317 RtlInitUnicodeString( &nameW, name );
318 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE)retkey, access, &attr ) );
322 /******************************************************************************
323 * RegOpenKeyExA [ADVAPI32.@]
325 * Open a registry key.
327 * PARAMS
328 * hkey [I] Handle of open key
329 * name [I] Name of subkey to open
330 * reserved [I] Reserved - must be zero
331 * access [I] Security access mask
332 * retkey [O] Handle to open key
334 * RETURNS
335 * Success: ERROR_SUCCESS
336 * Failure: A standard Win32 error code. retkey is set to 0.
338 * NOTES
339 * Unlike RegCreateKeyExA(), this function will not create the key if it
340 * does not exist.
342 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
344 OBJECT_ATTRIBUTES attr;
345 STRING nameA;
346 NTSTATUS status;
348 if (!is_version_nt()) access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
350 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
352 attr.Length = sizeof(attr);
353 attr.RootDirectory = hkey;
354 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
355 attr.Attributes = 0;
356 attr.SecurityDescriptor = NULL;
357 attr.SecurityQualityOfService = NULL;
359 RtlInitAnsiString( &nameA, name );
360 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
361 &nameA, FALSE )))
363 status = NtOpenKey( (PHANDLE)retkey, access, &attr );
365 return RtlNtStatusToDosError( status );
369 /******************************************************************************
370 * RegOpenKeyW [ADVAPI32.@]
372 * See RegOpenKeyA.
374 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
376 if (!name || !*name)
378 *retkey = hkey;
379 return ERROR_SUCCESS;
381 return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
385 /******************************************************************************
386 * RegOpenKeyA [ADVAPI32.@]
388 * Open a registry key.
390 * PARAMS
391 * hkey [I] Handle of parent key to open the new key under
392 * name [I] Name of the key under hkey to open
393 * retkey [O] Destination for the resulting Handle
395 * RETURNS
396 * Success: ERROR_SUCCESS
397 * Failure: A standard Win32 error code. retkey is set to 0.
399 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
401 if (!name || !*name)
403 *retkey = hkey;
404 return ERROR_SUCCESS;
406 return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
410 /******************************************************************************
411 * RegOpenCurrentUser [ADVAPI32.@]
413 * Get a handle to the HKEY_CURRENT_USER key for the user
414 * the current thread is impersonating.
416 * PARAMS
417 * access [I] Desired access rights to the key
418 * retkey [O] Handle to the opened key
420 * RETURNS
421 * Success: ERROR_SUCCESS
422 * Failure: nonzero error code from Winerror.h
424 * FIXME
425 * This function is supposed to retrieve a handle to the
426 * HKEY_CURRENT_USER for the user the current thread is impersonating.
427 * Since Wine does not currently allow threads to impersonate other users,
428 * this stub should work fine.
430 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
432 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
437 /******************************************************************************
438 * RegEnumKeyExW [ADVAPI32.@]
440 * Enumerate subkeys of the specified open registry key.
442 * PARAMS
443 * hkey [I] Handle to key to enumerate
444 * index [I] Index of subkey to enumerate
445 * name [O] Buffer for subkey name
446 * name_len [O] Size of subkey buffer
447 * reserved [I] Reserved
448 * class [O] Buffer for class string
449 * class_len [O] Size of class buffer
450 * ft [O] Time key last written to
452 * RETURNS
453 * Success: ERROR_SUCCESS
454 * Failure: System error code. If there are no more subkeys available, the
455 * function returns ERROR_NO_MORE_ITEMS.
457 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
458 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
460 NTSTATUS status;
461 char buffer[256], *buf_ptr = buffer;
462 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
463 DWORD total_size;
465 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
466 name_len ? *name_len : 0, reserved, class, class_len, ft );
468 if (reserved) return ERROR_INVALID_PARAMETER;
469 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
471 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
472 buffer, sizeof(buffer), &total_size );
474 while (status == STATUS_BUFFER_OVERFLOW)
476 /* retry with a dynamically allocated buffer */
477 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
478 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
479 return ERROR_NOT_ENOUGH_MEMORY;
480 info = (KEY_NODE_INFORMATION *)buf_ptr;
481 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
482 buf_ptr, total_size, &total_size );
485 if (!status)
487 DWORD len = info->NameLength / sizeof(WCHAR);
488 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
490 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
492 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
493 status = STATUS_BUFFER_OVERFLOW;
494 else
496 *name_len = len;
497 memcpy( name, info->Name, info->NameLength );
498 name[len] = 0;
499 if (class_len)
501 *class_len = cls_len;
502 if (class)
504 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
505 class[cls_len] = 0;
511 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
512 return RtlNtStatusToDosError( status );
516 /******************************************************************************
517 * RegEnumKeyExA [ADVAPI32.@]
519 * See RegEnumKeyExW.
521 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
522 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
524 NTSTATUS status;
525 char buffer[256], *buf_ptr = buffer;
526 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
527 DWORD total_size;
529 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
530 name_len ? *name_len : 0, reserved, class, class_len, ft );
532 if (reserved) return ERROR_INVALID_PARAMETER;
533 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
535 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
536 buffer, sizeof(buffer), &total_size );
538 while (status == STATUS_BUFFER_OVERFLOW)
540 /* retry with a dynamically allocated buffer */
541 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
542 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
543 return ERROR_NOT_ENOUGH_MEMORY;
544 info = (KEY_NODE_INFORMATION *)buf_ptr;
545 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
546 buf_ptr, total_size, &total_size );
549 if (!status)
551 DWORD len, cls_len;
553 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
554 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
555 info->ClassLength );
556 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
558 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
559 status = STATUS_BUFFER_OVERFLOW;
560 else
562 *name_len = len;
563 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
564 name[len] = 0;
565 if (class_len)
567 *class_len = cls_len;
568 if (class)
570 RtlUnicodeToMultiByteN( class, cls_len, NULL,
571 (WCHAR *)(buf_ptr + info->ClassOffset),
572 info->ClassLength );
573 class[cls_len] = 0;
579 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
580 return RtlNtStatusToDosError( status );
584 /******************************************************************************
585 * RegEnumKeyW [ADVAPI32.@]
587 * Enumerates subkeys of the specified open reg key.
589 * PARAMS
590 * hKey [I] Handle to an open key.
591 * dwIndex [I] Index of the subkey of hKey to retrieve.
592 * lpName [O] Name of the subkey.
593 * cchName [I] Size of lpName in TCHARS.
595 * RETURNS
596 * Success: ERROR_SUCCESS
597 * Failure: system error code. If there are no more subkeys available, the
598 * function returns ERROR_NO_MORE_ITEMS.
600 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
602 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
606 /******************************************************************************
607 * RegEnumKeyA [ADVAPI32.@]
609 * See RegEnumKeyW.
611 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
613 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
617 /******************************************************************************
618 * RegQueryInfoKeyW [ADVAPI32.@]
620 * Retrieves information about the specified registry key.
622 * PARAMS
623 * hkey [I] Handle to key to query
624 * class [O] Buffer for class string
625 * class_len [O] Size of class string buffer
626 * reserved [I] Reserved
627 * subkeys [O] Buffer for number of subkeys
628 * max_subkey [O] Buffer for longest subkey name length
629 * max_class [O] Buffer for longest class string length
630 * values [O] Buffer for number of value entries
631 * max_value [O] Buffer for longest value name length
632 * max_data [O] Buffer for longest value data length
633 * security [O] Buffer for security descriptor length
634 * modif [O] Modification time
636 * RETURNS
637 * Success: ERROR_SUCCESS
638 * Failure: system error code.
640 * NOTES
641 * - win95 allows class to be valid and class_len to be NULL
642 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
643 * - both allow class to be NULL and class_len to be NULL
644 * (it's hard to test validity, so test !NULL instead)
646 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
647 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
648 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
649 LPDWORD security, FILETIME *modif )
651 NTSTATUS status;
652 char buffer[256], *buf_ptr = buffer;
653 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
654 DWORD total_size;
656 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
657 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
659 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
660 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
662 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
663 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
665 if (class)
667 /* retry with a dynamically allocated buffer */
668 while (status == STATUS_BUFFER_OVERFLOW)
670 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
671 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
672 return ERROR_NOT_ENOUGH_MEMORY;
673 info = (KEY_FULL_INFORMATION *)buf_ptr;
674 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
677 if (status) goto done;
679 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
681 status = STATUS_BUFFER_OVERFLOW;
683 else
685 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
686 class[info->ClassLength/sizeof(WCHAR)] = 0;
689 else status = STATUS_SUCCESS;
691 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
692 if (subkeys) *subkeys = info->SubKeys;
693 if (max_subkey) *max_subkey = info->MaxNameLen;
694 if (max_class) *max_class = info->MaxClassLen;
695 if (values) *values = info->Values;
696 if (max_value) *max_value = info->MaxValueNameLen;
697 if (max_data) *max_data = info->MaxValueDataLen;
698 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
700 done:
701 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
702 return RtlNtStatusToDosError( status );
706 /******************************************************************************
707 * RegQueryMultipleValuesA [ADVAPI32.@]
709 * Retrieves the type and data for a list of value names associated with a key.
711 * PARAMS
712 * hKey [I] Handle to an open key.
713 * val_list [O] Array of VALENT structures that describes the entries.
714 * num_vals [I] Number of elements in val_list.
715 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
716 * ldwTotsize [I/O] Size of lpValueBuf.
718 * RETURNS
719 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
720 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
721 * bytes.
723 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
724 LPSTR lpValueBuf, LPDWORD ldwTotsize )
726 unsigned int i;
727 DWORD maxBytes = *ldwTotsize;
728 HRESULT status;
729 LPSTR bufptr = lpValueBuf;
730 *ldwTotsize = 0;
732 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
734 for(i=0; i < num_vals; ++i)
737 val_list[i].ve_valuelen=0;
738 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
739 if(status != ERROR_SUCCESS)
741 return status;
744 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
746 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
747 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
748 if(status != ERROR_SUCCESS)
750 return status;
753 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
755 bufptr += val_list[i].ve_valuelen;
758 *ldwTotsize += val_list[i].ve_valuelen;
760 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
764 /******************************************************************************
765 * RegQueryMultipleValuesW [ADVAPI32.@]
767 * See RegQueryMultipleValuesA.
769 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
770 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
772 unsigned int i;
773 DWORD maxBytes = *ldwTotsize;
774 HRESULT status;
775 LPSTR bufptr = (LPSTR)lpValueBuf;
776 *ldwTotsize = 0;
778 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
780 for(i=0; i < num_vals; ++i)
782 val_list[i].ve_valuelen=0;
783 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
784 if(status != ERROR_SUCCESS)
786 return status;
789 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
791 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
792 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
793 if(status != ERROR_SUCCESS)
795 return status;
798 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
800 bufptr += val_list[i].ve_valuelen;
803 *ldwTotsize += val_list[i].ve_valuelen;
805 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
808 /******************************************************************************
809 * RegQueryInfoKeyA [ADVAPI32.@]
811 * Retrieves information about a registry key.
813 * PARAMS
814 * hKey [I] Handle to an open key.
815 * lpClass [O] Class string of the key.
816 * lpcClass [I/O] size of lpClass.
817 * lpReserved [I] Reserved; must be NULL.
818 * lpcSubKeys [O] Number of subkeys contained by the key.
819 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
820 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
821 * class in TCHARS.
822 * lpcValues [O] Number of values associated with the key.
823 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
824 * lpcMaxValueLen [O] Longest data component among the key's values
825 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
826 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
828 * RETURNS
829 * Success: ERROR_SUCCESS
830 * Failure: nonzero error code from Winerror.h
832 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
833 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
834 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
835 LPDWORD security, FILETIME *modif )
837 NTSTATUS status;
838 char buffer[256], *buf_ptr = buffer;
839 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
840 DWORD total_size, len;
842 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
843 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
845 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
846 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
848 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
849 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
851 if (class || class_len)
853 /* retry with a dynamically allocated buffer */
854 while (status == STATUS_BUFFER_OVERFLOW)
856 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
857 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
858 return ERROR_NOT_ENOUGH_MEMORY;
859 info = (KEY_FULL_INFORMATION *)buf_ptr;
860 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
863 if (status) goto done;
865 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
866 if (class_len)
868 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
869 *class_len = len;
871 if (class && !status)
873 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
874 info->ClassLength );
875 class[len] = 0;
878 else status = STATUS_SUCCESS;
880 if (subkeys) *subkeys = info->SubKeys;
881 if (max_subkey) *max_subkey = info->MaxNameLen;
882 if (max_class) *max_class = info->MaxClassLen;
883 if (values) *values = info->Values;
884 if (max_value) *max_value = info->MaxValueNameLen;
885 if (max_data) *max_data = info->MaxValueDataLen;
886 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
888 done:
889 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
890 return RtlNtStatusToDosError( status );
894 /******************************************************************************
895 * RegCloseKey [ADVAPI32.@]
897 * Close an open registry key.
899 * PARAMS
900 * hkey [I] Handle of key to close
902 * RETURNS
903 * Success: ERROR_SUCCESS
904 * Failure: Error code
906 LSTATUS WINAPI RegCloseKey( HKEY hkey )
908 if (!hkey) return ERROR_INVALID_HANDLE;
909 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
910 return RtlNtStatusToDosError( NtClose( hkey ) );
914 /******************************************************************************
915 * RegDeleteKeyW [ADVAPI32.@]
917 * See RegDeleteKeyA.
919 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
921 DWORD ret;
922 HKEY tmp;
924 if (!name) return ERROR_INVALID_PARAMETER;
926 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
928 if (!(ret = RegOpenKeyExW( hkey, name, 0, DELETE, &tmp )))
930 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
931 RegCloseKey( tmp );
933 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
934 return ret;
938 /******************************************************************************
939 * RegDeleteKeyA [ADVAPI32.@]
941 * Delete a registry key.
943 * PARAMS
944 * hkey [I] Handle to parent key containing the key to delete
945 * name [I] Name of the key user hkey to delete
947 * NOTES
949 * MSDN is wrong when it says that hkey must be opened with the DELETE access
950 * right. In reality, it opens a new handle with DELETE access.
952 * RETURNS
953 * Success: ERROR_SUCCESS
954 * Failure: Error code
956 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
958 DWORD ret;
959 HKEY tmp;
961 if (!name) return ERROR_INVALID_PARAMETER;
963 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
965 if (!(ret = RegOpenKeyExA( hkey, name, 0, DELETE, &tmp )))
967 if (!is_version_nt()) /* win95 does recursive key deletes */
969 CHAR name[MAX_PATH];
971 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
973 if(RegDeleteKeyA(tmp, name)) /* recurse */
974 break;
977 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
978 RegCloseKey( tmp );
980 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
981 return ret;
986 /******************************************************************************
987 * RegSetValueExW [ADVAPI32.@]
989 * Set the data and contents of a registry value.
991 * PARAMS
992 * hkey [I] Handle of key to set value for
993 * name [I] Name of value to set
994 * reserved [I] Reserved, must be zero
995 * type [I] Type of the value being set
996 * data [I] The new contents of the value to set
997 * count [I] Size of data
999 * RETURNS
1000 * Success: ERROR_SUCCESS
1001 * Failure: Error code
1003 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1004 DWORD type, CONST BYTE *data, DWORD count )
1006 UNICODE_STRING nameW;
1008 /* no need for version check, not implemented on win9x anyway */
1009 if (count && is_string(type))
1011 LPCWSTR str = (LPCWSTR)data;
1012 /* if user forgot to count terminating null, add it (yes NT does this) */
1013 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1014 count += sizeof(WCHAR);
1016 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1018 RtlInitUnicodeString( &nameW, name );
1019 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1023 /******************************************************************************
1024 * RegSetValueExA [ADVAPI32.@]
1026 * See RegSetValueExW.
1028 * NOTES
1029 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1030 * NT does definitely care (aj)
1032 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1033 CONST BYTE *data, DWORD count )
1035 ANSI_STRING nameA;
1036 WCHAR *dataW = NULL;
1037 NTSTATUS status;
1039 if (!is_version_nt()) /* win95 */
1041 if (type == REG_SZ)
1043 if (!data) return ERROR_INVALID_PARAMETER;
1044 count = strlen((const char *)data) + 1;
1047 else if (count && is_string(type))
1049 /* if user forgot to count terminating null, add it (yes NT does this) */
1050 if (data[count-1] && !data[count]) count++;
1053 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1055 if (is_string( type )) /* need to convert to Unicode */
1057 DWORD lenW;
1058 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1059 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1060 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1061 count = lenW;
1062 data = (BYTE *)dataW;
1065 RtlInitAnsiString( &nameA, name );
1066 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1067 &nameA, FALSE )))
1069 status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
1071 HeapFree( GetProcessHeap(), 0, dataW );
1072 return RtlNtStatusToDosError( status );
1076 /******************************************************************************
1077 * RegSetValueW [ADVAPI32.@]
1079 * Sets the data for the default or unnamed value of a reg key.
1081 * PARAMS
1082 * hKey [I] Handle to an open key.
1083 * lpSubKey [I] Name of a subkey of hKey.
1084 * dwType [I] Type of information to store.
1085 * lpData [I] String that contains the data to set for the default value.
1086 * cbData [I] Ignored.
1088 * RETURNS
1089 * Success: ERROR_SUCCESS
1090 * Failure: nonzero error code from Winerror.h
1092 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1094 HKEY subkey = hkey;
1095 DWORD ret;
1097 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1099 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1101 if (name && name[0]) /* need to create the subkey */
1103 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1106 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1107 (strlenW( data ) + 1) * sizeof(WCHAR) );
1108 if (subkey != hkey) RegCloseKey( subkey );
1109 return ret;
1113 /******************************************************************************
1114 * RegSetValueA [ADVAPI32.@]
1116 * See RegSetValueW.
1118 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1120 HKEY subkey = hkey;
1121 DWORD ret;
1123 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1125 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1127 if (name && name[0]) /* need to create the subkey */
1129 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1131 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1132 if (subkey != hkey) RegCloseKey( subkey );
1133 return ret;
1138 /******************************************************************************
1139 * RegQueryValueExW [ADVAPI32.@]
1141 * See RegQueryValueExA.
1143 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1144 LPBYTE data, LPDWORD count )
1146 NTSTATUS status;
1147 UNICODE_STRING name_str;
1148 DWORD total_size;
1149 char buffer[256], *buf_ptr = buffer;
1150 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1151 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1153 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1154 hkey, debugstr_w(name), reserved, type, data, count,
1155 (count && data) ? *count : 0 );
1157 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1158 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1160 RtlInitUnicodeString( &name_str, name );
1162 if (data) total_size = min( sizeof(buffer), *count + info_size );
1163 else
1165 total_size = info_size;
1166 if (count) *count = 0;
1169 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1170 buffer, total_size, &total_size );
1171 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1173 if (data)
1175 /* retry with a dynamically allocated buffer */
1176 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1178 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1179 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1180 return ERROR_NOT_ENOUGH_MEMORY;
1181 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1182 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1183 buf_ptr, total_size, &total_size );
1186 if (!status)
1188 memcpy( data, buf_ptr + info_size, total_size - info_size );
1189 /* if the type is REG_SZ and data is not 0-terminated
1190 * and there is enough space in the buffer NT appends a \0 */
1191 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1193 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1194 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1197 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1199 else status = STATUS_SUCCESS;
1201 if (type) *type = info->Type;
1202 if (count) *count = total_size - info_size;
1204 done:
1205 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1206 return RtlNtStatusToDosError(status);
1210 /******************************************************************************
1211 * RegQueryValueExA [ADVAPI32.@]
1213 * Get the type and contents of a specified value under with a key.
1215 * PARAMS
1216 * hkey [I] Handle of the key to query
1217 * name [I] Name of value under hkey to query
1218 * reserved [I] Reserved - must be NULL
1219 * type [O] Destination for the value type, or NULL if not required
1220 * data [O] Destination for the values contents, or NULL if not required
1221 * count [I/O] Size of data, updated with the number of bytes returned
1223 * RETURNS
1224 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1225 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1226 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1227 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1229 * NOTES
1230 * MSDN states that if data is too small it is partially filled. In reality
1231 * it remains untouched.
1233 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1234 LPBYTE data, LPDWORD count )
1236 NTSTATUS status;
1237 ANSI_STRING nameA;
1238 DWORD total_size, datalen = 0;
1239 char buffer[256], *buf_ptr = buffer;
1240 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1241 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1243 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1244 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1246 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1247 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1249 if (count) datalen = *count;
1250 if (!data && count) *count = 0;
1252 /* this matches Win9x behaviour - NT sets *type to a random value */
1253 if (type) *type = REG_NONE;
1255 RtlInitAnsiString( &nameA, name );
1256 if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1257 &nameA, FALSE )))
1258 return RtlNtStatusToDosError(status);
1260 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1261 KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
1262 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1264 /* we need to fetch the contents for a string type even if not requested,
1265 * because we need to compute the length of the ASCII string. */
1266 if (data || is_string(info->Type))
1268 /* retry with a dynamically allocated buffer */
1269 while (status == STATUS_BUFFER_OVERFLOW)
1271 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1272 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1274 status = STATUS_NO_MEMORY;
1275 goto done;
1277 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1278 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1279 KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1282 if (status) goto done;
1284 if (is_string(info->Type))
1286 DWORD len;
1288 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1289 total_size - info_size );
1290 if (data && len)
1292 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1293 else
1295 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1296 total_size - info_size );
1297 /* if the type is REG_SZ and data is not 0-terminated
1298 * and there is enough space in the buffer NT appends a \0 */
1299 if (len < datalen && data[len-1]) data[len] = 0;
1302 total_size = len + info_size;
1304 else if (data)
1306 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1307 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1310 else status = STATUS_SUCCESS;
1312 if (type) *type = info->Type;
1313 if (count) *count = total_size - info_size;
1315 done:
1316 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1317 return RtlNtStatusToDosError(status);
1321 /******************************************************************************
1322 * RegQueryValueW [ADVAPI32.@]
1324 * Retrieves the data associated with the default or unnamed value of a key.
1326 * PARAMS
1327 * hkey [I] Handle to an open key.
1328 * name [I] Name of the subkey of hKey.
1329 * data [O] Receives the string associated with the default value
1330 * of the key.
1331 * count [I/O] Size of lpValue in bytes.
1333 * RETURNS
1334 * Success: ERROR_SUCCESS
1335 * Failure: nonzero error code from Winerror.h
1337 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1339 DWORD ret;
1340 HKEY subkey = hkey;
1342 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1344 if (name && name[0])
1346 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1348 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1349 if (subkey != hkey) RegCloseKey( subkey );
1350 if (ret == ERROR_FILE_NOT_FOUND)
1352 /* return empty string if default value not found */
1353 if (data) *data = 0;
1354 if (count) *count = sizeof(WCHAR);
1355 ret = ERROR_SUCCESS;
1357 return ret;
1361 /******************************************************************************
1362 * RegQueryValueA [ADVAPI32.@]
1364 * See RegQueryValueW.
1366 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1368 DWORD ret;
1369 HKEY subkey = hkey;
1371 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1373 if (name && name[0])
1375 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1377 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1378 if (subkey != hkey) RegCloseKey( subkey );
1379 if (ret == ERROR_FILE_NOT_FOUND)
1381 /* return empty string if default value not found */
1382 if (data) *data = 0;
1383 if (count) *count = 1;
1384 ret = ERROR_SUCCESS;
1386 return ret;
1390 /******************************************************************************
1391 * ADVAPI_ApplyRestrictions [internal]
1393 * Helper function for RegGetValueA/W.
1395 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1396 DWORD cbData, PLONG ret )
1398 /* Check if the type is restricted by the passed flags */
1399 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1401 DWORD dwMask = 0;
1403 switch (dwType)
1405 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1406 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1407 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1408 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1409 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1410 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1411 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1414 if (dwFlags & dwMask)
1416 /* Type is not restricted, check for size mismatch */
1417 if (dwType == REG_BINARY)
1419 DWORD cbExpect = 0;
1421 if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD)
1422 cbExpect = 4;
1423 else if ((dwFlags & RRF_RT_QWORD) == RRF_RT_QWORD)
1424 cbExpect = 8;
1426 if (cbExpect && cbData != cbExpect)
1427 *ret = ERROR_DATATYPE_MISMATCH;
1430 else *ret = ERROR_UNSUPPORTED_TYPE;
1435 /******************************************************************************
1436 * RegGetValueW [ADVAPI32.@]
1438 * Retrieves the type and data for a value name associated with a key,
1439 * optionally expanding its content and restricting its type.
1441 * PARAMS
1442 * hKey [I] Handle to an open key.
1443 * pszSubKey [I] Name of the subkey of hKey.
1444 * pszValue [I] Name of value under hKey/szSubKey to query.
1445 * dwFlags [I] Flags restricting the value type to retrieve.
1446 * pdwType [O] Destination for the values type, may be NULL.
1447 * pvData [O] Destination for the values content, may be NULL.
1448 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1449 * retrieve the whole content, including the trailing '\0'
1450 * for strings.
1452 * RETURNS
1453 * Success: ERROR_SUCCESS
1454 * Failure: nonzero error code from Winerror.h
1456 * NOTES
1457 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1458 * expanded and pdwType is set to REG_SZ instead.
1459 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1460 * without RRF_NOEXPAND is thus not allowed.
1461 * An exception is the case where RRF_RT_ANY is specified, because then
1462 * RRF_NOEXPAND is allowed.
1464 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1465 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1466 LPDWORD pcbData )
1468 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1469 PVOID pvBuf = NULL;
1470 LONG ret;
1472 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1473 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1474 pvData, pcbData, cbData);
1476 if (pvData && !pcbData)
1477 return ERROR_INVALID_PARAMETER;
1478 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1479 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1480 return ERROR_INVALID_PARAMETER;
1482 if (pszSubKey && pszSubKey[0])
1484 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1485 if (ret != ERROR_SUCCESS) return ret;
1488 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1490 /* If we are going to expand we need to read in the whole the value even
1491 * if the passed buffer was too small as the expanded string might be
1492 * smaller than the unexpanded one and could fit into cbData bytes. */
1493 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1494 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1496 do {
1497 HeapFree(GetProcessHeap(), 0, pvBuf);
1499 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1500 if (!pvBuf)
1502 ret = ERROR_NOT_ENOUGH_MEMORY;
1503 break;
1506 if (ret == ERROR_MORE_DATA || !pvData)
1507 ret = RegQueryValueExW(hKey, pszValue, NULL,
1508 &dwType, pvBuf, &cbData);
1509 else
1511 /* Even if cbData was large enough we have to copy the
1512 * string since ExpandEnvironmentStrings can't handle
1513 * overlapping buffers. */
1514 CopyMemory(pvBuf, pvData, cbData);
1517 /* Both the type or the value itself could have been modified in
1518 * between so we have to keep retrying until the buffer is large
1519 * enough or we no longer have to expand the value. */
1520 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1522 if (ret == ERROR_SUCCESS)
1524 /* Recheck dwType in case it changed since the first call */
1525 if (dwType == REG_EXPAND_SZ)
1527 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1528 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1529 dwType = REG_SZ;
1530 if(pvData && pcbData && cbData > *pcbData)
1531 ret = ERROR_MORE_DATA;
1533 else if (pvData)
1534 CopyMemory(pvData, pvBuf, *pcbData);
1537 HeapFree(GetProcessHeap(), 0, pvBuf);
1540 if (pszSubKey && pszSubKey[0])
1541 RegCloseKey(hKey);
1543 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1545 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1546 ZeroMemory(pvData, *pcbData);
1548 if (pdwType) *pdwType = dwType;
1549 if (pcbData) *pcbData = cbData;
1551 return ret;
1555 /******************************************************************************
1556 * RegGetValueA [ADVAPI32.@]
1558 * See RegGetValueW.
1560 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1561 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1562 LPDWORD pcbData )
1564 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1565 PVOID pvBuf = NULL;
1566 LONG ret;
1568 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1569 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1570 cbData);
1572 if (pvData && !pcbData)
1573 return ERROR_INVALID_PARAMETER;
1574 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1575 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1576 return ERROR_INVALID_PARAMETER;
1578 if (pszSubKey && pszSubKey[0])
1580 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1581 if (ret != ERROR_SUCCESS) return ret;
1584 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1586 /* If we are going to expand we need to read in the whole the value even
1587 * if the passed buffer was too small as the expanded string might be
1588 * smaller than the unexpanded one and could fit into cbData bytes. */
1589 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1590 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1592 do {
1593 HeapFree(GetProcessHeap(), 0, pvBuf);
1595 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1596 if (!pvBuf)
1598 ret = ERROR_NOT_ENOUGH_MEMORY;
1599 break;
1602 if (ret == ERROR_MORE_DATA || !pvData)
1603 ret = RegQueryValueExA(hKey, pszValue, NULL,
1604 &dwType, pvBuf, &cbData);
1605 else
1607 /* Even if cbData was large enough we have to copy the
1608 * string since ExpandEnvironmentStrings can't handle
1609 * overlapping buffers. */
1610 CopyMemory(pvBuf, pvData, cbData);
1613 /* Both the type or the value itself could have been modified in
1614 * between so we have to keep retrying until the buffer is large
1615 * enough or we no longer have to expand the value. */
1616 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1618 if (ret == ERROR_SUCCESS)
1620 /* Recheck dwType in case it changed since the first call */
1621 if (dwType == REG_EXPAND_SZ)
1623 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1624 pcbData ? *pcbData : 0);
1625 dwType = REG_SZ;
1626 if(pvData && pcbData && cbData > *pcbData)
1627 ret = ERROR_MORE_DATA;
1629 else if (pvData)
1630 CopyMemory(pvData, pvBuf, *pcbData);
1633 HeapFree(GetProcessHeap(), 0, pvBuf);
1636 if (pszSubKey && pszSubKey[0])
1637 RegCloseKey(hKey);
1639 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1641 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1642 ZeroMemory(pvData, *pcbData);
1644 if (pdwType) *pdwType = dwType;
1645 if (pcbData) *pcbData = cbData;
1647 return ret;
1651 /******************************************************************************
1652 * RegEnumValueW [ADVAPI32.@]
1654 * Enumerates the values for the specified open registry key.
1656 * PARAMS
1657 * hkey [I] Handle to key to query
1658 * index [I] Index of value to query
1659 * value [O] Value string
1660 * val_count [I/O] Size of value buffer (in wchars)
1661 * reserved [I] Reserved
1662 * type [O] Type code
1663 * data [O] Value data
1664 * count [I/O] Size of data buffer (in bytes)
1666 * RETURNS
1667 * Success: ERROR_SUCCESS
1668 * Failure: nonzero error code from Winerror.h
1671 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1672 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1674 NTSTATUS status;
1675 DWORD total_size;
1676 char buffer[256], *buf_ptr = buffer;
1677 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1678 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1680 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1681 hkey, index, value, val_count, reserved, type, data, count );
1683 /* NT only checks count, not val_count */
1684 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1685 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1687 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1688 if (data) total_size += *count;
1689 total_size = min( sizeof(buffer), total_size );
1691 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1692 buffer, total_size, &total_size );
1693 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1695 if (value || data)
1697 /* retry with a dynamically allocated buffer */
1698 while (status == STATUS_BUFFER_OVERFLOW)
1700 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1701 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1702 return ERROR_NOT_ENOUGH_MEMORY;
1703 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1704 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1705 buf_ptr, total_size, &total_size );
1708 if (status) goto done;
1710 if (value)
1712 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1714 status = STATUS_BUFFER_OVERFLOW;
1715 goto overflow;
1717 memcpy( value, info->Name, info->NameLength );
1718 *val_count = info->NameLength / sizeof(WCHAR);
1719 value[*val_count] = 0;
1722 if (data)
1724 if (total_size - info->DataOffset > *count)
1726 status = STATUS_BUFFER_OVERFLOW;
1727 goto overflow;
1729 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1730 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1732 /* if the type is REG_SZ and data is not 0-terminated
1733 * and there is enough space in the buffer NT appends a \0 */
1734 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1735 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1739 else status = STATUS_SUCCESS;
1741 overflow:
1742 if (type) *type = info->Type;
1743 if (count) *count = info->DataLength;
1745 done:
1746 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1747 return RtlNtStatusToDosError(status);
1751 /******************************************************************************
1752 * RegEnumValueA [ADVAPI32.@]
1754 * See RegEnumValueW.
1756 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1757 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1759 NTSTATUS status;
1760 DWORD total_size;
1761 char buffer[256], *buf_ptr = buffer;
1762 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1763 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1765 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1766 hkey, index, value, val_count, reserved, type, data, count );
1768 /* NT only checks count, not val_count */
1769 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1770 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1772 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1773 if (data) total_size += *count;
1774 total_size = min( sizeof(buffer), total_size );
1776 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1777 buffer, total_size, &total_size );
1778 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1780 /* we need to fetch the contents for a string type even if not requested,
1781 * because we need to compute the length of the ASCII string. */
1782 if (value || data || is_string(info->Type))
1784 /* retry with a dynamically allocated buffer */
1785 while (status == STATUS_BUFFER_OVERFLOW)
1787 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1788 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1789 return ERROR_NOT_ENOUGH_MEMORY;
1790 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1791 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1792 buf_ptr, total_size, &total_size );
1795 if (status) goto done;
1797 if (is_string(info->Type))
1799 DWORD len;
1800 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1801 total_size - info->DataOffset );
1802 if (data && len)
1804 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1805 else
1807 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1808 total_size - info->DataOffset );
1809 /* if the type is REG_SZ and data is not 0-terminated
1810 * and there is enough space in the buffer NT appends a \0 */
1811 if (len < *count && data[len-1]) data[len] = 0;
1814 info->DataLength = len;
1816 else if (data)
1818 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1819 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1822 if (value && !status)
1824 DWORD len;
1826 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1827 if (len >= *val_count)
1829 status = STATUS_BUFFER_OVERFLOW;
1830 if (*val_count)
1832 len = *val_count - 1;
1833 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1834 value[len] = 0;
1837 else
1839 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1840 value[len] = 0;
1841 *val_count = len;
1845 else status = STATUS_SUCCESS;
1847 if (type) *type = info->Type;
1848 if (count) *count = info->DataLength;
1850 done:
1851 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1852 return RtlNtStatusToDosError(status);
1857 /******************************************************************************
1858 * RegDeleteValueW [ADVAPI32.@]
1860 * See RegDeleteValueA.
1862 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1864 UNICODE_STRING nameW;
1866 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1868 RtlInitUnicodeString( &nameW, name );
1869 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1873 /******************************************************************************
1874 * RegDeleteValueA [ADVAPI32.@]
1876 * Delete a value from the registry.
1878 * PARAMS
1879 * hkey [I] Registry handle of the key holding the value
1880 * name [I] Name of the value under hkey to delete
1882 * RETURNS
1883 * Success: ERROR_SUCCESS
1884 * Failure: nonzero error code from Winerror.h
1886 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1888 STRING nameA;
1889 NTSTATUS status;
1891 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1893 RtlInitAnsiString( &nameA, name );
1894 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1895 &nameA, FALSE )))
1896 status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1897 return RtlNtStatusToDosError( status );
1901 /******************************************************************************
1902 * RegLoadKeyW [ADVAPI32.@]
1904 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1905 * registration information from a specified file into that subkey.
1907 * PARAMS
1908 * hkey [I] Handle of open key
1909 * subkey [I] Address of name of subkey
1910 * filename [I] Address of filename for registry information
1912 * RETURNS
1913 * Success: ERROR_SUCCESS
1914 * Failure: nonzero error code from Winerror.h
1916 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1918 OBJECT_ATTRIBUTES destkey, file;
1919 UNICODE_STRING subkeyW, filenameW;
1920 NTSTATUS status;
1922 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
1924 destkey.Length = sizeof(destkey);
1925 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
1926 destkey.ObjectName = &subkeyW; /* name of the key */
1927 destkey.Attributes = 0;
1928 destkey.SecurityDescriptor = NULL;
1929 destkey.SecurityQualityOfService = NULL;
1930 RtlInitUnicodeString(&subkeyW, subkey);
1932 file.Length = sizeof(file);
1933 file.RootDirectory = NULL;
1934 file.ObjectName = &filenameW; /* file containing the hive */
1935 file.Attributes = OBJ_CASE_INSENSITIVE;
1936 file.SecurityDescriptor = NULL;
1937 file.SecurityQualityOfService = NULL;
1938 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
1940 status = NtLoadKey(&destkey, &file);
1941 RtlFreeUnicodeString(&filenameW);
1942 return RtlNtStatusToDosError( status );
1946 /******************************************************************************
1947 * RegLoadKeyA [ADVAPI32.@]
1949 * See RegLoadKeyW.
1951 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1953 UNICODE_STRING subkeyW, filenameW;
1954 STRING subkeyA, filenameA;
1955 NTSTATUS status;
1956 LONG ret;
1958 RtlInitAnsiString(&subkeyA, subkey);
1959 RtlInitAnsiString(&filenameA, filename);
1961 RtlInitUnicodeString(&subkeyW, NULL);
1962 RtlInitUnicodeString(&filenameW, NULL);
1963 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
1964 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
1966 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
1968 else ret = RtlNtStatusToDosError(status);
1969 RtlFreeUnicodeString(&subkeyW);
1970 RtlFreeUnicodeString(&filenameW);
1971 return ret;
1975 /******************************************************************************
1976 * RegSaveKeyW [ADVAPI32.@]
1978 * Save a key and all of its subkeys and values to a new file in the standard format.
1980 * PARAMS
1981 * hkey [I] Handle of key where save begins
1982 * lpFile [I] Address of filename to save to
1983 * sa [I] Address of security structure
1985 * RETURNS
1986 * Success: ERROR_SUCCESS
1987 * Failure: nonzero error code from Winerror.h
1989 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1991 static const WCHAR format[] =
1992 {'r','e','g','%','0','4','x','.','t','m','p',0};
1993 WCHAR buffer[MAX_PATH];
1994 int count = 0;
1995 LPWSTR nameW;
1996 DWORD ret, err;
1997 HANDLE handle;
1999 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2001 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2002 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2004 err = GetLastError();
2005 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2007 for (;;)
2009 snprintfW( nameW, 16, format, count++ );
2010 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2011 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2012 if (handle != INVALID_HANDLE_VALUE) break;
2013 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2015 /* Something gone haywire ? Please report if this happens abnormally */
2016 if (count >= 100)
2017 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);
2020 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2022 CloseHandle( handle );
2023 if (!ret)
2025 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2027 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2028 debugstr_w(file) );
2029 ret = GetLastError();
2032 if (ret) DeleteFileW( buffer );
2034 done:
2035 SetLastError( err ); /* restore last error code */
2036 return ret;
2040 /******************************************************************************
2041 * RegSaveKeyA [ADVAPI32.@]
2043 * See RegSaveKeyW.
2045 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2047 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2048 NTSTATUS status;
2049 STRING fileA;
2051 RtlInitAnsiString(&fileA, file);
2052 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2053 return RtlNtStatusToDosError( status );
2054 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2058 /******************************************************************************
2059 * RegRestoreKeyW [ADVAPI32.@]
2061 * Read the registry information from a file and copy it over a key.
2063 * PARAMS
2064 * hkey [I] Handle of key where restore begins
2065 * lpFile [I] Address of filename containing saved tree
2066 * dwFlags [I] Optional flags
2068 * RETURNS
2069 * Success: ERROR_SUCCESS
2070 * Failure: nonzero error code from Winerror.h
2072 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2074 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2076 /* It seems to do this check before the hkey check */
2077 if (!lpFile || !*lpFile)
2078 return ERROR_INVALID_PARAMETER;
2080 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2082 /* Check for file existence */
2084 return ERROR_SUCCESS;
2088 /******************************************************************************
2089 * RegRestoreKeyA [ADVAPI32.@]
2091 * See RegRestoreKeyW.
2093 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2095 UNICODE_STRING lpFileW;
2096 LONG ret;
2098 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2099 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2100 RtlFreeUnicodeString( &lpFileW );
2101 return ret;
2105 /******************************************************************************
2106 * RegUnLoadKeyW [ADVAPI32.@]
2108 * Unload a registry key and its subkeys from the registry.
2110 * PARAMS
2111 * hkey [I] Handle of open key
2112 * lpSubKey [I] Address of name of subkey to unload
2114 * RETURNS
2115 * Success: ERROR_SUCCESS
2116 * Failure: nonzero error code from Winerror.h
2118 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2120 DWORD ret;
2121 HKEY shkey;
2122 OBJECT_ATTRIBUTES attr;
2123 UNICODE_STRING subkey;
2125 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2127 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2128 if( ret )
2129 return ERROR_INVALID_PARAMETER;
2131 RtlInitUnicodeString(&subkey, lpSubKey);
2132 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2133 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2135 RegCloseKey(shkey);
2137 return ret;
2141 /******************************************************************************
2142 * RegUnLoadKeyA [ADVAPI32.@]
2144 * See RegUnLoadKeyW.
2146 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2148 UNICODE_STRING lpSubKeyW;
2149 LONG ret;
2151 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2152 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2153 RtlFreeUnicodeString( &lpSubKeyW );
2154 return ret;
2158 /******************************************************************************
2159 * RegReplaceKeyW [ADVAPI32.@]
2161 * Replace the file backing a registry key and all its subkeys with another file.
2163 * PARAMS
2164 * hkey [I] Handle of open key
2165 * lpSubKey [I] Address of name of subkey
2166 * lpNewFile [I] Address of filename for file with new data
2167 * lpOldFile [I] Address of filename for backup file
2169 * RETURNS
2170 * Success: ERROR_SUCCESS
2171 * Failure: nonzero error code from Winerror.h
2173 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2174 LPCWSTR lpOldFile )
2176 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2177 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2178 return ERROR_SUCCESS;
2182 /******************************************************************************
2183 * RegReplaceKeyA [ADVAPI32.@]
2185 * See RegReplaceKeyW.
2187 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2188 LPCSTR lpOldFile )
2190 UNICODE_STRING lpSubKeyW;
2191 UNICODE_STRING lpNewFileW;
2192 UNICODE_STRING lpOldFileW;
2193 LONG ret;
2195 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2196 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2197 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2198 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2199 RtlFreeUnicodeString( &lpOldFileW );
2200 RtlFreeUnicodeString( &lpNewFileW );
2201 RtlFreeUnicodeString( &lpSubKeyW );
2202 return ret;
2206 /******************************************************************************
2207 * RegSetKeySecurity [ADVAPI32.@]
2209 * Set the security of an open registry key.
2211 * PARAMS
2212 * hkey [I] Open handle of key to set
2213 * SecurityInfo [I] Descriptor contents
2214 * pSecurityDesc [I] Address of descriptor for key
2216 * RETURNS
2217 * Success: ERROR_SUCCESS
2218 * Failure: nonzero error code from Winerror.h
2220 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2221 PSECURITY_DESCRIPTOR pSecurityDesc )
2223 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2225 /* It seems to perform this check before the hkey check */
2226 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2227 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2228 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2229 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2230 /* Param OK */
2231 } else
2232 return ERROR_INVALID_PARAMETER;
2234 if (!pSecurityDesc)
2235 return ERROR_INVALID_PARAMETER;
2237 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2239 return ERROR_SUCCESS;
2243 /******************************************************************************
2244 * RegGetKeySecurity [ADVAPI32.@]
2246 * Get a copy of the security descriptor for a given registry key.
2248 * PARAMS
2249 * hkey [I] Open handle of key to set
2250 * SecurityInformation [I] Descriptor contents
2251 * pSecurityDescriptor [O] Address of descriptor for key
2252 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2254 * RETURNS
2255 * Success: ERROR_SUCCESS
2256 * Failure: Error code
2258 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2259 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2260 LPDWORD lpcbSecurityDescriptor )
2262 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2263 *lpcbSecurityDescriptor);
2265 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2267 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2268 SecurityInformation, pSecurityDescriptor,
2269 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2273 /******************************************************************************
2274 * RegFlushKey [ADVAPI32.@]
2276 * Immediately write a registry key to registry.
2278 * PARAMS
2279 * hkey [I] Handle of key to write
2281 * RETURNS
2282 * Success: ERROR_SUCCESS
2283 * Failure: Error code
2285 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2287 hkey = get_special_root_hkey( hkey );
2288 if (!hkey) return ERROR_INVALID_HANDLE;
2290 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2294 /******************************************************************************
2295 * RegConnectRegistryW [ADVAPI32.@]
2297 * Establish a connection to a predefined registry key on another computer.
2299 * PARAMS
2300 * lpMachineName [I] Address of name of remote computer
2301 * hHey [I] Predefined registry handle
2302 * phkResult [I] Address of buffer for remote registry handle
2304 * RETURNS
2305 * Success: ERROR_SUCCESS
2306 * Failure: nonzero error code from Winerror.h
2308 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2309 PHKEY phkResult )
2311 LONG ret;
2313 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2315 if (!lpMachineName || !*lpMachineName) {
2316 /* Use the local machine name */
2317 ret = RegOpenKeyW( hKey, NULL, phkResult );
2319 else {
2320 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2321 DWORD len = sizeof(compName) / sizeof(WCHAR);
2323 /* MSDN says lpMachineName must start with \\ : not so */
2324 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2325 lpMachineName += 2;
2326 if (GetComputerNameW(compName, &len))
2328 if (!strcmpiW(lpMachineName, compName))
2329 ret = RegOpenKeyW(hKey, NULL, phkResult);
2330 else
2332 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2333 ret = ERROR_BAD_NETPATH;
2336 else
2337 ret = GetLastError();
2339 return ret;
2343 /******************************************************************************
2344 * RegConnectRegistryA [ADVAPI32.@]
2346 * See RegConnectRegistryW.
2348 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2350 UNICODE_STRING machineW;
2351 LONG ret;
2353 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2354 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2355 RtlFreeUnicodeString( &machineW );
2356 return ret;
2360 /******************************************************************************
2361 * RegNotifyChangeKeyValue [ADVAPI32.@]
2363 * Notify the caller about changes to the attributes or contents of a registry key.
2365 * PARAMS
2366 * hkey [I] Handle of key to watch
2367 * fWatchSubTree [I] Flag for subkey notification
2368 * fdwNotifyFilter [I] Changes to be reported
2369 * hEvent [I] Handle of signaled event
2370 * fAsync [I] Flag for asynchronous reporting
2372 * RETURNS
2373 * Success: ERROR_SUCCESS
2374 * Failure: nonzero error code from Winerror.h
2376 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2377 DWORD fdwNotifyFilter, HANDLE hEvent,
2378 BOOL fAsync )
2380 NTSTATUS status;
2381 IO_STATUS_BLOCK iosb;
2383 hkey = get_special_root_hkey( hkey );
2384 if (!hkey) return ERROR_INVALID_HANDLE;
2386 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2387 hEvent, fAsync);
2389 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2390 fdwNotifyFilter, fAsync, NULL, 0,
2391 fWatchSubTree);
2393 if (status && status != STATUS_TIMEOUT)
2394 return RtlNtStatusToDosError( status );
2396 return ERROR_SUCCESS;
2399 /******************************************************************************
2400 * RegOpenUserClassesRoot [ADVAPI32.@]
2402 * Open the HKEY_CLASSES_ROOT key for a user.
2404 * PARAMS
2405 * hToken [I] Handle of token representing the user
2406 * dwOptions [I] Reserved, must be 0
2407 * samDesired [I] Desired access rights
2408 * phkResult [O] Destination for the resulting key handle
2410 * RETURNS
2411 * Success: ERROR_SUCCESS
2412 * Failure: nonzero error code from Winerror.h
2414 * NOTES
2415 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2416 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2417 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2419 LSTATUS WINAPI RegOpenUserClassesRoot(
2420 HANDLE hToken,
2421 DWORD dwOptions,
2422 REGSAM samDesired,
2423 PHKEY phkResult
2426 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2428 *phkResult = HKEY_CLASSES_ROOT;
2429 return ERROR_SUCCESS;
2432 /******************************************************************************
2433 * load_string [Internal]
2435 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2436 * avoid importing user32, which is higher level than advapi32. Helper for
2437 * RegLoadMUIString.
2439 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2441 HGLOBAL hMemory;
2442 HRSRC hResource;
2443 WCHAR *pString;
2444 int idxString;
2446 /* Negative values have to be inverted. */
2447 if (HIWORD(resId) == 0xffff)
2448 resId = (UINT)(-((INT)resId));
2450 /* Load the resource into memory and get a pointer to it. */
2451 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2452 if (!hResource) return 0;
2453 hMemory = LoadResource(hModule, hResource);
2454 if (!hMemory) return 0;
2455 pString = LockResource(hMemory);
2457 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2458 idxString = resId & 0xf;
2459 while (idxString--) pString += *pString + 1;
2461 /* If no buffer is given, return length of the string. */
2462 if (!pwszBuffer) return *pString;
2464 /* Else copy over the string, respecting the buffer size. */
2465 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2466 if (cMaxChars >= 0) {
2467 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2468 pwszBuffer[cMaxChars] = '\0';
2471 return cMaxChars;
2474 /******************************************************************************
2475 * RegLoadMUIStringW [ADVAPI32.@]
2477 * Load the localized version of a string resource from some PE, respective
2478 * id and path of which are given in the registry value in the format
2479 * @[path]\dllname,-resourceId
2481 * PARAMS
2482 * hKey [I] Key, of which to load the string value from.
2483 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2484 * pszBuffer [O] Buffer to store the localized string in.
2485 * cbBuffer [I] Size of the destination buffer in bytes.
2486 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2487 * dwFlags [I] None supported yet.
2488 * pszBaseDir [I] Not supported yet.
2490 * RETURNS
2491 * Success: ERROR_SUCCESS,
2492 * Failure: nonzero error code from winerror.h
2494 * NOTES
2495 * This is an API of Windows Vista, which wasn't available at the time this code
2496 * was written. We have to check for the correct behaviour once it's available.
2498 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2499 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2501 DWORD dwValueType, cbData;
2502 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2503 LONG result;
2505 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2506 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2507 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2509 /* Parameter sanity checks. */
2510 if (!hKey || !pwszBuffer)
2511 return ERROR_INVALID_PARAMETER;
2513 if (pwszBaseDir && *pwszBaseDir) {
2514 FIXME("BaseDir parameter not yet supported!\n");
2515 return ERROR_INVALID_PARAMETER;
2518 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2519 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2520 if (result != ERROR_SUCCESS) goto cleanup;
2521 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2522 result = ERROR_FILE_NOT_FOUND;
2523 goto cleanup;
2525 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2526 if (!pwszTempBuffer) {
2527 result = ERROR_NOT_ENOUGH_MEMORY;
2528 goto cleanup;
2530 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2531 if (result != ERROR_SUCCESS) goto cleanup;
2533 /* Expand environment variables, if appropriate, or copy the original string over. */
2534 if (dwValueType == REG_EXPAND_SZ) {
2535 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2536 if (!cbData) goto cleanup;
2537 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2538 if (!pwszExpandedBuffer) {
2539 result = ERROR_NOT_ENOUGH_MEMORY;
2540 goto cleanup;
2542 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2543 } else {
2544 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2545 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2548 /* If the value references a resource based string, parse the value and load the string.
2549 * Else just copy over the original value. */
2550 result = ERROR_SUCCESS;
2551 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2552 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2553 } else {
2554 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2555 UINT uiStringId;
2556 HMODULE hModule;
2558 /* Format of the expanded value is 'path_to_dll,-resId' */
2559 if (!pComma || pComma[1] != '-') {
2560 result = ERROR_BADKEY;
2561 goto cleanup;
2564 uiStringId = atoiW(pComma+2);
2565 *pComma = '\0';
2567 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2568 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2569 result = ERROR_BADKEY;
2570 FreeLibrary(hModule);
2573 cleanup:
2574 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2575 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2576 return result;
2579 /******************************************************************************
2580 * RegLoadMUIStringA [ADVAPI32.@]
2582 * See RegLoadMUIStringW
2584 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2585 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2587 UNICODE_STRING valueW, baseDirW;
2588 WCHAR *pwszBuffer;
2589 DWORD cbData = cbBuffer * sizeof(WCHAR);
2590 LONG result;
2592 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2593 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2594 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2595 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2597 result = ERROR_NOT_ENOUGH_MEMORY;
2598 goto cleanup;
2601 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2602 baseDirW.Buffer);
2604 if (result == ERROR_SUCCESS) {
2605 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2606 if (pcbData)
2607 *pcbData = cbData;
2610 cleanup:
2611 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2612 RtlFreeUnicodeString(&baseDirW);
2613 RtlFreeUnicodeString(&valueW);
2615 return result;
2618 /******************************************************************************
2619 * RegDisablePredefinedCache [ADVAPI32.@]
2621 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2623 * PARAMS
2624 * None.
2626 * RETURNS
2627 * Success: ERROR_SUCCESS
2628 * Failure: nonzero error code from Winerror.h
2630 * NOTES
2631 * This is useful for services that use impersonation.
2633 LSTATUS WINAPI RegDisablePredefinedCache(void)
2635 HKEY hkey_current_user;
2636 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2638 /* prevent caching of future requests */
2639 hkcu_cache_disabled = TRUE;
2641 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2643 if (hkey_current_user)
2644 NtClose( hkey_current_user );
2646 return ERROR_SUCCESS;
2649 /******************************************************************************
2650 * RegDeleteTreeW [ADVAPI32.@]
2653 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2655 LONG ret;
2656 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2657 DWORD dwMaxLen, dwSize;
2658 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2659 HKEY hSubKey = hKey;
2661 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2663 if(lpszSubKey)
2665 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2666 if (ret) return ret;
2669 /* Get highest length for keys, values */
2670 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2671 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2672 if (ret) goto cleanup;
2674 dwMaxSubkeyLen++;
2675 dwMaxValueLen++;
2676 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2677 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2679 /* Name too big: alloc a buffer for it */
2680 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2682 ret = ERROR_NOT_ENOUGH_MEMORY;
2683 goto cleanup;
2688 /* Recursively delete all the subkeys */
2689 while (TRUE)
2691 dwSize = dwMaxLen;
2692 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2693 NULL, NULL, NULL)) break;
2695 ret = RegDeleteTreeW(hSubKey, lpszName);
2696 if (ret) goto cleanup;
2699 if (lpszSubKey)
2700 ret = RegDeleteKeyW(hKey, lpszSubKey);
2701 else
2702 while (TRUE)
2704 dwSize = dwMaxLen;
2705 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2706 NULL, NULL, NULL, NULL)) break;
2708 ret = RegDeleteValueW(hKey, lpszName);
2709 if (ret) goto cleanup;
2712 cleanup:
2713 /* Free buffer if allocated */
2714 if (lpszName != szNameBuf)
2715 HeapFree( GetProcessHeap(), 0, lpszName);
2716 if(lpszSubKey)
2717 RegCloseKey(hSubKey);
2718 return ret;
2721 /******************************************************************************
2722 * RegDeleteTreeA [ADVAPI32.@]
2725 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2727 LONG ret;
2728 UNICODE_STRING lpszSubKeyW;
2730 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2731 else lpszSubKeyW.Buffer = NULL;
2732 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2733 RtlFreeUnicodeString( &lpszSubKeyW );
2734 return ret;