advapi32: Implemented RegDeleteKeyExA/W.
[wine/multimedia.git] / dlls / advapi32 / registry.c
blobfaae2b14ba197245d6af724d3390863dd5d3ec61
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 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
194 RtlInitUnicodeString( &nameW, name );
195 RtlInitUnicodeString( &classW, class );
197 return RtlNtStatusToDosError( NtCreateKey( (PHANDLE)retkey, access, &attr, 0,
198 &classW, options, dispos ) );
202 /******************************************************************************
203 * RegCreateKeyExA [ADVAPI32.@]
205 * Open a registry key, creating it if it doesn't exist.
207 * PARAMS
208 * hkey [I] Handle of the parent registry key
209 * name [I] Name of the new key to open or create
210 * reserved [I] Reserved, pass 0
211 * class [I] The object type of the new key
212 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
213 * access [I] Access level desired
214 * sa [I] Security attributes for the key
215 * retkey [O] Destination for the resulting handle
216 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
218 * RETURNS
219 * Success: ERROR_SUCCESS.
220 * Failure: A standard Win32 error code. retkey remains untouched.
222 * FIXME
223 * MAXIMUM_ALLOWED in access mask not supported by server
225 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
226 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
227 PHKEY retkey, LPDWORD dispos )
229 OBJECT_ATTRIBUTES attr;
230 UNICODE_STRING classW;
231 ANSI_STRING nameA, classA;
232 NTSTATUS status;
234 if (reserved) return ERROR_INVALID_PARAMETER;
235 if (!is_version_nt())
237 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
238 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
240 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
242 attr.Length = sizeof(attr);
243 attr.RootDirectory = hkey;
244 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
245 attr.Attributes = 0;
246 attr.SecurityDescriptor = NULL;
247 attr.SecurityQualityOfService = NULL;
248 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
249 RtlInitAnsiString( &nameA, name );
250 RtlInitAnsiString( &classA, class );
252 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
253 &nameA, FALSE )))
255 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
257 status = NtCreateKey( (PHANDLE)retkey, access, &attr, 0, &classW, options, dispos );
258 RtlFreeUnicodeString( &classW );
261 return RtlNtStatusToDosError( status );
265 /******************************************************************************
266 * RegCreateKeyW [ADVAPI32.@]
268 * Creates the specified reg key.
270 * PARAMS
271 * hKey [I] Handle to an open key.
272 * lpSubKey [I] Name of a key that will be opened or created.
273 * phkResult [O] Receives a handle to the opened or created key.
275 * RETURNS
276 * Success: ERROR_SUCCESS
277 * Failure: nonzero error code defined in Winerror.h
279 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
281 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
282 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
283 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
284 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
288 /******************************************************************************
289 * RegCreateKeyA [ADVAPI32.@]
291 * See RegCreateKeyW.
293 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
295 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
296 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
301 /******************************************************************************
302 * RegOpenKeyExW [ADVAPI32.@]
304 * See RegOpenKeyExA.
306 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
308 OBJECT_ATTRIBUTES attr;
309 UNICODE_STRING nameW;
311 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
312 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
314 if (!retkey) return ERROR_INVALID_PARAMETER;
315 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
317 attr.Length = sizeof(attr);
318 attr.RootDirectory = hkey;
319 attr.ObjectName = &nameW;
320 attr.Attributes = 0;
321 attr.SecurityDescriptor = NULL;
322 attr.SecurityQualityOfService = NULL;
323 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
324 RtlInitUnicodeString( &nameW, name );
325 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE)retkey, access, &attr ) );
329 /******************************************************************************
330 * RegOpenKeyExA [ADVAPI32.@]
332 * Open a registry key.
334 * PARAMS
335 * hkey [I] Handle of open key
336 * name [I] Name of subkey to open
337 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
338 * access [I] Security access mask
339 * retkey [O] Handle to open key
341 * RETURNS
342 * Success: ERROR_SUCCESS
343 * Failure: A standard Win32 error code. retkey is set to 0.
345 * NOTES
346 * Unlike RegCreateKeyExA(), this function will not create the key if it
347 * does not exist.
349 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
351 OBJECT_ATTRIBUTES attr;
352 STRING nameA;
353 NTSTATUS status;
355 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
356 else
358 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
359 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
362 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
364 attr.Length = sizeof(attr);
365 attr.RootDirectory = hkey;
366 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
367 attr.Attributes = 0;
368 attr.SecurityDescriptor = NULL;
369 attr.SecurityQualityOfService = NULL;
370 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
372 RtlInitAnsiString( &nameA, name );
373 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
374 &nameA, FALSE )))
376 status = NtOpenKey( (PHANDLE)retkey, access, &attr );
378 return RtlNtStatusToDosError( status );
382 /******************************************************************************
383 * RegOpenKeyW [ADVAPI32.@]
385 * See RegOpenKeyA.
387 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
389 if (!retkey)
390 return ERROR_INVALID_PARAMETER;
392 if (!name || !*name)
394 *retkey = hkey;
395 return ERROR_SUCCESS;
397 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
401 /******************************************************************************
402 * RegOpenKeyA [ADVAPI32.@]
404 * Open a registry key.
406 * PARAMS
407 * hkey [I] Handle of parent key to open the new key under
408 * name [I] Name of the key under hkey to open
409 * retkey [O] Destination for the resulting Handle
411 * RETURNS
412 * Success: ERROR_SUCCESS
413 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
415 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
417 if (!retkey)
418 return ERROR_INVALID_PARAMETER;
420 if (!name || !*name)
422 *retkey = hkey;
423 return ERROR_SUCCESS;
425 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
429 /******************************************************************************
430 * RegOpenCurrentUser [ADVAPI32.@]
432 * Get a handle to the HKEY_CURRENT_USER key for the user
433 * the current thread is impersonating.
435 * PARAMS
436 * access [I] Desired access rights to the key
437 * retkey [O] Handle to the opened key
439 * RETURNS
440 * Success: ERROR_SUCCESS
441 * Failure: nonzero error code from Winerror.h
443 * FIXME
444 * This function is supposed to retrieve a handle to the
445 * HKEY_CURRENT_USER for the user the current thread is impersonating.
446 * Since Wine does not currently allow threads to impersonate other users,
447 * this stub should work fine.
449 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
451 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
456 /******************************************************************************
457 * RegEnumKeyExW [ADVAPI32.@]
459 * Enumerate subkeys of the specified open registry key.
461 * PARAMS
462 * hkey [I] Handle to key to enumerate
463 * index [I] Index of subkey to enumerate
464 * name [O] Buffer for subkey name
465 * name_len [O] Size of subkey buffer
466 * reserved [I] Reserved
467 * class [O] Buffer for class string
468 * class_len [O] Size of class buffer
469 * ft [O] Time key last written to
471 * RETURNS
472 * Success: ERROR_SUCCESS
473 * Failure: System error code. If there are no more subkeys available, the
474 * function returns ERROR_NO_MORE_ITEMS.
476 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
477 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
479 NTSTATUS status;
480 char buffer[256], *buf_ptr = buffer;
481 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
482 DWORD total_size;
484 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
485 name_len ? *name_len : 0, reserved, class, class_len, ft );
487 if (reserved) return ERROR_INVALID_PARAMETER;
488 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
490 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
491 buffer, sizeof(buffer), &total_size );
493 while (status == STATUS_BUFFER_OVERFLOW)
495 /* retry with a dynamically allocated buffer */
496 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
497 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
498 return ERROR_NOT_ENOUGH_MEMORY;
499 info = (KEY_NODE_INFORMATION *)buf_ptr;
500 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
501 buf_ptr, total_size, &total_size );
504 if (!status)
506 DWORD len = info->NameLength / sizeof(WCHAR);
507 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
509 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
511 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
512 status = STATUS_BUFFER_OVERFLOW;
513 else
515 *name_len = len;
516 memcpy( name, info->Name, info->NameLength );
517 name[len] = 0;
518 if (class_len)
520 *class_len = cls_len;
521 if (class)
523 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
524 class[cls_len] = 0;
530 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
531 return RtlNtStatusToDosError( status );
535 /******************************************************************************
536 * RegEnumKeyExA [ADVAPI32.@]
538 * See RegEnumKeyExW.
540 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
541 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
543 NTSTATUS status;
544 char buffer[256], *buf_ptr = buffer;
545 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
546 DWORD total_size;
548 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
549 name_len ? *name_len : 0, reserved, class, class_len, ft );
551 if (reserved) return ERROR_INVALID_PARAMETER;
552 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
554 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
555 buffer, sizeof(buffer), &total_size );
557 while (status == STATUS_BUFFER_OVERFLOW)
559 /* retry with a dynamically allocated buffer */
560 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
561 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
562 return ERROR_NOT_ENOUGH_MEMORY;
563 info = (KEY_NODE_INFORMATION *)buf_ptr;
564 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
565 buf_ptr, total_size, &total_size );
568 if (!status)
570 DWORD len, cls_len;
572 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
573 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
574 info->ClassLength );
575 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
577 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
578 status = STATUS_BUFFER_OVERFLOW;
579 else
581 *name_len = len;
582 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
583 name[len] = 0;
584 if (class_len)
586 *class_len = cls_len;
587 if (class)
589 RtlUnicodeToMultiByteN( class, cls_len, NULL,
590 (WCHAR *)(buf_ptr + info->ClassOffset),
591 info->ClassLength );
592 class[cls_len] = 0;
598 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
599 return RtlNtStatusToDosError( status );
603 /******************************************************************************
604 * RegEnumKeyW [ADVAPI32.@]
606 * Enumerates subkeys of the specified open reg key.
608 * PARAMS
609 * hKey [I] Handle to an open key.
610 * dwIndex [I] Index of the subkey of hKey to retrieve.
611 * lpName [O] Name of the subkey.
612 * cchName [I] Size of lpName in TCHARS.
614 * RETURNS
615 * Success: ERROR_SUCCESS
616 * Failure: system error code. If there are no more subkeys available, the
617 * function returns ERROR_NO_MORE_ITEMS.
619 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
621 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
625 /******************************************************************************
626 * RegEnumKeyA [ADVAPI32.@]
628 * See RegEnumKeyW.
630 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
632 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
636 /******************************************************************************
637 * RegQueryInfoKeyW [ADVAPI32.@]
639 * Retrieves information about the specified registry key.
641 * PARAMS
642 * hkey [I] Handle to key to query
643 * class [O] Buffer for class string
644 * class_len [O] Size of class string buffer
645 * reserved [I] Reserved
646 * subkeys [O] Buffer for number of subkeys
647 * max_subkey [O] Buffer for longest subkey name length
648 * max_class [O] Buffer for longest class string length
649 * values [O] Buffer for number of value entries
650 * max_value [O] Buffer for longest value name length
651 * max_data [O] Buffer for longest value data length
652 * security [O] Buffer for security descriptor length
653 * modif [O] Modification time
655 * RETURNS
656 * Success: ERROR_SUCCESS
657 * Failure: system error code.
659 * NOTES
660 * - win95 allows class to be valid and class_len to be NULL
661 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
662 * - both allow class to be NULL and class_len to be NULL
663 * (it's hard to test validity, so test !NULL instead)
665 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
666 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
667 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
668 LPDWORD security, FILETIME *modif )
670 NTSTATUS status;
671 char buffer[256], *buf_ptr = buffer;
672 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
673 DWORD total_size;
675 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
676 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
678 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
679 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
681 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
682 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
684 if (class)
686 /* retry with a dynamically allocated buffer */
687 while (status == STATUS_BUFFER_OVERFLOW)
689 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
690 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
691 return ERROR_NOT_ENOUGH_MEMORY;
692 info = (KEY_FULL_INFORMATION *)buf_ptr;
693 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
696 if (status) goto done;
698 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
700 status = STATUS_BUFFER_OVERFLOW;
702 else
704 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
705 class[info->ClassLength/sizeof(WCHAR)] = 0;
708 else status = STATUS_SUCCESS;
710 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
711 if (subkeys) *subkeys = info->SubKeys;
712 if (max_subkey) *max_subkey = info->MaxNameLen;
713 if (max_class) *max_class = info->MaxClassLen;
714 if (values) *values = info->Values;
715 if (max_value) *max_value = info->MaxValueNameLen;
716 if (max_data) *max_data = info->MaxValueDataLen;
717 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
719 done:
720 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
721 return RtlNtStatusToDosError( status );
725 /******************************************************************************
726 * RegQueryMultipleValuesA [ADVAPI32.@]
728 * Retrieves the type and data for a list of value names associated with a key.
730 * PARAMS
731 * hKey [I] Handle to an open key.
732 * val_list [O] Array of VALENT structures that describes the entries.
733 * num_vals [I] Number of elements in val_list.
734 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
735 * ldwTotsize [I/O] Size of lpValueBuf.
737 * RETURNS
738 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
739 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
740 * bytes.
742 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
743 LPSTR lpValueBuf, LPDWORD ldwTotsize )
745 unsigned int i;
746 DWORD maxBytes = *ldwTotsize;
747 HRESULT status;
748 LPSTR bufptr = lpValueBuf;
749 *ldwTotsize = 0;
751 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
753 for(i=0; i < num_vals; ++i)
756 val_list[i].ve_valuelen=0;
757 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
758 if(status != ERROR_SUCCESS)
760 return status;
763 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
765 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
766 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
767 if(status != ERROR_SUCCESS)
769 return status;
772 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
774 bufptr += val_list[i].ve_valuelen;
777 *ldwTotsize += val_list[i].ve_valuelen;
779 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
783 /******************************************************************************
784 * RegQueryMultipleValuesW [ADVAPI32.@]
786 * See RegQueryMultipleValuesA.
788 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
789 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
791 unsigned int i;
792 DWORD maxBytes = *ldwTotsize;
793 HRESULT status;
794 LPSTR bufptr = (LPSTR)lpValueBuf;
795 *ldwTotsize = 0;
797 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
799 for(i=0; i < num_vals; ++i)
801 val_list[i].ve_valuelen=0;
802 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
803 if(status != ERROR_SUCCESS)
805 return status;
808 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
810 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
811 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
812 if(status != ERROR_SUCCESS)
814 return status;
817 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
819 bufptr += val_list[i].ve_valuelen;
822 *ldwTotsize += val_list[i].ve_valuelen;
824 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
827 /******************************************************************************
828 * RegQueryInfoKeyA [ADVAPI32.@]
830 * Retrieves information about a registry key.
832 * PARAMS
833 * hKey [I] Handle to an open key.
834 * lpClass [O] Class string of the key.
835 * lpcClass [I/O] size of lpClass.
836 * lpReserved [I] Reserved; must be NULL.
837 * lpcSubKeys [O] Number of subkeys contained by the key.
838 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
839 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
840 * class in TCHARS.
841 * lpcValues [O] Number of values associated with the key.
842 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
843 * lpcMaxValueLen [O] Longest data component among the key's values
844 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
845 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
847 * RETURNS
848 * Success: ERROR_SUCCESS
849 * Failure: nonzero error code from Winerror.h
851 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
852 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
853 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
854 LPDWORD security, FILETIME *modif )
856 NTSTATUS status;
857 char buffer[256], *buf_ptr = buffer;
858 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
859 DWORD total_size, len;
861 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
862 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
864 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
865 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
867 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
868 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
870 if (class || class_len)
872 /* retry with a dynamically allocated buffer */
873 while (status == STATUS_BUFFER_OVERFLOW)
875 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
876 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
877 return ERROR_NOT_ENOUGH_MEMORY;
878 info = (KEY_FULL_INFORMATION *)buf_ptr;
879 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
882 if (status) goto done;
884 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
885 if (class_len)
887 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
888 *class_len = len;
890 if (class && !status)
892 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
893 info->ClassLength );
894 class[len] = 0;
897 else status = STATUS_SUCCESS;
899 if (subkeys) *subkeys = info->SubKeys;
900 if (max_subkey) *max_subkey = info->MaxNameLen;
901 if (max_class) *max_class = info->MaxClassLen;
902 if (values) *values = info->Values;
903 if (max_value) *max_value = info->MaxValueNameLen;
904 if (max_data) *max_data = info->MaxValueDataLen;
905 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
907 done:
908 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
909 return RtlNtStatusToDosError( status );
913 /******************************************************************************
914 * RegCloseKey [ADVAPI32.@]
916 * Close an open registry key.
918 * PARAMS
919 * hkey [I] Handle of key to close
921 * RETURNS
922 * Success: ERROR_SUCCESS
923 * Failure: Error code
925 LSTATUS WINAPI RegCloseKey( HKEY hkey )
927 if (!hkey) return ERROR_INVALID_HANDLE;
928 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
929 return RtlNtStatusToDosError( NtClose( hkey ) );
933 /******************************************************************************
934 * RegDeleteKeyExW [ADVAPI32.@]
936 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
938 DWORD ret;
939 HKEY tmp;
941 if (!name) return ERROR_INVALID_PARAMETER;
943 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
945 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
946 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
948 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
949 RegCloseKey( tmp );
951 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
952 return ret;
956 /******************************************************************************
957 * RegDeleteKeyW [ADVAPI32.@]
959 * See RegDeleteKeyA.
961 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
963 return RegDeleteKeyExW( hkey, name, 0, 0 );
967 /******************************************************************************
968 * RegDeleteKeyExA [ADVAPI32.@]
970 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
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 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
980 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
982 if (!is_version_nt()) /* win95 does recursive key deletes */
984 CHAR name[MAX_PATH];
986 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
988 if(RegDeleteKeyExA(tmp, name, access, reserved)) /* recurse */
989 break;
992 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
993 RegCloseKey( tmp );
995 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
996 return ret;
1000 /******************************************************************************
1001 * RegDeleteKeyA [ADVAPI32.@]
1003 * Delete a registry key.
1005 * PARAMS
1006 * hkey [I] Handle to parent key containing the key to delete
1007 * name [I] Name of the key user hkey to delete
1009 * NOTES
1011 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1012 * right. In reality, it opens a new handle with DELETE access.
1014 * RETURNS
1015 * Success: ERROR_SUCCESS
1016 * Failure: Error code
1018 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1020 return RegDeleteKeyExA( hkey, name, 0, 0 );
1025 /******************************************************************************
1026 * RegSetValueExW [ADVAPI32.@]
1028 * Set the data and contents of a registry value.
1030 * PARAMS
1031 * hkey [I] Handle of key to set value for
1032 * name [I] Name of value to set
1033 * reserved [I] Reserved, must be zero
1034 * type [I] Type of the value being set
1035 * data [I] The new contents of the value to set
1036 * count [I] Size of data
1038 * RETURNS
1039 * Success: ERROR_SUCCESS
1040 * Failure: Error code
1042 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1043 DWORD type, CONST BYTE *data, DWORD count )
1045 UNICODE_STRING nameW;
1047 /* no need for version check, not implemented on win9x anyway */
1048 if (count && is_string(type))
1050 LPCWSTR str = (LPCWSTR)data;
1051 /* if user forgot to count terminating null, add it (yes NT does this) */
1052 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1053 count += sizeof(WCHAR);
1055 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1057 RtlInitUnicodeString( &nameW, name );
1058 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1062 /******************************************************************************
1063 * RegSetValueExA [ADVAPI32.@]
1065 * See RegSetValueExW.
1067 * NOTES
1068 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1069 * NT does definitely care (aj)
1071 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1072 CONST BYTE *data, DWORD count )
1074 ANSI_STRING nameA;
1075 WCHAR *dataW = NULL;
1076 NTSTATUS status;
1078 if (!is_version_nt()) /* win95 */
1080 if (type == REG_SZ)
1082 if (!data) return ERROR_INVALID_PARAMETER;
1083 count = strlen((const char *)data) + 1;
1086 else if (count && is_string(type))
1088 /* if user forgot to count terminating null, add it (yes NT does this) */
1089 if (data[count-1] && !data[count]) count++;
1092 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1094 if (is_string( type )) /* need to convert to Unicode */
1096 DWORD lenW;
1097 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1098 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1099 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1100 count = lenW;
1101 data = (BYTE *)dataW;
1104 RtlInitAnsiString( &nameA, name );
1105 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1106 &nameA, FALSE )))
1108 status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
1110 HeapFree( GetProcessHeap(), 0, dataW );
1111 return RtlNtStatusToDosError( status );
1115 /******************************************************************************
1116 * RegSetValueW [ADVAPI32.@]
1118 * Sets the data for the default or unnamed value of a reg key.
1120 * PARAMS
1121 * hKey [I] Handle to an open key.
1122 * lpSubKey [I] Name of a subkey of hKey.
1123 * dwType [I] Type of information to store.
1124 * lpData [I] String that contains the data to set for the default value.
1125 * cbData [I] Ignored.
1127 * RETURNS
1128 * Success: ERROR_SUCCESS
1129 * Failure: nonzero error code from Winerror.h
1131 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1133 HKEY subkey = hkey;
1134 DWORD ret;
1136 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1138 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1140 if (name && name[0]) /* need to create the subkey */
1142 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1145 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1146 (strlenW( data ) + 1) * sizeof(WCHAR) );
1147 if (subkey != hkey) RegCloseKey( subkey );
1148 return ret;
1152 /******************************************************************************
1153 * RegSetValueA [ADVAPI32.@]
1155 * See RegSetValueW.
1157 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1159 HKEY subkey = hkey;
1160 DWORD ret;
1162 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1164 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1166 if (name && name[0]) /* need to create the subkey */
1168 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1170 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1171 if (subkey != hkey) RegCloseKey( subkey );
1172 return ret;
1177 /******************************************************************************
1178 * RegQueryValueExW [ADVAPI32.@]
1180 * See RegQueryValueExA.
1182 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1183 LPBYTE data, LPDWORD count )
1185 NTSTATUS status;
1186 UNICODE_STRING name_str;
1187 DWORD total_size;
1188 char buffer[256], *buf_ptr = buffer;
1189 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1190 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1192 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1193 hkey, debugstr_w(name), reserved, type, data, count,
1194 (count && data) ? *count : 0 );
1196 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1197 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1199 RtlInitUnicodeString( &name_str, name );
1201 if (data) total_size = min( sizeof(buffer), *count + info_size );
1202 else
1204 total_size = info_size;
1205 if (count) *count = 0;
1208 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1209 buffer, total_size, &total_size );
1210 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1212 if (data)
1214 /* retry with a dynamically allocated buffer */
1215 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1217 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1218 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1219 return ERROR_NOT_ENOUGH_MEMORY;
1220 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1221 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1222 buf_ptr, total_size, &total_size );
1225 if (!status)
1227 memcpy( data, buf_ptr + info_size, total_size - info_size );
1228 /* if the type is REG_SZ and data is not 0-terminated
1229 * and there is enough space in the buffer NT appends a \0 */
1230 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1232 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1233 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1236 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1238 else status = STATUS_SUCCESS;
1240 if (type) *type = info->Type;
1241 if (count) *count = total_size - info_size;
1243 done:
1244 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1245 return RtlNtStatusToDosError(status);
1249 /******************************************************************************
1250 * RegQueryValueExA [ADVAPI32.@]
1252 * Get the type and contents of a specified value under with a key.
1254 * PARAMS
1255 * hkey [I] Handle of the key to query
1256 * name [I] Name of value under hkey to query
1257 * reserved [I] Reserved - must be NULL
1258 * type [O] Destination for the value type, or NULL if not required
1259 * data [O] Destination for the values contents, or NULL if not required
1260 * count [I/O] Size of data, updated with the number of bytes returned
1262 * RETURNS
1263 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1264 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1265 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1266 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1268 * NOTES
1269 * MSDN states that if data is too small it is partially filled. In reality
1270 * it remains untouched.
1272 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1273 LPBYTE data, LPDWORD count )
1275 NTSTATUS status;
1276 ANSI_STRING nameA;
1277 DWORD total_size, datalen = 0;
1278 char buffer[256], *buf_ptr = buffer;
1279 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1280 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1282 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1283 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1285 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1286 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1288 if (count) datalen = *count;
1289 if (!data && count) *count = 0;
1291 /* this matches Win9x behaviour - NT sets *type to a random value */
1292 if (type) *type = REG_NONE;
1294 RtlInitAnsiString( &nameA, name );
1295 if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1296 &nameA, FALSE )))
1297 return RtlNtStatusToDosError(status);
1299 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1300 KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
1301 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1303 /* we need to fetch the contents for a string type even if not requested,
1304 * because we need to compute the length of the ASCII string. */
1305 if (data || is_string(info->Type))
1307 /* retry with a dynamically allocated buffer */
1308 while (status == STATUS_BUFFER_OVERFLOW)
1310 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1311 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1313 status = STATUS_NO_MEMORY;
1314 goto done;
1316 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1317 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1318 KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1321 if (status) goto done;
1323 if (is_string(info->Type))
1325 DWORD len;
1327 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1328 total_size - info_size );
1329 if (data && len)
1331 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1332 else
1334 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1335 total_size - info_size );
1336 /* if the type is REG_SZ and data is not 0-terminated
1337 * and there is enough space in the buffer NT appends a \0 */
1338 if (len < datalen && data[len-1]) data[len] = 0;
1341 total_size = len + info_size;
1343 else if (data)
1345 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1346 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1349 else status = STATUS_SUCCESS;
1351 if (type) *type = info->Type;
1352 if (count) *count = total_size - info_size;
1354 done:
1355 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1356 return RtlNtStatusToDosError(status);
1360 /******************************************************************************
1361 * RegQueryValueW [ADVAPI32.@]
1363 * Retrieves the data associated with the default or unnamed value of a key.
1365 * PARAMS
1366 * hkey [I] Handle to an open key.
1367 * name [I] Name of the subkey of hKey.
1368 * data [O] Receives the string associated with the default value
1369 * of the key.
1370 * count [I/O] Size of lpValue in bytes.
1372 * RETURNS
1373 * Success: ERROR_SUCCESS
1374 * Failure: nonzero error code from Winerror.h
1376 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1378 DWORD ret;
1379 HKEY subkey = hkey;
1381 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1383 if (name && name[0])
1385 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1387 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1388 if (subkey != hkey) RegCloseKey( subkey );
1389 if (ret == ERROR_FILE_NOT_FOUND)
1391 /* return empty string if default value not found */
1392 if (data) *data = 0;
1393 if (count) *count = sizeof(WCHAR);
1394 ret = ERROR_SUCCESS;
1396 return ret;
1400 /******************************************************************************
1401 * RegQueryValueA [ADVAPI32.@]
1403 * See RegQueryValueW.
1405 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1407 DWORD ret;
1408 HKEY subkey = hkey;
1410 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1412 if (name && name[0])
1414 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1416 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1417 if (subkey != hkey) RegCloseKey( subkey );
1418 if (ret == ERROR_FILE_NOT_FOUND)
1420 /* return empty string if default value not found */
1421 if (data) *data = 0;
1422 if (count) *count = 1;
1423 ret = ERROR_SUCCESS;
1425 return ret;
1429 /******************************************************************************
1430 * ADVAPI_ApplyRestrictions [internal]
1432 * Helper function for RegGetValueA/W.
1434 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1435 DWORD cbData, PLONG ret )
1437 /* Check if the type is restricted by the passed flags */
1438 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1440 DWORD dwMask = 0;
1442 switch (dwType)
1444 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1445 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1446 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1447 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1448 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1449 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1450 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1453 if (dwFlags & dwMask)
1455 /* Type is not restricted, check for size mismatch */
1456 if (dwType == REG_BINARY)
1458 DWORD cbExpect = 0;
1460 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1461 cbExpect = 4;
1462 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1463 cbExpect = 8;
1465 if (cbExpect && cbData != cbExpect)
1466 *ret = ERROR_DATATYPE_MISMATCH;
1469 else *ret = ERROR_UNSUPPORTED_TYPE;
1474 /******************************************************************************
1475 * RegGetValueW [ADVAPI32.@]
1477 * Retrieves the type and data for a value name associated with a key,
1478 * optionally expanding its content and restricting its type.
1480 * PARAMS
1481 * hKey [I] Handle to an open key.
1482 * pszSubKey [I] Name of the subkey of hKey.
1483 * pszValue [I] Name of value under hKey/szSubKey to query.
1484 * dwFlags [I] Flags restricting the value type to retrieve.
1485 * pdwType [O] Destination for the values type, may be NULL.
1486 * pvData [O] Destination for the values content, may be NULL.
1487 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1488 * retrieve the whole content, including the trailing '\0'
1489 * for strings.
1491 * RETURNS
1492 * Success: ERROR_SUCCESS
1493 * Failure: nonzero error code from Winerror.h
1495 * NOTES
1496 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1497 * expanded and pdwType is set to REG_SZ instead.
1498 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1499 * without RRF_NOEXPAND is thus not allowed.
1500 * An exception is the case where RRF_RT_ANY is specified, because then
1501 * RRF_NOEXPAND is allowed.
1503 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1504 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1505 LPDWORD pcbData )
1507 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1508 PVOID pvBuf = NULL;
1509 LONG ret;
1511 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1512 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1513 pvData, pcbData, cbData);
1515 if (pvData && !pcbData)
1516 return ERROR_INVALID_PARAMETER;
1517 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1518 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1519 return ERROR_INVALID_PARAMETER;
1521 if (pszSubKey && pszSubKey[0])
1523 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1524 if (ret != ERROR_SUCCESS) return ret;
1527 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1529 /* If we are going to expand we need to read in the whole the value even
1530 * if the passed buffer was too small as the expanded string might be
1531 * smaller than the unexpanded one and could fit into cbData bytes. */
1532 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1533 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1535 do {
1536 HeapFree(GetProcessHeap(), 0, pvBuf);
1538 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1539 if (!pvBuf)
1541 ret = ERROR_NOT_ENOUGH_MEMORY;
1542 break;
1545 if (ret == ERROR_MORE_DATA || !pvData)
1546 ret = RegQueryValueExW(hKey, pszValue, NULL,
1547 &dwType, pvBuf, &cbData);
1548 else
1550 /* Even if cbData was large enough we have to copy the
1551 * string since ExpandEnvironmentStrings can't handle
1552 * overlapping buffers. */
1553 CopyMemory(pvBuf, pvData, cbData);
1556 /* Both the type or the value itself could have been modified in
1557 * between so we have to keep retrying until the buffer is large
1558 * enough or we no longer have to expand the value. */
1559 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1561 if (ret == ERROR_SUCCESS)
1563 /* Recheck dwType in case it changed since the first call */
1564 if (dwType == REG_EXPAND_SZ)
1566 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1567 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1568 dwType = REG_SZ;
1569 if(pvData && pcbData && cbData > *pcbData)
1570 ret = ERROR_MORE_DATA;
1572 else if (pvData)
1573 CopyMemory(pvData, pvBuf, *pcbData);
1576 HeapFree(GetProcessHeap(), 0, pvBuf);
1579 if (pszSubKey && pszSubKey[0])
1580 RegCloseKey(hKey);
1582 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1584 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1585 ZeroMemory(pvData, *pcbData);
1587 if (pdwType) *pdwType = dwType;
1588 if (pcbData) *pcbData = cbData;
1590 return ret;
1594 /******************************************************************************
1595 * RegGetValueA [ADVAPI32.@]
1597 * See RegGetValueW.
1599 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1600 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1601 LPDWORD pcbData )
1603 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1604 PVOID pvBuf = NULL;
1605 LONG ret;
1607 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1608 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1609 cbData);
1611 if (pvData && !pcbData)
1612 return ERROR_INVALID_PARAMETER;
1613 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1614 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1615 return ERROR_INVALID_PARAMETER;
1617 if (pszSubKey && pszSubKey[0])
1619 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1620 if (ret != ERROR_SUCCESS) return ret;
1623 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1625 /* If we are going to expand we need to read in the whole the value even
1626 * if the passed buffer was too small as the expanded string might be
1627 * smaller than the unexpanded one and could fit into cbData bytes. */
1628 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1629 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1631 do {
1632 HeapFree(GetProcessHeap(), 0, pvBuf);
1634 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1635 if (!pvBuf)
1637 ret = ERROR_NOT_ENOUGH_MEMORY;
1638 break;
1641 if (ret == ERROR_MORE_DATA || !pvData)
1642 ret = RegQueryValueExA(hKey, pszValue, NULL,
1643 &dwType, pvBuf, &cbData);
1644 else
1646 /* Even if cbData was large enough we have to copy the
1647 * string since ExpandEnvironmentStrings can't handle
1648 * overlapping buffers. */
1649 CopyMemory(pvBuf, pvData, cbData);
1652 /* Both the type or the value itself could have been modified in
1653 * between so we have to keep retrying until the buffer is large
1654 * enough or we no longer have to expand the value. */
1655 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1657 if (ret == ERROR_SUCCESS)
1659 /* Recheck dwType in case it changed since the first call */
1660 if (dwType == REG_EXPAND_SZ)
1662 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1663 pcbData ? *pcbData : 0);
1664 dwType = REG_SZ;
1665 if(pvData && pcbData && cbData > *pcbData)
1666 ret = ERROR_MORE_DATA;
1668 else if (pvData)
1669 CopyMemory(pvData, pvBuf, *pcbData);
1672 HeapFree(GetProcessHeap(), 0, pvBuf);
1675 if (pszSubKey && pszSubKey[0])
1676 RegCloseKey(hKey);
1678 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1680 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1681 ZeroMemory(pvData, *pcbData);
1683 if (pdwType) *pdwType = dwType;
1684 if (pcbData) *pcbData = cbData;
1686 return ret;
1690 /******************************************************************************
1691 * RegEnumValueW [ADVAPI32.@]
1693 * Enumerates the values for the specified open registry key.
1695 * PARAMS
1696 * hkey [I] Handle to key to query
1697 * index [I] Index of value to query
1698 * value [O] Value string
1699 * val_count [I/O] Size of value buffer (in wchars)
1700 * reserved [I] Reserved
1701 * type [O] Type code
1702 * data [O] Value data
1703 * count [I/O] Size of data buffer (in bytes)
1705 * RETURNS
1706 * Success: ERROR_SUCCESS
1707 * Failure: nonzero error code from Winerror.h
1710 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1711 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1713 NTSTATUS status;
1714 DWORD total_size;
1715 char buffer[256], *buf_ptr = buffer;
1716 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1717 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1719 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1720 hkey, index, value, val_count, reserved, type, data, count );
1722 /* NT only checks count, not val_count */
1723 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1724 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1726 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1727 if (data) total_size += *count;
1728 total_size = min( sizeof(buffer), total_size );
1730 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1731 buffer, total_size, &total_size );
1732 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1734 if (value || data)
1736 /* retry with a dynamically allocated buffer */
1737 while (status == STATUS_BUFFER_OVERFLOW)
1739 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1740 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1741 return ERROR_NOT_ENOUGH_MEMORY;
1742 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1743 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1744 buf_ptr, total_size, &total_size );
1747 if (status) goto done;
1749 if (value)
1751 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1753 status = STATUS_BUFFER_OVERFLOW;
1754 goto overflow;
1756 memcpy( value, info->Name, info->NameLength );
1757 *val_count = info->NameLength / sizeof(WCHAR);
1758 value[*val_count] = 0;
1761 if (data)
1763 if (total_size - info->DataOffset > *count)
1765 status = STATUS_BUFFER_OVERFLOW;
1766 goto overflow;
1768 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1769 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1771 /* if the type is REG_SZ and data is not 0-terminated
1772 * and there is enough space in the buffer NT appends a \0 */
1773 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1774 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1778 else status = STATUS_SUCCESS;
1780 overflow:
1781 if (type) *type = info->Type;
1782 if (count) *count = info->DataLength;
1784 done:
1785 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1786 return RtlNtStatusToDosError(status);
1790 /******************************************************************************
1791 * RegEnumValueA [ADVAPI32.@]
1793 * See RegEnumValueW.
1795 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1796 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1798 NTSTATUS status;
1799 DWORD total_size;
1800 char buffer[256], *buf_ptr = buffer;
1801 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1802 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1804 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1805 hkey, index, value, val_count, reserved, type, data, count );
1807 /* NT only checks count, not val_count */
1808 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1809 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1811 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1812 if (data) total_size += *count;
1813 total_size = min( sizeof(buffer), total_size );
1815 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1816 buffer, total_size, &total_size );
1817 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1819 /* we need to fetch the contents for a string type even if not requested,
1820 * because we need to compute the length of the ASCII string. */
1821 if (value || data || is_string(info->Type))
1823 /* retry with a dynamically allocated buffer */
1824 while (status == STATUS_BUFFER_OVERFLOW)
1826 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1827 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1828 return ERROR_NOT_ENOUGH_MEMORY;
1829 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1830 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1831 buf_ptr, total_size, &total_size );
1834 if (status) goto done;
1836 if (is_string(info->Type))
1838 DWORD len;
1839 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1840 total_size - info->DataOffset );
1841 if (data && len)
1843 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1844 else
1846 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1847 total_size - info->DataOffset );
1848 /* if the type is REG_SZ and data is not 0-terminated
1849 * and there is enough space in the buffer NT appends a \0 */
1850 if (len < *count && data[len-1]) data[len] = 0;
1853 info->DataLength = len;
1855 else if (data)
1857 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1858 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1861 if (value && !status)
1863 DWORD len;
1865 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1866 if (len >= *val_count)
1868 status = STATUS_BUFFER_OVERFLOW;
1869 if (*val_count)
1871 len = *val_count - 1;
1872 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1873 value[len] = 0;
1876 else
1878 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1879 value[len] = 0;
1880 *val_count = len;
1884 else status = STATUS_SUCCESS;
1886 if (type) *type = info->Type;
1887 if (count) *count = info->DataLength;
1889 done:
1890 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1891 return RtlNtStatusToDosError(status);
1896 /******************************************************************************
1897 * RegDeleteValueW [ADVAPI32.@]
1899 * See RegDeleteValueA.
1901 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1903 UNICODE_STRING nameW;
1905 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1907 RtlInitUnicodeString( &nameW, name );
1908 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1912 /******************************************************************************
1913 * RegDeleteValueA [ADVAPI32.@]
1915 * Delete a value from the registry.
1917 * PARAMS
1918 * hkey [I] Registry handle of the key holding the value
1919 * name [I] Name of the value under hkey to delete
1921 * RETURNS
1922 * Success: ERROR_SUCCESS
1923 * Failure: nonzero error code from Winerror.h
1925 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1927 STRING nameA;
1928 NTSTATUS status;
1930 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1932 RtlInitAnsiString( &nameA, name );
1933 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1934 &nameA, FALSE )))
1935 status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1936 return RtlNtStatusToDosError( status );
1940 /******************************************************************************
1941 * RegLoadKeyW [ADVAPI32.@]
1943 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1944 * registration information from a specified file into that subkey.
1946 * PARAMS
1947 * hkey [I] Handle of open key
1948 * subkey [I] Address of name of subkey
1949 * filename [I] Address of filename for registry information
1951 * RETURNS
1952 * Success: ERROR_SUCCESS
1953 * Failure: nonzero error code from Winerror.h
1955 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1957 OBJECT_ATTRIBUTES destkey, file;
1958 UNICODE_STRING subkeyW, filenameW;
1959 NTSTATUS status;
1961 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
1963 destkey.Length = sizeof(destkey);
1964 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
1965 destkey.ObjectName = &subkeyW; /* name of the key */
1966 destkey.Attributes = 0;
1967 destkey.SecurityDescriptor = NULL;
1968 destkey.SecurityQualityOfService = NULL;
1969 RtlInitUnicodeString(&subkeyW, subkey);
1971 file.Length = sizeof(file);
1972 file.RootDirectory = NULL;
1973 file.ObjectName = &filenameW; /* file containing the hive */
1974 file.Attributes = OBJ_CASE_INSENSITIVE;
1975 file.SecurityDescriptor = NULL;
1976 file.SecurityQualityOfService = NULL;
1977 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
1979 status = NtLoadKey(&destkey, &file);
1980 RtlFreeUnicodeString(&filenameW);
1981 return RtlNtStatusToDosError( status );
1985 /******************************************************************************
1986 * RegLoadKeyA [ADVAPI32.@]
1988 * See RegLoadKeyW.
1990 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1992 UNICODE_STRING subkeyW, filenameW;
1993 STRING subkeyA, filenameA;
1994 NTSTATUS status;
1995 LONG ret;
1997 RtlInitAnsiString(&subkeyA, subkey);
1998 RtlInitAnsiString(&filenameA, filename);
2000 RtlInitUnicodeString(&subkeyW, NULL);
2001 RtlInitUnicodeString(&filenameW, NULL);
2002 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2003 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2005 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2007 else ret = RtlNtStatusToDosError(status);
2008 RtlFreeUnicodeString(&subkeyW);
2009 RtlFreeUnicodeString(&filenameW);
2010 return ret;
2014 /******************************************************************************
2015 * RegSaveKeyW [ADVAPI32.@]
2017 * Save a key and all of its subkeys and values to a new file in the standard format.
2019 * PARAMS
2020 * hkey [I] Handle of key where save begins
2021 * lpFile [I] Address of filename to save to
2022 * sa [I] Address of security structure
2024 * RETURNS
2025 * Success: ERROR_SUCCESS
2026 * Failure: nonzero error code from Winerror.h
2028 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2030 static const WCHAR format[] =
2031 {'r','e','g','%','0','4','x','.','t','m','p',0};
2032 WCHAR buffer[MAX_PATH];
2033 int count = 0;
2034 LPWSTR nameW;
2035 DWORD ret, err;
2036 HANDLE handle;
2038 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2040 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2041 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2043 err = GetLastError();
2044 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2046 for (;;)
2048 snprintfW( nameW, 16, format, count++ );
2049 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2050 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2051 if (handle != INVALID_HANDLE_VALUE) break;
2052 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2054 /* Something gone haywire ? Please report if this happens abnormally */
2055 if (count >= 100)
2056 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);
2059 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2061 CloseHandle( handle );
2062 if (!ret)
2064 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2066 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2067 debugstr_w(file) );
2068 ret = GetLastError();
2071 if (ret) DeleteFileW( buffer );
2073 done:
2074 SetLastError( err ); /* restore last error code */
2075 return ret;
2079 /******************************************************************************
2080 * RegSaveKeyA [ADVAPI32.@]
2082 * See RegSaveKeyW.
2084 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2086 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2087 NTSTATUS status;
2088 STRING fileA;
2090 RtlInitAnsiString(&fileA, file);
2091 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2092 return RtlNtStatusToDosError( status );
2093 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2097 /******************************************************************************
2098 * RegRestoreKeyW [ADVAPI32.@]
2100 * Read the registry information from a file and copy it over a key.
2102 * PARAMS
2103 * hkey [I] Handle of key where restore begins
2104 * lpFile [I] Address of filename containing saved tree
2105 * dwFlags [I] Optional flags
2107 * RETURNS
2108 * Success: ERROR_SUCCESS
2109 * Failure: nonzero error code from Winerror.h
2111 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2113 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2115 /* It seems to do this check before the hkey check */
2116 if (!lpFile || !*lpFile)
2117 return ERROR_INVALID_PARAMETER;
2119 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2121 /* Check for file existence */
2123 return ERROR_SUCCESS;
2127 /******************************************************************************
2128 * RegRestoreKeyA [ADVAPI32.@]
2130 * See RegRestoreKeyW.
2132 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2134 UNICODE_STRING lpFileW;
2135 LONG ret;
2137 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2138 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2139 RtlFreeUnicodeString( &lpFileW );
2140 return ret;
2144 /******************************************************************************
2145 * RegUnLoadKeyW [ADVAPI32.@]
2147 * Unload a registry key and its subkeys from the registry.
2149 * PARAMS
2150 * hkey [I] Handle of open key
2151 * lpSubKey [I] Address of name of subkey to unload
2153 * RETURNS
2154 * Success: ERROR_SUCCESS
2155 * Failure: nonzero error code from Winerror.h
2157 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2159 DWORD ret;
2160 HKEY shkey;
2161 OBJECT_ATTRIBUTES attr;
2162 UNICODE_STRING subkey;
2164 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2166 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2167 if( ret )
2168 return ERROR_INVALID_PARAMETER;
2170 RtlInitUnicodeString(&subkey, lpSubKey);
2171 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2172 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2174 RegCloseKey(shkey);
2176 return ret;
2180 /******************************************************************************
2181 * RegUnLoadKeyA [ADVAPI32.@]
2183 * See RegUnLoadKeyW.
2185 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2187 UNICODE_STRING lpSubKeyW;
2188 LONG ret;
2190 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2191 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2192 RtlFreeUnicodeString( &lpSubKeyW );
2193 return ret;
2197 /******************************************************************************
2198 * RegReplaceKeyW [ADVAPI32.@]
2200 * Replace the file backing a registry key and all its subkeys with another file.
2202 * PARAMS
2203 * hkey [I] Handle of open key
2204 * lpSubKey [I] Address of name of subkey
2205 * lpNewFile [I] Address of filename for file with new data
2206 * lpOldFile [I] Address of filename for backup file
2208 * RETURNS
2209 * Success: ERROR_SUCCESS
2210 * Failure: nonzero error code from Winerror.h
2212 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2213 LPCWSTR lpOldFile )
2215 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2216 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2217 return ERROR_SUCCESS;
2221 /******************************************************************************
2222 * RegReplaceKeyA [ADVAPI32.@]
2224 * See RegReplaceKeyW.
2226 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2227 LPCSTR lpOldFile )
2229 UNICODE_STRING lpSubKeyW;
2230 UNICODE_STRING lpNewFileW;
2231 UNICODE_STRING lpOldFileW;
2232 LONG ret;
2234 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2235 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2236 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2237 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2238 RtlFreeUnicodeString( &lpOldFileW );
2239 RtlFreeUnicodeString( &lpNewFileW );
2240 RtlFreeUnicodeString( &lpSubKeyW );
2241 return ret;
2245 /******************************************************************************
2246 * RegSetKeySecurity [ADVAPI32.@]
2248 * Set the security of an open registry key.
2250 * PARAMS
2251 * hkey [I] Open handle of key to set
2252 * SecurityInfo [I] Descriptor contents
2253 * pSecurityDesc [I] Address of descriptor for key
2255 * RETURNS
2256 * Success: ERROR_SUCCESS
2257 * Failure: nonzero error code from Winerror.h
2259 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2260 PSECURITY_DESCRIPTOR pSecurityDesc )
2262 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2264 /* It seems to perform this check before the hkey check */
2265 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2266 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2267 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2268 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2269 /* Param OK */
2270 } else
2271 return ERROR_INVALID_PARAMETER;
2273 if (!pSecurityDesc)
2274 return ERROR_INVALID_PARAMETER;
2276 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2278 return ERROR_SUCCESS;
2282 /******************************************************************************
2283 * RegGetKeySecurity [ADVAPI32.@]
2285 * Get a copy of the security descriptor for a given registry key.
2287 * PARAMS
2288 * hkey [I] Open handle of key to set
2289 * SecurityInformation [I] Descriptor contents
2290 * pSecurityDescriptor [O] Address of descriptor for key
2291 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2293 * RETURNS
2294 * Success: ERROR_SUCCESS
2295 * Failure: Error code
2297 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2298 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2299 LPDWORD lpcbSecurityDescriptor )
2301 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2302 *lpcbSecurityDescriptor);
2304 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2306 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2307 SecurityInformation, pSecurityDescriptor,
2308 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2312 /******************************************************************************
2313 * RegFlushKey [ADVAPI32.@]
2315 * Immediately write a registry key to registry.
2317 * PARAMS
2318 * hkey [I] Handle of key to write
2320 * RETURNS
2321 * Success: ERROR_SUCCESS
2322 * Failure: Error code
2324 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2326 hkey = get_special_root_hkey( hkey );
2327 if (!hkey) return ERROR_INVALID_HANDLE;
2329 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2333 /******************************************************************************
2334 * RegConnectRegistryW [ADVAPI32.@]
2336 * Establish a connection to a predefined registry key on another computer.
2338 * PARAMS
2339 * lpMachineName [I] Address of name of remote computer
2340 * hHey [I] Predefined registry handle
2341 * phkResult [I] Address of buffer for remote registry handle
2343 * RETURNS
2344 * Success: ERROR_SUCCESS
2345 * Failure: nonzero error code from Winerror.h
2347 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2348 PHKEY phkResult )
2350 LONG ret;
2352 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2354 if (!lpMachineName || !*lpMachineName) {
2355 /* Use the local machine name */
2356 ret = RegOpenKeyW( hKey, NULL, phkResult );
2358 else {
2359 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2360 DWORD len = sizeof(compName) / sizeof(WCHAR);
2362 /* MSDN says lpMachineName must start with \\ : not so */
2363 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2364 lpMachineName += 2;
2365 if (GetComputerNameW(compName, &len))
2367 if (!strcmpiW(lpMachineName, compName))
2368 ret = RegOpenKeyW(hKey, NULL, phkResult);
2369 else
2371 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2372 ret = ERROR_BAD_NETPATH;
2375 else
2376 ret = GetLastError();
2378 return ret;
2382 /******************************************************************************
2383 * RegConnectRegistryA [ADVAPI32.@]
2385 * See RegConnectRegistryW.
2387 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2389 UNICODE_STRING machineW;
2390 LONG ret;
2392 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2393 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2394 RtlFreeUnicodeString( &machineW );
2395 return ret;
2399 /******************************************************************************
2400 * RegNotifyChangeKeyValue [ADVAPI32.@]
2402 * Notify the caller about changes to the attributes or contents of a registry key.
2404 * PARAMS
2405 * hkey [I] Handle of key to watch
2406 * fWatchSubTree [I] Flag for subkey notification
2407 * fdwNotifyFilter [I] Changes to be reported
2408 * hEvent [I] Handle of signaled event
2409 * fAsync [I] Flag for asynchronous reporting
2411 * RETURNS
2412 * Success: ERROR_SUCCESS
2413 * Failure: nonzero error code from Winerror.h
2415 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2416 DWORD fdwNotifyFilter, HANDLE hEvent,
2417 BOOL fAsync )
2419 NTSTATUS status;
2420 IO_STATUS_BLOCK iosb;
2422 hkey = get_special_root_hkey( hkey );
2423 if (!hkey) return ERROR_INVALID_HANDLE;
2425 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2426 hEvent, fAsync);
2428 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2429 fdwNotifyFilter, fAsync, NULL, 0,
2430 fWatchSubTree);
2432 if (status && status != STATUS_TIMEOUT)
2433 return RtlNtStatusToDosError( status );
2435 return ERROR_SUCCESS;
2438 /******************************************************************************
2439 * RegOpenUserClassesRoot [ADVAPI32.@]
2441 * Open the HKEY_CLASSES_ROOT key for a user.
2443 * PARAMS
2444 * hToken [I] Handle of token representing the user
2445 * dwOptions [I] Reserved, must be 0
2446 * samDesired [I] Desired access rights
2447 * phkResult [O] Destination for the resulting key handle
2449 * RETURNS
2450 * Success: ERROR_SUCCESS
2451 * Failure: nonzero error code from Winerror.h
2453 * NOTES
2454 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2455 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2456 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2458 LSTATUS WINAPI RegOpenUserClassesRoot(
2459 HANDLE hToken,
2460 DWORD dwOptions,
2461 REGSAM samDesired,
2462 PHKEY phkResult
2465 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2467 *phkResult = HKEY_CLASSES_ROOT;
2468 return ERROR_SUCCESS;
2471 /******************************************************************************
2472 * load_string [Internal]
2474 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2475 * avoid importing user32, which is higher level than advapi32. Helper for
2476 * RegLoadMUIString.
2478 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2480 HGLOBAL hMemory;
2481 HRSRC hResource;
2482 WCHAR *pString;
2483 int idxString;
2485 /* Negative values have to be inverted. */
2486 if (HIWORD(resId) == 0xffff)
2487 resId = (UINT)(-((INT)resId));
2489 /* Load the resource into memory and get a pointer to it. */
2490 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2491 if (!hResource) return 0;
2492 hMemory = LoadResource(hModule, hResource);
2493 if (!hMemory) return 0;
2494 pString = LockResource(hMemory);
2496 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2497 idxString = resId & 0xf;
2498 while (idxString--) pString += *pString + 1;
2500 /* If no buffer is given, return length of the string. */
2501 if (!pwszBuffer) return *pString;
2503 /* Else copy over the string, respecting the buffer size. */
2504 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2505 if (cMaxChars >= 0) {
2506 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2507 pwszBuffer[cMaxChars] = '\0';
2510 return cMaxChars;
2513 /******************************************************************************
2514 * RegLoadMUIStringW [ADVAPI32.@]
2516 * Load the localized version of a string resource from some PE, respective
2517 * id and path of which are given in the registry value in the format
2518 * @[path]\dllname,-resourceId
2520 * PARAMS
2521 * hKey [I] Key, of which to load the string value from.
2522 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2523 * pszBuffer [O] Buffer to store the localized string in.
2524 * cbBuffer [I] Size of the destination buffer in bytes.
2525 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2526 * dwFlags [I] None supported yet.
2527 * pszBaseDir [I] Not supported yet.
2529 * RETURNS
2530 * Success: ERROR_SUCCESS,
2531 * Failure: nonzero error code from winerror.h
2533 * NOTES
2534 * This is an API of Windows Vista, which wasn't available at the time this code
2535 * was written. We have to check for the correct behaviour once it's available.
2537 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2538 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2540 DWORD dwValueType, cbData;
2541 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2542 LONG result;
2544 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2545 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2546 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2548 /* Parameter sanity checks. */
2549 if (!hKey || !pwszBuffer)
2550 return ERROR_INVALID_PARAMETER;
2552 if (pwszBaseDir && *pwszBaseDir) {
2553 FIXME("BaseDir parameter not yet supported!\n");
2554 return ERROR_INVALID_PARAMETER;
2557 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2558 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2559 if (result != ERROR_SUCCESS) goto cleanup;
2560 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2561 result = ERROR_FILE_NOT_FOUND;
2562 goto cleanup;
2564 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2565 if (!pwszTempBuffer) {
2566 result = ERROR_NOT_ENOUGH_MEMORY;
2567 goto cleanup;
2569 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2570 if (result != ERROR_SUCCESS) goto cleanup;
2572 /* Expand environment variables, if appropriate, or copy the original string over. */
2573 if (dwValueType == REG_EXPAND_SZ) {
2574 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2575 if (!cbData) goto cleanup;
2576 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2577 if (!pwszExpandedBuffer) {
2578 result = ERROR_NOT_ENOUGH_MEMORY;
2579 goto cleanup;
2581 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2582 } else {
2583 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2584 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2587 /* If the value references a resource based string, parse the value and load the string.
2588 * Else just copy over the original value. */
2589 result = ERROR_SUCCESS;
2590 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2591 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2592 } else {
2593 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2594 UINT uiStringId;
2595 HMODULE hModule;
2597 /* Format of the expanded value is 'path_to_dll,-resId' */
2598 if (!pComma || pComma[1] != '-') {
2599 result = ERROR_BADKEY;
2600 goto cleanup;
2603 uiStringId = atoiW(pComma+2);
2604 *pComma = '\0';
2606 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2607 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2608 result = ERROR_BADKEY;
2609 FreeLibrary(hModule);
2612 cleanup:
2613 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2614 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2615 return result;
2618 /******************************************************************************
2619 * RegLoadMUIStringA [ADVAPI32.@]
2621 * See RegLoadMUIStringW
2623 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2624 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2626 UNICODE_STRING valueW, baseDirW;
2627 WCHAR *pwszBuffer;
2628 DWORD cbData = cbBuffer * sizeof(WCHAR);
2629 LONG result;
2631 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2632 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2633 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2634 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2636 result = ERROR_NOT_ENOUGH_MEMORY;
2637 goto cleanup;
2640 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2641 baseDirW.Buffer);
2643 if (result == ERROR_SUCCESS) {
2644 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2645 if (pcbData)
2646 *pcbData = cbData;
2649 cleanup:
2650 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2651 RtlFreeUnicodeString(&baseDirW);
2652 RtlFreeUnicodeString(&valueW);
2654 return result;
2657 /******************************************************************************
2658 * RegDisablePredefinedCache [ADVAPI32.@]
2660 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2662 * PARAMS
2663 * None.
2665 * RETURNS
2666 * Success: ERROR_SUCCESS
2667 * Failure: nonzero error code from Winerror.h
2669 * NOTES
2670 * This is useful for services that use impersonation.
2672 LSTATUS WINAPI RegDisablePredefinedCache(void)
2674 HKEY hkey_current_user;
2675 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2677 /* prevent caching of future requests */
2678 hkcu_cache_disabled = TRUE;
2680 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2682 if (hkey_current_user)
2683 NtClose( hkey_current_user );
2685 return ERROR_SUCCESS;
2688 /******************************************************************************
2689 * RegDeleteTreeW [ADVAPI32.@]
2692 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2694 LONG ret;
2695 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2696 DWORD dwMaxLen, dwSize;
2697 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2698 HKEY hSubKey = hKey;
2700 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2702 if(lpszSubKey)
2704 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2705 if (ret) return ret;
2708 /* Get highest length for keys, values */
2709 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2710 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2711 if (ret) goto cleanup;
2713 dwMaxSubkeyLen++;
2714 dwMaxValueLen++;
2715 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2716 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2718 /* Name too big: alloc a buffer for it */
2719 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2721 ret = ERROR_NOT_ENOUGH_MEMORY;
2722 goto cleanup;
2727 /* Recursively delete all the subkeys */
2728 while (TRUE)
2730 dwSize = dwMaxLen;
2731 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2732 NULL, NULL, NULL)) break;
2734 ret = RegDeleteTreeW(hSubKey, lpszName);
2735 if (ret) goto cleanup;
2738 if (lpszSubKey)
2739 ret = RegDeleteKeyW(hKey, lpszSubKey);
2740 else
2741 while (TRUE)
2743 dwSize = dwMaxLen;
2744 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2745 NULL, NULL, NULL, NULL)) break;
2747 ret = RegDeleteValueW(hKey, lpszName);
2748 if (ret) goto cleanup;
2751 cleanup:
2752 /* Free buffer if allocated */
2753 if (lpszName != szNameBuf)
2754 HeapFree( GetProcessHeap(), 0, lpszName);
2755 if(lpszSubKey)
2756 RegCloseKey(hSubKey);
2757 return ret;
2760 /******************************************************************************
2761 * RegDeleteTreeA [ADVAPI32.@]
2764 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2766 LONG ret;
2767 UNICODE_STRING lpszSubKeyW;
2769 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2770 else lpszSubKeyW.Buffer = NULL;
2771 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2772 RtlFreeUnicodeString( &lpszSubKeyW );
2773 return ret;