push 87b6981010d7405c33b14cddcceec21b47729eba
[wine/hacks.git] / dlls / advapi32 / registry.c
blob84320d11006f24900b1171d0fcfe1e9862daa2c3
1 /*
2 * Registry management
4 * Copyright (C) 1999 Alexandre Julliard
6 * Based on misc/registry.c code
7 * Copyright (C) 1996 Marcus Meissner
8 * Copyright (C) 1998 Matthew Becker
9 * Copyright (C) 1999 Sylvain St-Germain
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <stdio.h>
30 #include "ntstatus.h"
31 #define WIN32_NO_STATUS
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winreg.h"
35 #include "winerror.h"
36 #include "winternl.h"
37 #include "winuser.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(reg);
44 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
45 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
46 #define NB_SPECIAL_ROOT_KEYS ((UINT_PTR)HKEY_SPECIAL_ROOT_LAST - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST + 1)
48 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
49 static BOOL hkcu_cache_disabled;
51 static const WCHAR name_CLASSES_ROOT[] =
52 {'M','a','c','h','i','n','e','\\',
53 'S','o','f','t','w','a','r','e','\\',
54 'C','l','a','s','s','e','s',0};
55 static const WCHAR name_LOCAL_MACHINE[] =
56 {'M','a','c','h','i','n','e',0};
57 static const WCHAR name_USERS[] =
58 {'U','s','e','r',0};
59 static const WCHAR name_PERFORMANCE_DATA[] =
60 {'P','e','r','f','D','a','t','a',0};
61 static const WCHAR name_CURRENT_CONFIG[] =
62 {'M','a','c','h','i','n','e','\\',
63 'S','y','s','t','e','m','\\',
64 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
65 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
66 'C','u','r','r','e','n','t',0};
67 static const WCHAR name_DYN_DATA[] =
68 {'D','y','n','D','a','t','a',0};
70 static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] =
72 name_CLASSES_ROOT,
73 NULL, /* HKEY_CURRENT_USER is determined dynamically */
74 name_LOCAL_MACHINE,
75 name_USERS,
76 name_PERFORMANCE_DATA,
77 name_CURRENT_CONFIG,
78 name_DYN_DATA
82 /* check if value type needs string conversion (Ansi<->Unicode) */
83 static inline int is_string( DWORD type )
85 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
88 /* check if current version is NT or Win95 */
89 static inline int is_version_nt(void)
91 return !(GetVersion() & 0x80000000);
94 /* create one of the HKEY_* special root keys */
95 static HKEY create_special_root_hkey( HANDLE hkey, DWORD access )
97 HKEY ret = 0;
98 int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
100 if (hkey == HKEY_CURRENT_USER)
102 if (RtlOpenCurrentUser( access, &hkey )) return 0;
103 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
105 /* don't cache the key in the table if caching is disabled */
106 if (hkcu_cache_disabled)
107 return hkey;
109 else
111 OBJECT_ATTRIBUTES attr;
112 UNICODE_STRING name;
114 attr.Length = sizeof(attr);
115 attr.RootDirectory = 0;
116 attr.ObjectName = &name;
117 attr.Attributes = 0;
118 attr.SecurityDescriptor = NULL;
119 attr.SecurityQualityOfService = NULL;
120 RtlInitUnicodeString( &name, root_key_names[idx] );
121 if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
122 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
125 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
126 ret = hkey;
127 else
128 NtClose( hkey ); /* somebody beat us to it */
129 return ret;
132 /* map the hkey from special root to normal key if necessary */
133 static inline HKEY get_special_root_hkey( HKEY hkey )
135 HKEY ret = hkey;
137 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
139 if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
140 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED );
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 = MAXIMUM_ALLOWED; /* 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 MAXIMUM_ALLOWED, 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 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
299 /******************************************************************************
300 * RegOpenKeyExW [ADVAPI32.@]
302 * See RegOpenKeyExA.
304 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
306 OBJECT_ATTRIBUTES attr;
307 UNICODE_STRING nameW;
309 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
310 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
312 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
314 attr.Length = sizeof(attr);
315 attr.RootDirectory = hkey;
316 attr.ObjectName = &nameW;
317 attr.Attributes = 0;
318 attr.SecurityDescriptor = NULL;
319 attr.SecurityQualityOfService = NULL;
320 RtlInitUnicodeString( &nameW, name );
321 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE)retkey, access, &attr ) );
325 /******************************************************************************
326 * RegOpenKeyExA [ADVAPI32.@]
328 * Open a registry key.
330 * PARAMS
331 * hkey [I] Handle of open key
332 * name [I] Name of subkey to open
333 * reserved [I] Reserved - must be zero
334 * access [I] Security access mask
335 * retkey [O] Handle to open key
337 * RETURNS
338 * Success: ERROR_SUCCESS
339 * Failure: A standard Win32 error code. retkey is set to 0.
341 * NOTES
342 * Unlike RegCreateKeyExA(), this function will not create the key if it
343 * does not exist.
345 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
347 OBJECT_ATTRIBUTES attr;
348 STRING nameA;
349 NTSTATUS status;
351 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
352 else
354 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
355 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
358 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
360 attr.Length = sizeof(attr);
361 attr.RootDirectory = hkey;
362 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
363 attr.Attributes = 0;
364 attr.SecurityDescriptor = NULL;
365 attr.SecurityQualityOfService = NULL;
367 RtlInitAnsiString( &nameA, name );
368 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
369 &nameA, FALSE )))
371 status = NtOpenKey( (PHANDLE)retkey, access, &attr );
373 return RtlNtStatusToDosError( status );
377 /******************************************************************************
378 * RegOpenKeyW [ADVAPI32.@]
380 * See RegOpenKeyA.
382 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
384 if (!retkey)
385 return ERROR_INVALID_PARAMETER;
387 if (!name || !*name)
389 *retkey = hkey;
390 return ERROR_SUCCESS;
392 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
396 /******************************************************************************
397 * RegOpenKeyA [ADVAPI32.@]
399 * Open a registry key.
401 * PARAMS
402 * hkey [I] Handle of parent key to open the new key under
403 * name [I] Name of the key under hkey to open
404 * retkey [O] Destination for the resulting Handle
406 * RETURNS
407 * Success: ERROR_SUCCESS
408 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
410 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
412 if (!retkey)
413 return ERROR_INVALID_PARAMETER;
415 if (!name || !*name)
417 *retkey = hkey;
418 return ERROR_SUCCESS;
420 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
424 /******************************************************************************
425 * RegOpenCurrentUser [ADVAPI32.@]
427 * Get a handle to the HKEY_CURRENT_USER key for the user
428 * the current thread is impersonating.
430 * PARAMS
431 * access [I] Desired access rights to the key
432 * retkey [O] Handle to the opened key
434 * RETURNS
435 * Success: ERROR_SUCCESS
436 * Failure: nonzero error code from Winerror.h
438 * FIXME
439 * This function is supposed to retrieve a handle to the
440 * HKEY_CURRENT_USER for the user the current thread is impersonating.
441 * Since Wine does not currently allow threads to impersonate other users,
442 * this stub should work fine.
444 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
446 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
451 /******************************************************************************
452 * RegEnumKeyExW [ADVAPI32.@]
454 * Enumerate subkeys of the specified open registry key.
456 * PARAMS
457 * hkey [I] Handle to key to enumerate
458 * index [I] Index of subkey to enumerate
459 * name [O] Buffer for subkey name
460 * name_len [O] Size of subkey buffer
461 * reserved [I] Reserved
462 * class [O] Buffer for class string
463 * class_len [O] Size of class buffer
464 * ft [O] Time key last written to
466 * RETURNS
467 * Success: ERROR_SUCCESS
468 * Failure: System error code. If there are no more subkeys available, the
469 * function returns ERROR_NO_MORE_ITEMS.
471 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
472 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
474 NTSTATUS status;
475 char buffer[256], *buf_ptr = buffer;
476 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
477 DWORD total_size;
479 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
480 name_len ? *name_len : 0, reserved, class, class_len, ft );
482 if (reserved) return ERROR_INVALID_PARAMETER;
483 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
485 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
486 buffer, sizeof(buffer), &total_size );
488 while (status == STATUS_BUFFER_OVERFLOW)
490 /* retry with a dynamically allocated buffer */
491 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
492 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
493 return ERROR_NOT_ENOUGH_MEMORY;
494 info = (KEY_NODE_INFORMATION *)buf_ptr;
495 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
496 buf_ptr, total_size, &total_size );
499 if (!status)
501 DWORD len = info->NameLength / sizeof(WCHAR);
502 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
504 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
506 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
507 status = STATUS_BUFFER_OVERFLOW;
508 else
510 *name_len = len;
511 memcpy( name, info->Name, info->NameLength );
512 name[len] = 0;
513 if (class_len)
515 *class_len = cls_len;
516 if (class)
518 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
519 class[cls_len] = 0;
525 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
526 return RtlNtStatusToDosError( status );
530 /******************************************************************************
531 * RegEnumKeyExA [ADVAPI32.@]
533 * See RegEnumKeyExW.
535 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
536 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
538 NTSTATUS status;
539 char buffer[256], *buf_ptr = buffer;
540 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
541 DWORD total_size;
543 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
544 name_len ? *name_len : 0, reserved, class, class_len, ft );
546 if (reserved) return ERROR_INVALID_PARAMETER;
547 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
549 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
550 buffer, sizeof(buffer), &total_size );
552 while (status == STATUS_BUFFER_OVERFLOW)
554 /* retry with a dynamically allocated buffer */
555 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
556 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
557 return ERROR_NOT_ENOUGH_MEMORY;
558 info = (KEY_NODE_INFORMATION *)buf_ptr;
559 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
560 buf_ptr, total_size, &total_size );
563 if (!status)
565 DWORD len, cls_len;
567 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
568 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
569 info->ClassLength );
570 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
572 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
573 status = STATUS_BUFFER_OVERFLOW;
574 else
576 *name_len = len;
577 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
578 name[len] = 0;
579 if (class_len)
581 *class_len = cls_len;
582 if (class)
584 RtlUnicodeToMultiByteN( class, cls_len, NULL,
585 (WCHAR *)(buf_ptr + info->ClassOffset),
586 info->ClassLength );
587 class[cls_len] = 0;
593 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
594 return RtlNtStatusToDosError( status );
598 /******************************************************************************
599 * RegEnumKeyW [ADVAPI32.@]
601 * Enumerates subkeys of the specified open reg key.
603 * PARAMS
604 * hKey [I] Handle to an open key.
605 * dwIndex [I] Index of the subkey of hKey to retrieve.
606 * lpName [O] Name of the subkey.
607 * cchName [I] Size of lpName in TCHARS.
609 * RETURNS
610 * Success: ERROR_SUCCESS
611 * Failure: system error code. If there are no more subkeys available, the
612 * function returns ERROR_NO_MORE_ITEMS.
614 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
616 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
620 /******************************************************************************
621 * RegEnumKeyA [ADVAPI32.@]
623 * See RegEnumKeyW.
625 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
627 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
631 /******************************************************************************
632 * RegQueryInfoKeyW [ADVAPI32.@]
634 * Retrieves information about the specified registry key.
636 * PARAMS
637 * hkey [I] Handle to key to query
638 * class [O] Buffer for class string
639 * class_len [O] Size of class string buffer
640 * reserved [I] Reserved
641 * subkeys [O] Buffer for number of subkeys
642 * max_subkey [O] Buffer for longest subkey name length
643 * max_class [O] Buffer for longest class string length
644 * values [O] Buffer for number of value entries
645 * max_value [O] Buffer for longest value name length
646 * max_data [O] Buffer for longest value data length
647 * security [O] Buffer for security descriptor length
648 * modif [O] Modification time
650 * RETURNS
651 * Success: ERROR_SUCCESS
652 * Failure: system error code.
654 * NOTES
655 * - win95 allows class to be valid and class_len to be NULL
656 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
657 * - both allow class to be NULL and class_len to be NULL
658 * (it's hard to test validity, so test !NULL instead)
660 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
661 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
662 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
663 LPDWORD security, FILETIME *modif )
665 NTSTATUS status;
666 char buffer[256], *buf_ptr = buffer;
667 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
668 DWORD total_size;
670 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
671 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
673 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
674 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
676 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
677 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
679 if (class)
681 /* retry with a dynamically allocated buffer */
682 while (status == STATUS_BUFFER_OVERFLOW)
684 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
685 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
686 return ERROR_NOT_ENOUGH_MEMORY;
687 info = (KEY_FULL_INFORMATION *)buf_ptr;
688 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
691 if (status) goto done;
693 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
695 status = STATUS_BUFFER_OVERFLOW;
697 else
699 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
700 class[info->ClassLength/sizeof(WCHAR)] = 0;
703 else status = STATUS_SUCCESS;
705 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
706 if (subkeys) *subkeys = info->SubKeys;
707 if (max_subkey) *max_subkey = info->MaxNameLen;
708 if (max_class) *max_class = info->MaxClassLen;
709 if (values) *values = info->Values;
710 if (max_value) *max_value = info->MaxValueNameLen;
711 if (max_data) *max_data = info->MaxValueDataLen;
712 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
714 done:
715 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
716 return RtlNtStatusToDosError( status );
720 /******************************************************************************
721 * RegQueryMultipleValuesA [ADVAPI32.@]
723 * Retrieves the type and data for a list of value names associated with a key.
725 * PARAMS
726 * hKey [I] Handle to an open key.
727 * val_list [O] Array of VALENT structures that describes the entries.
728 * num_vals [I] Number of elements in val_list.
729 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
730 * ldwTotsize [I/O] Size of lpValueBuf.
732 * RETURNS
733 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
734 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
735 * bytes.
737 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
738 LPSTR lpValueBuf, LPDWORD ldwTotsize )
740 unsigned int i;
741 DWORD maxBytes = *ldwTotsize;
742 HRESULT status;
743 LPSTR bufptr = lpValueBuf;
744 *ldwTotsize = 0;
746 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
748 for(i=0; i < num_vals; ++i)
751 val_list[i].ve_valuelen=0;
752 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
753 if(status != ERROR_SUCCESS)
755 return status;
758 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
760 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
761 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
762 if(status != ERROR_SUCCESS)
764 return status;
767 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
769 bufptr += val_list[i].ve_valuelen;
772 *ldwTotsize += val_list[i].ve_valuelen;
774 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
778 /******************************************************************************
779 * RegQueryMultipleValuesW [ADVAPI32.@]
781 * See RegQueryMultipleValuesA.
783 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
784 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
786 unsigned int i;
787 DWORD maxBytes = *ldwTotsize;
788 HRESULT status;
789 LPSTR bufptr = (LPSTR)lpValueBuf;
790 *ldwTotsize = 0;
792 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
794 for(i=0; i < num_vals; ++i)
796 val_list[i].ve_valuelen=0;
797 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
798 if(status != ERROR_SUCCESS)
800 return status;
803 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
805 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
806 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
807 if(status != ERROR_SUCCESS)
809 return status;
812 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
814 bufptr += val_list[i].ve_valuelen;
817 *ldwTotsize += val_list[i].ve_valuelen;
819 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
822 /******************************************************************************
823 * RegQueryInfoKeyA [ADVAPI32.@]
825 * Retrieves information about a registry key.
827 * PARAMS
828 * hKey [I] Handle to an open key.
829 * lpClass [O] Class string of the key.
830 * lpcClass [I/O] size of lpClass.
831 * lpReserved [I] Reserved; must be NULL.
832 * lpcSubKeys [O] Number of subkeys contained by the key.
833 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
834 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
835 * class in TCHARS.
836 * lpcValues [O] Number of values associated with the key.
837 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
838 * lpcMaxValueLen [O] Longest data component among the key's values
839 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
840 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
842 * RETURNS
843 * Success: ERROR_SUCCESS
844 * Failure: nonzero error code from Winerror.h
846 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
847 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
848 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
849 LPDWORD security, FILETIME *modif )
851 NTSTATUS status;
852 char buffer[256], *buf_ptr = buffer;
853 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
854 DWORD total_size, len;
856 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
857 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
859 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
860 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
862 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
863 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
865 if (class || class_len)
867 /* retry with a dynamically allocated buffer */
868 while (status == STATUS_BUFFER_OVERFLOW)
870 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
871 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
872 return ERROR_NOT_ENOUGH_MEMORY;
873 info = (KEY_FULL_INFORMATION *)buf_ptr;
874 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
877 if (status) goto done;
879 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
880 if (class_len)
882 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
883 *class_len = len;
885 if (class && !status)
887 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
888 info->ClassLength );
889 class[len] = 0;
892 else status = STATUS_SUCCESS;
894 if (subkeys) *subkeys = info->SubKeys;
895 if (max_subkey) *max_subkey = info->MaxNameLen;
896 if (max_class) *max_class = info->MaxClassLen;
897 if (values) *values = info->Values;
898 if (max_value) *max_value = info->MaxValueNameLen;
899 if (max_data) *max_data = info->MaxValueDataLen;
900 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
902 done:
903 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
904 return RtlNtStatusToDosError( status );
908 /******************************************************************************
909 * RegCloseKey [ADVAPI32.@]
911 * Close an open registry key.
913 * PARAMS
914 * hkey [I] Handle of key to close
916 * RETURNS
917 * Success: ERROR_SUCCESS
918 * Failure: Error code
920 LSTATUS WINAPI RegCloseKey( HKEY hkey )
922 if (!hkey) return ERROR_INVALID_HANDLE;
923 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
924 return RtlNtStatusToDosError( NtClose( hkey ) );
928 /******************************************************************************
929 * RegDeleteKeyW [ADVAPI32.@]
931 * See RegDeleteKeyA.
933 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
935 DWORD ret;
936 HKEY tmp;
938 if (!name) return ERROR_INVALID_PARAMETER;
940 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
942 if (!(ret = RegOpenKeyExW( hkey, name, 0, DELETE, &tmp )))
944 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
945 RegCloseKey( tmp );
947 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
948 return ret;
952 /******************************************************************************
953 * RegDeleteKeyA [ADVAPI32.@]
955 * Delete a registry key.
957 * PARAMS
958 * hkey [I] Handle to parent key containing the key to delete
959 * name [I] Name of the key user hkey to delete
961 * NOTES
963 * MSDN is wrong when it says that hkey must be opened with the DELETE access
964 * right. In reality, it opens a new handle with DELETE access.
966 * RETURNS
967 * Success: ERROR_SUCCESS
968 * Failure: Error code
970 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
972 DWORD ret;
973 HKEY tmp;
975 if (!name) return ERROR_INVALID_PARAMETER;
977 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
979 if (!(ret = RegOpenKeyExA( hkey, name, 0, DELETE, &tmp )))
981 if (!is_version_nt()) /* win95 does recursive key deletes */
983 CHAR name[MAX_PATH];
985 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
987 if(RegDeleteKeyA(tmp, name)) /* recurse */
988 break;
991 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
992 RegCloseKey( tmp );
994 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
995 return ret;
1000 /******************************************************************************
1001 * RegSetValueExW [ADVAPI32.@]
1003 * Set the data and contents of a registry value.
1005 * PARAMS
1006 * hkey [I] Handle of key to set value for
1007 * name [I] Name of value to set
1008 * reserved [I] Reserved, must be zero
1009 * type [I] Type of the value being set
1010 * data [I] The new contents of the value to set
1011 * count [I] Size of data
1013 * RETURNS
1014 * Success: ERROR_SUCCESS
1015 * Failure: Error code
1017 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1018 DWORD type, CONST BYTE *data, DWORD count )
1020 UNICODE_STRING nameW;
1022 /* no need for version check, not implemented on win9x anyway */
1023 if (count && is_string(type))
1025 LPCWSTR str = (LPCWSTR)data;
1026 /* if user forgot to count terminating null, add it (yes NT does this) */
1027 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1028 count += sizeof(WCHAR);
1030 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1032 RtlInitUnicodeString( &nameW, name );
1033 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1037 /******************************************************************************
1038 * RegSetValueExA [ADVAPI32.@]
1040 * See RegSetValueExW.
1042 * NOTES
1043 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1044 * NT does definitely care (aj)
1046 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1047 CONST BYTE *data, DWORD count )
1049 ANSI_STRING nameA;
1050 WCHAR *dataW = NULL;
1051 NTSTATUS status;
1053 if (!is_version_nt()) /* win95 */
1055 if (type == REG_SZ)
1057 if (!data) return ERROR_INVALID_PARAMETER;
1058 count = strlen((const char *)data) + 1;
1061 else if (count && is_string(type))
1063 /* if user forgot to count terminating null, add it (yes NT does this) */
1064 if (data[count-1] && !data[count]) count++;
1067 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1069 if (is_string( type )) /* need to convert to Unicode */
1071 DWORD lenW;
1072 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1073 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1074 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1075 count = lenW;
1076 data = (BYTE *)dataW;
1079 RtlInitAnsiString( &nameA, name );
1080 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1081 &nameA, FALSE )))
1083 status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
1085 HeapFree( GetProcessHeap(), 0, dataW );
1086 return RtlNtStatusToDosError( status );
1090 /******************************************************************************
1091 * RegSetValueW [ADVAPI32.@]
1093 * Sets the data for the default or unnamed value of a reg key.
1095 * PARAMS
1096 * hKey [I] Handle to an open key.
1097 * lpSubKey [I] Name of a subkey of hKey.
1098 * dwType [I] Type of information to store.
1099 * lpData [I] String that contains the data to set for the default value.
1100 * cbData [I] Ignored.
1102 * RETURNS
1103 * Success: ERROR_SUCCESS
1104 * Failure: nonzero error code from Winerror.h
1106 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1108 HKEY subkey = hkey;
1109 DWORD ret;
1111 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1113 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1115 if (name && name[0]) /* need to create the subkey */
1117 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1120 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1121 (strlenW( data ) + 1) * sizeof(WCHAR) );
1122 if (subkey != hkey) RegCloseKey( subkey );
1123 return ret;
1127 /******************************************************************************
1128 * RegSetValueA [ADVAPI32.@]
1130 * See RegSetValueW.
1132 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1134 HKEY subkey = hkey;
1135 DWORD ret;
1137 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1139 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1141 if (name && name[0]) /* need to create the subkey */
1143 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1145 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1146 if (subkey != hkey) RegCloseKey( subkey );
1147 return ret;
1152 /******************************************************************************
1153 * RegQueryValueExW [ADVAPI32.@]
1155 * See RegQueryValueExA.
1157 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1158 LPBYTE data, LPDWORD count )
1160 NTSTATUS status;
1161 UNICODE_STRING name_str;
1162 DWORD total_size;
1163 char buffer[256], *buf_ptr = buffer;
1164 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1165 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1167 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1168 hkey, debugstr_w(name), reserved, type, data, count,
1169 (count && data) ? *count : 0 );
1171 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1172 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1174 RtlInitUnicodeString( &name_str, name );
1176 if (data) total_size = min( sizeof(buffer), *count + info_size );
1177 else
1179 total_size = info_size;
1180 if (count) *count = 0;
1183 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1184 buffer, total_size, &total_size );
1185 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1187 if (data)
1189 /* retry with a dynamically allocated buffer */
1190 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1192 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1193 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1194 return ERROR_NOT_ENOUGH_MEMORY;
1195 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1196 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1197 buf_ptr, total_size, &total_size );
1200 if (!status)
1202 memcpy( data, buf_ptr + info_size, total_size - info_size );
1203 /* if the type is REG_SZ and data is not 0-terminated
1204 * and there is enough space in the buffer NT appends a \0 */
1205 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1207 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1208 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1211 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1213 else status = STATUS_SUCCESS;
1215 if (type) *type = info->Type;
1216 if (count) *count = total_size - info_size;
1218 done:
1219 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1220 return RtlNtStatusToDosError(status);
1224 /******************************************************************************
1225 * RegQueryValueExA [ADVAPI32.@]
1227 * Get the type and contents of a specified value under with a key.
1229 * PARAMS
1230 * hkey [I] Handle of the key to query
1231 * name [I] Name of value under hkey to query
1232 * reserved [I] Reserved - must be NULL
1233 * type [O] Destination for the value type, or NULL if not required
1234 * data [O] Destination for the values contents, or NULL if not required
1235 * count [I/O] Size of data, updated with the number of bytes returned
1237 * RETURNS
1238 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1239 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1240 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1241 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1243 * NOTES
1244 * MSDN states that if data is too small it is partially filled. In reality
1245 * it remains untouched.
1247 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1248 LPBYTE data, LPDWORD count )
1250 NTSTATUS status;
1251 ANSI_STRING nameA;
1252 DWORD total_size, datalen = 0;
1253 char buffer[256], *buf_ptr = buffer;
1254 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1255 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1257 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1258 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1260 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1261 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1263 if (count) datalen = *count;
1264 if (!data && count) *count = 0;
1266 /* this matches Win9x behaviour - NT sets *type to a random value */
1267 if (type) *type = REG_NONE;
1269 RtlInitAnsiString( &nameA, name );
1270 if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1271 &nameA, FALSE )))
1272 return RtlNtStatusToDosError(status);
1274 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1275 KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
1276 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1278 /* we need to fetch the contents for a string type even if not requested,
1279 * because we need to compute the length of the ASCII string. */
1280 if (data || is_string(info->Type))
1282 /* retry with a dynamically allocated buffer */
1283 while (status == STATUS_BUFFER_OVERFLOW)
1285 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1286 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1288 status = STATUS_NO_MEMORY;
1289 goto done;
1291 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1292 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1293 KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1296 if (status) goto done;
1298 if (is_string(info->Type))
1300 DWORD len;
1302 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1303 total_size - info_size );
1304 if (data && len)
1306 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1307 else
1309 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1310 total_size - info_size );
1311 /* if the type is REG_SZ and data is not 0-terminated
1312 * and there is enough space in the buffer NT appends a \0 */
1313 if (len < datalen && data[len-1]) data[len] = 0;
1316 total_size = len + info_size;
1318 else if (data)
1320 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1321 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1324 else status = STATUS_SUCCESS;
1326 if (type) *type = info->Type;
1327 if (count) *count = total_size - info_size;
1329 done:
1330 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1331 return RtlNtStatusToDosError(status);
1335 /******************************************************************************
1336 * RegQueryValueW [ADVAPI32.@]
1338 * Retrieves the data associated with the default or unnamed value of a key.
1340 * PARAMS
1341 * hkey [I] Handle to an open key.
1342 * name [I] Name of the subkey of hKey.
1343 * data [O] Receives the string associated with the default value
1344 * of the key.
1345 * count [I/O] Size of lpValue in bytes.
1347 * RETURNS
1348 * Success: ERROR_SUCCESS
1349 * Failure: nonzero error code from Winerror.h
1351 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1353 DWORD ret;
1354 HKEY subkey = hkey;
1356 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1358 if (name && name[0])
1360 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1362 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1363 if (subkey != hkey) RegCloseKey( subkey );
1364 if (ret == ERROR_FILE_NOT_FOUND)
1366 /* return empty string if default value not found */
1367 if (data) *data = 0;
1368 if (count) *count = sizeof(WCHAR);
1369 ret = ERROR_SUCCESS;
1371 return ret;
1375 /******************************************************************************
1376 * RegQueryValueA [ADVAPI32.@]
1378 * See RegQueryValueW.
1380 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1382 DWORD ret;
1383 HKEY subkey = hkey;
1385 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1387 if (name && name[0])
1389 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1391 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1392 if (subkey != hkey) RegCloseKey( subkey );
1393 if (ret == ERROR_FILE_NOT_FOUND)
1395 /* return empty string if default value not found */
1396 if (data) *data = 0;
1397 if (count) *count = 1;
1398 ret = ERROR_SUCCESS;
1400 return ret;
1404 /******************************************************************************
1405 * ADVAPI_ApplyRestrictions [internal]
1407 * Helper function for RegGetValueA/W.
1409 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1410 DWORD cbData, PLONG ret )
1412 /* Check if the type is restricted by the passed flags */
1413 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1415 DWORD dwMask = 0;
1417 switch (dwType)
1419 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1420 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1421 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1422 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1423 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1424 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1425 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1428 if (dwFlags & dwMask)
1430 /* Type is not restricted, check for size mismatch */
1431 if (dwType == REG_BINARY)
1433 DWORD cbExpect = 0;
1435 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1436 cbExpect = 4;
1437 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1438 cbExpect = 8;
1440 if (cbExpect && cbData != cbExpect)
1441 *ret = ERROR_DATATYPE_MISMATCH;
1444 else *ret = ERROR_UNSUPPORTED_TYPE;
1449 /******************************************************************************
1450 * RegGetValueW [ADVAPI32.@]
1452 * Retrieves the type and data for a value name associated with a key,
1453 * optionally expanding its content and restricting its type.
1455 * PARAMS
1456 * hKey [I] Handle to an open key.
1457 * pszSubKey [I] Name of the subkey of hKey.
1458 * pszValue [I] Name of value under hKey/szSubKey to query.
1459 * dwFlags [I] Flags restricting the value type to retrieve.
1460 * pdwType [O] Destination for the values type, may be NULL.
1461 * pvData [O] Destination for the values content, may be NULL.
1462 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1463 * retrieve the whole content, including the trailing '\0'
1464 * for strings.
1466 * RETURNS
1467 * Success: ERROR_SUCCESS
1468 * Failure: nonzero error code from Winerror.h
1470 * NOTES
1471 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1472 * expanded and pdwType is set to REG_SZ instead.
1473 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1474 * without RRF_NOEXPAND is thus not allowed.
1475 * An exception is the case where RRF_RT_ANY is specified, because then
1476 * RRF_NOEXPAND is allowed.
1478 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1479 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1480 LPDWORD pcbData )
1482 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1483 PVOID pvBuf = NULL;
1484 LONG ret;
1486 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1487 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1488 pvData, pcbData, cbData);
1490 if (pvData && !pcbData)
1491 return ERROR_INVALID_PARAMETER;
1492 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1493 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1494 return ERROR_INVALID_PARAMETER;
1496 if (pszSubKey && pszSubKey[0])
1498 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1499 if (ret != ERROR_SUCCESS) return ret;
1502 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1504 /* If we are going to expand we need to read in the whole the value even
1505 * if the passed buffer was too small as the expanded string might be
1506 * smaller than the unexpanded one and could fit into cbData bytes. */
1507 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1508 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1510 do {
1511 HeapFree(GetProcessHeap(), 0, pvBuf);
1513 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1514 if (!pvBuf)
1516 ret = ERROR_NOT_ENOUGH_MEMORY;
1517 break;
1520 if (ret == ERROR_MORE_DATA || !pvData)
1521 ret = RegQueryValueExW(hKey, pszValue, NULL,
1522 &dwType, pvBuf, &cbData);
1523 else
1525 /* Even if cbData was large enough we have to copy the
1526 * string since ExpandEnvironmentStrings can't handle
1527 * overlapping buffers. */
1528 CopyMemory(pvBuf, pvData, cbData);
1531 /* Both the type or the value itself could have been modified in
1532 * between so we have to keep retrying until the buffer is large
1533 * enough or we no longer have to expand the value. */
1534 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1536 if (ret == ERROR_SUCCESS)
1538 /* Recheck dwType in case it changed since the first call */
1539 if (dwType == REG_EXPAND_SZ)
1541 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1542 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1543 dwType = REG_SZ;
1544 if(pvData && pcbData && cbData > *pcbData)
1545 ret = ERROR_MORE_DATA;
1547 else if (pvData)
1548 CopyMemory(pvData, pvBuf, *pcbData);
1551 HeapFree(GetProcessHeap(), 0, pvBuf);
1554 if (pszSubKey && pszSubKey[0])
1555 RegCloseKey(hKey);
1557 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1559 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1560 ZeroMemory(pvData, *pcbData);
1562 if (pdwType) *pdwType = dwType;
1563 if (pcbData) *pcbData = cbData;
1565 return ret;
1569 /******************************************************************************
1570 * RegGetValueA [ADVAPI32.@]
1572 * See RegGetValueW.
1574 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1575 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1576 LPDWORD pcbData )
1578 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1579 PVOID pvBuf = NULL;
1580 LONG ret;
1582 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1583 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1584 cbData);
1586 if (pvData && !pcbData)
1587 return ERROR_INVALID_PARAMETER;
1588 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1589 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1590 return ERROR_INVALID_PARAMETER;
1592 if (pszSubKey && pszSubKey[0])
1594 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1595 if (ret != ERROR_SUCCESS) return ret;
1598 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1600 /* If we are going to expand we need to read in the whole the value even
1601 * if the passed buffer was too small as the expanded string might be
1602 * smaller than the unexpanded one and could fit into cbData bytes. */
1603 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1604 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1606 do {
1607 HeapFree(GetProcessHeap(), 0, pvBuf);
1609 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1610 if (!pvBuf)
1612 ret = ERROR_NOT_ENOUGH_MEMORY;
1613 break;
1616 if (ret == ERROR_MORE_DATA || !pvData)
1617 ret = RegQueryValueExA(hKey, pszValue, NULL,
1618 &dwType, pvBuf, &cbData);
1619 else
1621 /* Even if cbData was large enough we have to copy the
1622 * string since ExpandEnvironmentStrings can't handle
1623 * overlapping buffers. */
1624 CopyMemory(pvBuf, pvData, cbData);
1627 /* Both the type or the value itself could have been modified in
1628 * between so we have to keep retrying until the buffer is large
1629 * enough or we no longer have to expand the value. */
1630 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1632 if (ret == ERROR_SUCCESS)
1634 /* Recheck dwType in case it changed since the first call */
1635 if (dwType == REG_EXPAND_SZ)
1637 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1638 pcbData ? *pcbData : 0);
1639 dwType = REG_SZ;
1640 if(pvData && pcbData && cbData > *pcbData)
1641 ret = ERROR_MORE_DATA;
1643 else if (pvData)
1644 CopyMemory(pvData, pvBuf, *pcbData);
1647 HeapFree(GetProcessHeap(), 0, pvBuf);
1650 if (pszSubKey && pszSubKey[0])
1651 RegCloseKey(hKey);
1653 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1655 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1656 ZeroMemory(pvData, *pcbData);
1658 if (pdwType) *pdwType = dwType;
1659 if (pcbData) *pcbData = cbData;
1661 return ret;
1665 /******************************************************************************
1666 * RegEnumValueW [ADVAPI32.@]
1668 * Enumerates the values for the specified open registry key.
1670 * PARAMS
1671 * hkey [I] Handle to key to query
1672 * index [I] Index of value to query
1673 * value [O] Value string
1674 * val_count [I/O] Size of value buffer (in wchars)
1675 * reserved [I] Reserved
1676 * type [O] Type code
1677 * data [O] Value data
1678 * count [I/O] Size of data buffer (in bytes)
1680 * RETURNS
1681 * Success: ERROR_SUCCESS
1682 * Failure: nonzero error code from Winerror.h
1685 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1686 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1688 NTSTATUS status;
1689 DWORD total_size;
1690 char buffer[256], *buf_ptr = buffer;
1691 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1692 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1694 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1695 hkey, index, value, val_count, reserved, type, data, count );
1697 /* NT only checks count, not val_count */
1698 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1699 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1701 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1702 if (data) total_size += *count;
1703 total_size = min( sizeof(buffer), total_size );
1705 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1706 buffer, total_size, &total_size );
1707 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1709 if (value || data)
1711 /* retry with a dynamically allocated buffer */
1712 while (status == STATUS_BUFFER_OVERFLOW)
1714 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1715 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1716 return ERROR_NOT_ENOUGH_MEMORY;
1717 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1718 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1719 buf_ptr, total_size, &total_size );
1722 if (status) goto done;
1724 if (value)
1726 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1728 status = STATUS_BUFFER_OVERFLOW;
1729 goto overflow;
1731 memcpy( value, info->Name, info->NameLength );
1732 *val_count = info->NameLength / sizeof(WCHAR);
1733 value[*val_count] = 0;
1736 if (data)
1738 if (total_size - info->DataOffset > *count)
1740 status = STATUS_BUFFER_OVERFLOW;
1741 goto overflow;
1743 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1744 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1746 /* if the type is REG_SZ and data is not 0-terminated
1747 * and there is enough space in the buffer NT appends a \0 */
1748 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1749 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1753 else status = STATUS_SUCCESS;
1755 overflow:
1756 if (type) *type = info->Type;
1757 if (count) *count = info->DataLength;
1759 done:
1760 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1761 return RtlNtStatusToDosError(status);
1765 /******************************************************************************
1766 * RegEnumValueA [ADVAPI32.@]
1768 * See RegEnumValueW.
1770 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1771 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1773 NTSTATUS status;
1774 DWORD total_size;
1775 char buffer[256], *buf_ptr = buffer;
1776 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1777 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1779 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1780 hkey, index, value, val_count, reserved, type, data, count );
1782 /* NT only checks count, not val_count */
1783 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1784 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1786 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1787 if (data) total_size += *count;
1788 total_size = min( sizeof(buffer), total_size );
1790 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1791 buffer, total_size, &total_size );
1792 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1794 /* we need to fetch the contents for a string type even if not requested,
1795 * because we need to compute the length of the ASCII string. */
1796 if (value || data || is_string(info->Type))
1798 /* retry with a dynamically allocated buffer */
1799 while (status == STATUS_BUFFER_OVERFLOW)
1801 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1802 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1803 return ERROR_NOT_ENOUGH_MEMORY;
1804 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1805 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1806 buf_ptr, total_size, &total_size );
1809 if (status) goto done;
1811 if (is_string(info->Type))
1813 DWORD len;
1814 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1815 total_size - info->DataOffset );
1816 if (data && len)
1818 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1819 else
1821 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1822 total_size - info->DataOffset );
1823 /* if the type is REG_SZ and data is not 0-terminated
1824 * and there is enough space in the buffer NT appends a \0 */
1825 if (len < *count && data[len-1]) data[len] = 0;
1828 info->DataLength = len;
1830 else if (data)
1832 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1833 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1836 if (value && !status)
1838 DWORD len;
1840 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1841 if (len >= *val_count)
1843 status = STATUS_BUFFER_OVERFLOW;
1844 if (*val_count)
1846 len = *val_count - 1;
1847 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1848 value[len] = 0;
1851 else
1853 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1854 value[len] = 0;
1855 *val_count = len;
1859 else status = STATUS_SUCCESS;
1861 if (type) *type = info->Type;
1862 if (count) *count = info->DataLength;
1864 done:
1865 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1866 return RtlNtStatusToDosError(status);
1871 /******************************************************************************
1872 * RegDeleteValueW [ADVAPI32.@]
1874 * See RegDeleteValueA.
1876 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1878 UNICODE_STRING nameW;
1880 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1882 RtlInitUnicodeString( &nameW, name );
1883 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1887 /******************************************************************************
1888 * RegDeleteValueA [ADVAPI32.@]
1890 * Delete a value from the registry.
1892 * PARAMS
1893 * hkey [I] Registry handle of the key holding the value
1894 * name [I] Name of the value under hkey to delete
1896 * RETURNS
1897 * Success: ERROR_SUCCESS
1898 * Failure: nonzero error code from Winerror.h
1900 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1902 STRING nameA;
1903 NTSTATUS status;
1905 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1907 RtlInitAnsiString( &nameA, name );
1908 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1909 &nameA, FALSE )))
1910 status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1911 return RtlNtStatusToDosError( status );
1915 /******************************************************************************
1916 * RegLoadKeyW [ADVAPI32.@]
1918 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1919 * registration information from a specified file into that subkey.
1921 * PARAMS
1922 * hkey [I] Handle of open key
1923 * subkey [I] Address of name of subkey
1924 * filename [I] Address of filename for registry information
1926 * RETURNS
1927 * Success: ERROR_SUCCESS
1928 * Failure: nonzero error code from Winerror.h
1930 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1932 OBJECT_ATTRIBUTES destkey, file;
1933 UNICODE_STRING subkeyW, filenameW;
1934 NTSTATUS status;
1936 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
1938 destkey.Length = sizeof(destkey);
1939 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
1940 destkey.ObjectName = &subkeyW; /* name of the key */
1941 destkey.Attributes = 0;
1942 destkey.SecurityDescriptor = NULL;
1943 destkey.SecurityQualityOfService = NULL;
1944 RtlInitUnicodeString(&subkeyW, subkey);
1946 file.Length = sizeof(file);
1947 file.RootDirectory = NULL;
1948 file.ObjectName = &filenameW; /* file containing the hive */
1949 file.Attributes = OBJ_CASE_INSENSITIVE;
1950 file.SecurityDescriptor = NULL;
1951 file.SecurityQualityOfService = NULL;
1952 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
1954 status = NtLoadKey(&destkey, &file);
1955 RtlFreeUnicodeString(&filenameW);
1956 return RtlNtStatusToDosError( status );
1960 /******************************************************************************
1961 * RegLoadKeyA [ADVAPI32.@]
1963 * See RegLoadKeyW.
1965 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1967 UNICODE_STRING subkeyW, filenameW;
1968 STRING subkeyA, filenameA;
1969 NTSTATUS status;
1970 LONG ret;
1972 RtlInitAnsiString(&subkeyA, subkey);
1973 RtlInitAnsiString(&filenameA, filename);
1975 RtlInitUnicodeString(&subkeyW, NULL);
1976 RtlInitUnicodeString(&filenameW, NULL);
1977 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
1978 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
1980 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
1982 else ret = RtlNtStatusToDosError(status);
1983 RtlFreeUnicodeString(&subkeyW);
1984 RtlFreeUnicodeString(&filenameW);
1985 return ret;
1989 /******************************************************************************
1990 * RegSaveKeyW [ADVAPI32.@]
1992 * Save a key and all of its subkeys and values to a new file in the standard format.
1994 * PARAMS
1995 * hkey [I] Handle of key where save begins
1996 * lpFile [I] Address of filename to save to
1997 * sa [I] Address of security structure
1999 * RETURNS
2000 * Success: ERROR_SUCCESS
2001 * Failure: nonzero error code from Winerror.h
2003 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2005 static const WCHAR format[] =
2006 {'r','e','g','%','0','4','x','.','t','m','p',0};
2007 WCHAR buffer[MAX_PATH];
2008 int count = 0;
2009 LPWSTR nameW;
2010 DWORD ret, err;
2011 HANDLE handle;
2013 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2015 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2016 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2018 err = GetLastError();
2019 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2021 for (;;)
2023 snprintfW( nameW, 16, format, count++ );
2024 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2025 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2026 if (handle != INVALID_HANDLE_VALUE) break;
2027 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2029 /* Something gone haywire ? Please report if this happens abnormally */
2030 if (count >= 100)
2031 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);
2034 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2036 CloseHandle( handle );
2037 if (!ret)
2039 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2041 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2042 debugstr_w(file) );
2043 ret = GetLastError();
2046 if (ret) DeleteFileW( buffer );
2048 done:
2049 SetLastError( err ); /* restore last error code */
2050 return ret;
2054 /******************************************************************************
2055 * RegSaveKeyA [ADVAPI32.@]
2057 * See RegSaveKeyW.
2059 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2061 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2062 NTSTATUS status;
2063 STRING fileA;
2065 RtlInitAnsiString(&fileA, file);
2066 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2067 return RtlNtStatusToDosError( status );
2068 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2072 /******************************************************************************
2073 * RegRestoreKeyW [ADVAPI32.@]
2075 * Read the registry information from a file and copy it over a key.
2077 * PARAMS
2078 * hkey [I] Handle of key where restore begins
2079 * lpFile [I] Address of filename containing saved tree
2080 * dwFlags [I] Optional flags
2082 * RETURNS
2083 * Success: ERROR_SUCCESS
2084 * Failure: nonzero error code from Winerror.h
2086 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2088 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2090 /* It seems to do this check before the hkey check */
2091 if (!lpFile || !*lpFile)
2092 return ERROR_INVALID_PARAMETER;
2094 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2096 /* Check for file existence */
2098 return ERROR_SUCCESS;
2102 /******************************************************************************
2103 * RegRestoreKeyA [ADVAPI32.@]
2105 * See RegRestoreKeyW.
2107 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2109 UNICODE_STRING lpFileW;
2110 LONG ret;
2112 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2113 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2114 RtlFreeUnicodeString( &lpFileW );
2115 return ret;
2119 /******************************************************************************
2120 * RegUnLoadKeyW [ADVAPI32.@]
2122 * Unload a registry key and its subkeys from the registry.
2124 * PARAMS
2125 * hkey [I] Handle of open key
2126 * lpSubKey [I] Address of name of subkey to unload
2128 * RETURNS
2129 * Success: ERROR_SUCCESS
2130 * Failure: nonzero error code from Winerror.h
2132 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2134 DWORD ret;
2135 HKEY shkey;
2136 OBJECT_ATTRIBUTES attr;
2137 UNICODE_STRING subkey;
2139 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2141 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2142 if( ret )
2143 return ERROR_INVALID_PARAMETER;
2145 RtlInitUnicodeString(&subkey, lpSubKey);
2146 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2147 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2149 RegCloseKey(shkey);
2151 return ret;
2155 /******************************************************************************
2156 * RegUnLoadKeyA [ADVAPI32.@]
2158 * See RegUnLoadKeyW.
2160 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2162 UNICODE_STRING lpSubKeyW;
2163 LONG ret;
2165 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2166 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2167 RtlFreeUnicodeString( &lpSubKeyW );
2168 return ret;
2172 /******************************************************************************
2173 * RegReplaceKeyW [ADVAPI32.@]
2175 * Replace the file backing a registry key and all its subkeys with another file.
2177 * PARAMS
2178 * hkey [I] Handle of open key
2179 * lpSubKey [I] Address of name of subkey
2180 * lpNewFile [I] Address of filename for file with new data
2181 * lpOldFile [I] Address of filename for backup file
2183 * RETURNS
2184 * Success: ERROR_SUCCESS
2185 * Failure: nonzero error code from Winerror.h
2187 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2188 LPCWSTR lpOldFile )
2190 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2191 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2192 return ERROR_SUCCESS;
2196 /******************************************************************************
2197 * RegReplaceKeyA [ADVAPI32.@]
2199 * See RegReplaceKeyW.
2201 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2202 LPCSTR lpOldFile )
2204 UNICODE_STRING lpSubKeyW;
2205 UNICODE_STRING lpNewFileW;
2206 UNICODE_STRING lpOldFileW;
2207 LONG ret;
2209 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2210 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2211 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2212 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2213 RtlFreeUnicodeString( &lpOldFileW );
2214 RtlFreeUnicodeString( &lpNewFileW );
2215 RtlFreeUnicodeString( &lpSubKeyW );
2216 return ret;
2220 /******************************************************************************
2221 * RegSetKeySecurity [ADVAPI32.@]
2223 * Set the security of an open registry key.
2225 * PARAMS
2226 * hkey [I] Open handle of key to set
2227 * SecurityInfo [I] Descriptor contents
2228 * pSecurityDesc [I] Address of descriptor for key
2230 * RETURNS
2231 * Success: ERROR_SUCCESS
2232 * Failure: nonzero error code from Winerror.h
2234 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2235 PSECURITY_DESCRIPTOR pSecurityDesc )
2237 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2239 /* It seems to perform this check before the hkey check */
2240 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2241 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2242 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2243 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2244 /* Param OK */
2245 } else
2246 return ERROR_INVALID_PARAMETER;
2248 if (!pSecurityDesc)
2249 return ERROR_INVALID_PARAMETER;
2251 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2253 return ERROR_SUCCESS;
2257 /******************************************************************************
2258 * RegGetKeySecurity [ADVAPI32.@]
2260 * Get a copy of the security descriptor for a given registry key.
2262 * PARAMS
2263 * hkey [I] Open handle of key to set
2264 * SecurityInformation [I] Descriptor contents
2265 * pSecurityDescriptor [O] Address of descriptor for key
2266 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2268 * RETURNS
2269 * Success: ERROR_SUCCESS
2270 * Failure: Error code
2272 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2273 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2274 LPDWORD lpcbSecurityDescriptor )
2276 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2277 *lpcbSecurityDescriptor);
2279 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2281 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2282 SecurityInformation, pSecurityDescriptor,
2283 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2287 /******************************************************************************
2288 * RegFlushKey [ADVAPI32.@]
2290 * Immediately write a registry key to registry.
2292 * PARAMS
2293 * hkey [I] Handle of key to write
2295 * RETURNS
2296 * Success: ERROR_SUCCESS
2297 * Failure: Error code
2299 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2301 hkey = get_special_root_hkey( hkey );
2302 if (!hkey) return ERROR_INVALID_HANDLE;
2304 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2308 /******************************************************************************
2309 * RegConnectRegistryW [ADVAPI32.@]
2311 * Establish a connection to a predefined registry key on another computer.
2313 * PARAMS
2314 * lpMachineName [I] Address of name of remote computer
2315 * hHey [I] Predefined registry handle
2316 * phkResult [I] Address of buffer for remote registry handle
2318 * RETURNS
2319 * Success: ERROR_SUCCESS
2320 * Failure: nonzero error code from Winerror.h
2322 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2323 PHKEY phkResult )
2325 LONG ret;
2327 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2329 if (!lpMachineName || !*lpMachineName) {
2330 /* Use the local machine name */
2331 ret = RegOpenKeyW( hKey, NULL, phkResult );
2333 else {
2334 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2335 DWORD len = sizeof(compName) / sizeof(WCHAR);
2337 /* MSDN says lpMachineName must start with \\ : not so */
2338 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2339 lpMachineName += 2;
2340 if (GetComputerNameW(compName, &len))
2342 if (!strcmpiW(lpMachineName, compName))
2343 ret = RegOpenKeyW(hKey, NULL, phkResult);
2344 else
2346 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2347 ret = ERROR_BAD_NETPATH;
2350 else
2351 ret = GetLastError();
2353 return ret;
2357 /******************************************************************************
2358 * RegConnectRegistryA [ADVAPI32.@]
2360 * See RegConnectRegistryW.
2362 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2364 UNICODE_STRING machineW;
2365 LONG ret;
2367 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2368 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2369 RtlFreeUnicodeString( &machineW );
2370 return ret;
2374 /******************************************************************************
2375 * RegNotifyChangeKeyValue [ADVAPI32.@]
2377 * Notify the caller about changes to the attributes or contents of a registry key.
2379 * PARAMS
2380 * hkey [I] Handle of key to watch
2381 * fWatchSubTree [I] Flag for subkey notification
2382 * fdwNotifyFilter [I] Changes to be reported
2383 * hEvent [I] Handle of signaled event
2384 * fAsync [I] Flag for asynchronous reporting
2386 * RETURNS
2387 * Success: ERROR_SUCCESS
2388 * Failure: nonzero error code from Winerror.h
2390 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2391 DWORD fdwNotifyFilter, HANDLE hEvent,
2392 BOOL fAsync )
2394 NTSTATUS status;
2395 IO_STATUS_BLOCK iosb;
2397 hkey = get_special_root_hkey( hkey );
2398 if (!hkey) return ERROR_INVALID_HANDLE;
2400 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2401 hEvent, fAsync);
2403 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2404 fdwNotifyFilter, fAsync, NULL, 0,
2405 fWatchSubTree);
2407 if (status && status != STATUS_TIMEOUT)
2408 return RtlNtStatusToDosError( status );
2410 return ERROR_SUCCESS;
2413 /******************************************************************************
2414 * RegOpenUserClassesRoot [ADVAPI32.@]
2416 * Open the HKEY_CLASSES_ROOT key for a user.
2418 * PARAMS
2419 * hToken [I] Handle of token representing the user
2420 * dwOptions [I] Reserved, must be 0
2421 * samDesired [I] Desired access rights
2422 * phkResult [O] Destination for the resulting key handle
2424 * RETURNS
2425 * Success: ERROR_SUCCESS
2426 * Failure: nonzero error code from Winerror.h
2428 * NOTES
2429 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2430 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2431 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2433 LSTATUS WINAPI RegOpenUserClassesRoot(
2434 HANDLE hToken,
2435 DWORD dwOptions,
2436 REGSAM samDesired,
2437 PHKEY phkResult
2440 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2442 *phkResult = HKEY_CLASSES_ROOT;
2443 return ERROR_SUCCESS;
2446 /******************************************************************************
2447 * load_string [Internal]
2449 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2450 * avoid importing user32, which is higher level than advapi32. Helper for
2451 * RegLoadMUIString.
2453 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2455 HGLOBAL hMemory;
2456 HRSRC hResource;
2457 WCHAR *pString;
2458 int idxString;
2460 /* Negative values have to be inverted. */
2461 if (HIWORD(resId) == 0xffff)
2462 resId = (UINT)(-((INT)resId));
2464 /* Load the resource into memory and get a pointer to it. */
2465 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2466 if (!hResource) return 0;
2467 hMemory = LoadResource(hModule, hResource);
2468 if (!hMemory) return 0;
2469 pString = LockResource(hMemory);
2471 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2472 idxString = resId & 0xf;
2473 while (idxString--) pString += *pString + 1;
2475 /* If no buffer is given, return length of the string. */
2476 if (!pwszBuffer) return *pString;
2478 /* Else copy over the string, respecting the buffer size. */
2479 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2480 if (cMaxChars >= 0) {
2481 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2482 pwszBuffer[cMaxChars] = '\0';
2485 return cMaxChars;
2488 /******************************************************************************
2489 * RegLoadMUIStringW [ADVAPI32.@]
2491 * Load the localized version of a string resource from some PE, respective
2492 * id and path of which are given in the registry value in the format
2493 * @[path]\dllname,-resourceId
2495 * PARAMS
2496 * hKey [I] Key, of which to load the string value from.
2497 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2498 * pszBuffer [O] Buffer to store the localized string in.
2499 * cbBuffer [I] Size of the destination buffer in bytes.
2500 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2501 * dwFlags [I] None supported yet.
2502 * pszBaseDir [I] Not supported yet.
2504 * RETURNS
2505 * Success: ERROR_SUCCESS,
2506 * Failure: nonzero error code from winerror.h
2508 * NOTES
2509 * This is an API of Windows Vista, which wasn't available at the time this code
2510 * was written. We have to check for the correct behaviour once it's available.
2512 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2513 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2515 DWORD dwValueType, cbData;
2516 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2517 LONG result;
2519 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2520 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2521 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2523 /* Parameter sanity checks. */
2524 if (!hKey || !pwszBuffer)
2525 return ERROR_INVALID_PARAMETER;
2527 if (pwszBaseDir && *pwszBaseDir) {
2528 FIXME("BaseDir parameter not yet supported!\n");
2529 return ERROR_INVALID_PARAMETER;
2532 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2533 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2534 if (result != ERROR_SUCCESS) goto cleanup;
2535 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2536 result = ERROR_FILE_NOT_FOUND;
2537 goto cleanup;
2539 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2540 if (!pwszTempBuffer) {
2541 result = ERROR_NOT_ENOUGH_MEMORY;
2542 goto cleanup;
2544 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2545 if (result != ERROR_SUCCESS) goto cleanup;
2547 /* Expand environment variables, if appropriate, or copy the original string over. */
2548 if (dwValueType == REG_EXPAND_SZ) {
2549 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2550 if (!cbData) goto cleanup;
2551 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2552 if (!pwszExpandedBuffer) {
2553 result = ERROR_NOT_ENOUGH_MEMORY;
2554 goto cleanup;
2556 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2557 } else {
2558 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2559 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2562 /* If the value references a resource based string, parse the value and load the string.
2563 * Else just copy over the original value. */
2564 result = ERROR_SUCCESS;
2565 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2566 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2567 } else {
2568 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2569 UINT uiStringId;
2570 HMODULE hModule;
2572 /* Format of the expanded value is 'path_to_dll,-resId' */
2573 if (!pComma || pComma[1] != '-') {
2574 result = ERROR_BADKEY;
2575 goto cleanup;
2578 uiStringId = atoiW(pComma+2);
2579 *pComma = '\0';
2581 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2582 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2583 result = ERROR_BADKEY;
2584 FreeLibrary(hModule);
2587 cleanup:
2588 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2589 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2590 return result;
2593 /******************************************************************************
2594 * RegLoadMUIStringA [ADVAPI32.@]
2596 * See RegLoadMUIStringW
2598 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2599 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2601 UNICODE_STRING valueW, baseDirW;
2602 WCHAR *pwszBuffer;
2603 DWORD cbData = cbBuffer * sizeof(WCHAR);
2604 LONG result;
2606 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2607 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2608 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2609 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2611 result = ERROR_NOT_ENOUGH_MEMORY;
2612 goto cleanup;
2615 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2616 baseDirW.Buffer);
2618 if (result == ERROR_SUCCESS) {
2619 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2620 if (pcbData)
2621 *pcbData = cbData;
2624 cleanup:
2625 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2626 RtlFreeUnicodeString(&baseDirW);
2627 RtlFreeUnicodeString(&valueW);
2629 return result;
2632 /******************************************************************************
2633 * RegDisablePredefinedCache [ADVAPI32.@]
2635 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2637 * PARAMS
2638 * None.
2640 * RETURNS
2641 * Success: ERROR_SUCCESS
2642 * Failure: nonzero error code from Winerror.h
2644 * NOTES
2645 * This is useful for services that use impersonation.
2647 LSTATUS WINAPI RegDisablePredefinedCache(void)
2649 HKEY hkey_current_user;
2650 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2652 /* prevent caching of future requests */
2653 hkcu_cache_disabled = TRUE;
2655 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2657 if (hkey_current_user)
2658 NtClose( hkey_current_user );
2660 return ERROR_SUCCESS;
2663 /******************************************************************************
2664 * RegDeleteTreeW [ADVAPI32.@]
2667 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2669 LONG ret;
2670 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2671 DWORD dwMaxLen, dwSize;
2672 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2673 HKEY hSubKey = hKey;
2675 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2677 if(lpszSubKey)
2679 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2680 if (ret) return ret;
2683 /* Get highest length for keys, values */
2684 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2685 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2686 if (ret) goto cleanup;
2688 dwMaxSubkeyLen++;
2689 dwMaxValueLen++;
2690 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2691 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2693 /* Name too big: alloc a buffer for it */
2694 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2696 ret = ERROR_NOT_ENOUGH_MEMORY;
2697 goto cleanup;
2702 /* Recursively delete all the subkeys */
2703 while (TRUE)
2705 dwSize = dwMaxLen;
2706 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2707 NULL, NULL, NULL)) break;
2709 ret = RegDeleteTreeW(hSubKey, lpszName);
2710 if (ret) goto cleanup;
2713 if (lpszSubKey)
2714 ret = RegDeleteKeyW(hKey, lpszSubKey);
2715 else
2716 while (TRUE)
2718 dwSize = dwMaxLen;
2719 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2720 NULL, NULL, NULL, NULL)) break;
2722 ret = RegDeleteValueW(hKey, lpszName);
2723 if (ret) goto cleanup;
2726 cleanup:
2727 /* Free buffer if allocated */
2728 if (lpszName != szNameBuf)
2729 HeapFree( GetProcessHeap(), 0, lpszName);
2730 if(lpszSubKey)
2731 RegCloseKey(hSubKey);
2732 return ret;
2735 /******************************************************************************
2736 * RegDeleteTreeA [ADVAPI32.@]
2739 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2741 LONG ret;
2742 UNICODE_STRING lpszSubKeyW;
2744 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2745 else lpszSubKeyW.Buffer = NULL;
2746 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2747 RtlFreeUnicodeString( &lpszSubKeyW );
2748 return ret;