advapi32: Don't use the static Unicode buffer for value names since they can be large...
[wine/multimedia.git] / dlls / advapi32 / registry.c
blob9266d3ff82b353e4301d78d513dc69703789e016
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 /* wrapper for NtCreateKey that creates the key recursively if necessary */
95 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
96 const UNICODE_STRING *class, ULONG options, PULONG dispos )
98 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class, options, dispos );
100 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
102 DWORD attrs, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
104 while (i < len && attr->ObjectName->Buffer[i] != '\\') i++;
105 if (i == len) return status;
106 attrs = attr->Attributes;
107 attr->Attributes &= ~OBJ_OPENLINK;
109 while (i < len)
111 attr->ObjectName->Length = i * sizeof(WCHAR);
112 status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class,
113 options & ~REG_OPTION_CREATE_LINK, dispos );
114 if (status) return status;
115 NtClose( *retkey );
116 while (i < len && attr->ObjectName->Buffer[i] == '\\') i++;
117 while (i < len && attr->ObjectName->Buffer[i] != '\\') i++;
119 attr->Attributes = attrs;
120 attr->ObjectName->Length = len * sizeof(WCHAR);
121 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, class, options, dispos );
123 return status;
126 /* create one of the HKEY_* special root keys */
127 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
129 HKEY ret = 0;
130 int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
132 if (hkey == HKEY_CURRENT_USER)
134 if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
135 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
137 /* don't cache the key in the table if caching is disabled */
138 if (hkcu_cache_disabled)
139 return hkey;
141 else
143 OBJECT_ATTRIBUTES attr;
144 UNICODE_STRING name;
146 attr.Length = sizeof(attr);
147 attr.RootDirectory = 0;
148 attr.ObjectName = &name;
149 attr.Attributes = 0;
150 attr.SecurityDescriptor = NULL;
151 attr.SecurityQualityOfService = NULL;
152 RtlInitUnicodeString( &name, root_key_names[idx] );
153 if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0;
154 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
157 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
158 ret = hkey;
159 else
160 NtClose( hkey ); /* somebody beat us to it */
161 return ret;
164 /* map the hkey from special root to normal key if necessary */
165 static inline HKEY get_special_root_hkey( HKEY hkey )
167 HKEY ret = hkey;
169 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
171 if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
172 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED );
174 return ret;
178 /******************************************************************************
179 * RegOverridePredefKey [ADVAPI32.@]
181 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
183 HKEY old_key;
184 int idx;
186 if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST))
187 return ERROR_INVALID_PARAMETER;
188 idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
190 if (override)
192 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
193 GetCurrentProcess(), (HANDLE *)&override,
194 0, 0, DUPLICATE_SAME_ACCESS );
195 if (status) return RtlNtStatusToDosError( status );
198 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
199 if (old_key) NtClose( old_key );
200 return ERROR_SUCCESS;
204 /******************************************************************************
205 * RegCreateKeyExW [ADVAPI32.@]
207 * See RegCreateKeyExA.
209 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
210 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
211 PHKEY retkey, LPDWORD dispos )
213 OBJECT_ATTRIBUTES attr;
214 UNICODE_STRING nameW, classW;
216 if (reserved) return ERROR_INVALID_PARAMETER;
217 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
219 attr.Length = sizeof(attr);
220 attr.RootDirectory = hkey;
221 attr.ObjectName = &nameW;
222 attr.Attributes = 0;
223 attr.SecurityDescriptor = NULL;
224 attr.SecurityQualityOfService = NULL;
225 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
226 RtlInitUnicodeString( &nameW, name );
227 RtlInitUnicodeString( &classW, class );
229 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
233 /******************************************************************************
234 * RegCreateKeyExA [ADVAPI32.@]
236 * Open a registry key, creating it if it doesn't exist.
238 * PARAMS
239 * hkey [I] Handle of the parent registry key
240 * name [I] Name of the new key to open or create
241 * reserved [I] Reserved, pass 0
242 * class [I] The object type of the new key
243 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
244 * access [I] Access level desired
245 * sa [I] Security attributes for the key
246 * retkey [O] Destination for the resulting handle
247 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
249 * RETURNS
250 * Success: ERROR_SUCCESS.
251 * Failure: A standard Win32 error code. retkey remains untouched.
253 * FIXME
254 * MAXIMUM_ALLOWED in access mask not supported by server
256 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
257 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
258 PHKEY retkey, LPDWORD dispos )
260 OBJECT_ATTRIBUTES attr;
261 UNICODE_STRING classW;
262 ANSI_STRING nameA, classA;
263 NTSTATUS status;
265 if (reserved) return ERROR_INVALID_PARAMETER;
266 if (!is_version_nt())
268 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
269 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
271 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
273 attr.Length = sizeof(attr);
274 attr.RootDirectory = hkey;
275 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
276 attr.Attributes = 0;
277 attr.SecurityDescriptor = NULL;
278 attr.SecurityQualityOfService = NULL;
279 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
280 RtlInitAnsiString( &nameA, name );
281 RtlInitAnsiString( &classA, class );
283 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
284 &nameA, FALSE )))
286 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
288 status = create_key( retkey, access, &attr, &classW, options, dispos );
289 RtlFreeUnicodeString( &classW );
292 return RtlNtStatusToDosError( status );
296 /******************************************************************************
297 * RegCreateKeyW [ADVAPI32.@]
299 * Creates the specified reg key.
301 * PARAMS
302 * hKey [I] Handle to an open key.
303 * lpSubKey [I] Name of a key that will be opened or created.
304 * phkResult [O] Receives a handle to the opened or created key.
306 * RETURNS
307 * Success: ERROR_SUCCESS
308 * Failure: nonzero error code defined in Winerror.h
310 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
312 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
313 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
314 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
315 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
319 /******************************************************************************
320 * RegCreateKeyA [ADVAPI32.@]
322 * See RegCreateKeyW.
324 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
326 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
327 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
332 /******************************************************************************
333 * RegOpenKeyExW [ADVAPI32.@]
335 * See RegOpenKeyExA.
337 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
339 OBJECT_ATTRIBUTES attr;
340 UNICODE_STRING nameW;
342 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
343 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
345 if (!retkey) return ERROR_INVALID_PARAMETER;
346 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
348 attr.Length = sizeof(attr);
349 attr.RootDirectory = hkey;
350 attr.ObjectName = &nameW;
351 attr.Attributes = 0;
352 attr.SecurityDescriptor = NULL;
353 attr.SecurityQualityOfService = NULL;
354 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
355 RtlInitUnicodeString( &nameW, name );
356 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE)retkey, access, &attr ) );
360 /******************************************************************************
361 * RegOpenKeyExA [ADVAPI32.@]
363 * Open a registry key.
365 * PARAMS
366 * hkey [I] Handle of open key
367 * name [I] Name of subkey to open
368 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
369 * access [I] Security access mask
370 * retkey [O] Handle to open key
372 * RETURNS
373 * Success: ERROR_SUCCESS
374 * Failure: A standard Win32 error code. retkey is set to 0.
376 * NOTES
377 * Unlike RegCreateKeyExA(), this function will not create the key if it
378 * does not exist.
380 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
382 OBJECT_ATTRIBUTES attr;
383 STRING nameA;
384 NTSTATUS status;
386 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
387 else
389 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
390 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
393 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
395 attr.Length = sizeof(attr);
396 attr.RootDirectory = hkey;
397 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
398 attr.Attributes = 0;
399 attr.SecurityDescriptor = NULL;
400 attr.SecurityQualityOfService = NULL;
401 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
403 RtlInitAnsiString( &nameA, name );
404 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
405 &nameA, FALSE )))
407 status = NtOpenKey( (PHANDLE)retkey, access, &attr );
409 return RtlNtStatusToDosError( status );
413 /******************************************************************************
414 * RegOpenKeyW [ADVAPI32.@]
416 * See RegOpenKeyA.
418 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
420 if (!retkey)
421 return ERROR_INVALID_PARAMETER;
423 if (!name || !*name)
425 *retkey = hkey;
426 return ERROR_SUCCESS;
428 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
432 /******************************************************************************
433 * RegOpenKeyA [ADVAPI32.@]
435 * Open a registry key.
437 * PARAMS
438 * hkey [I] Handle of parent key to open the new key under
439 * name [I] Name of the key under hkey to open
440 * retkey [O] Destination for the resulting Handle
442 * RETURNS
443 * Success: ERROR_SUCCESS
444 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
446 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
448 if (!retkey)
449 return ERROR_INVALID_PARAMETER;
451 if (!name || !*name)
453 *retkey = hkey;
454 return ERROR_SUCCESS;
456 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
460 /******************************************************************************
461 * RegOpenCurrentUser [ADVAPI32.@]
463 * Get a handle to the HKEY_CURRENT_USER key for the user
464 * the current thread is impersonating.
466 * PARAMS
467 * access [I] Desired access rights to the key
468 * retkey [O] Handle to the opened key
470 * RETURNS
471 * Success: ERROR_SUCCESS
472 * Failure: nonzero error code from Winerror.h
474 * FIXME
475 * This function is supposed to retrieve a handle to the
476 * HKEY_CURRENT_USER for the user the current thread is impersonating.
477 * Since Wine does not currently allow threads to impersonate other users,
478 * this stub should work fine.
480 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
482 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
487 /******************************************************************************
488 * RegEnumKeyExW [ADVAPI32.@]
490 * Enumerate subkeys of the specified open registry key.
492 * PARAMS
493 * hkey [I] Handle to key to enumerate
494 * index [I] Index of subkey to enumerate
495 * name [O] Buffer for subkey name
496 * name_len [O] Size of subkey buffer
497 * reserved [I] Reserved
498 * class [O] Buffer for class string
499 * class_len [O] Size of class buffer
500 * ft [O] Time key last written to
502 * RETURNS
503 * Success: ERROR_SUCCESS
504 * Failure: System error code. If there are no more subkeys available, the
505 * function returns ERROR_NO_MORE_ITEMS.
507 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
508 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
510 NTSTATUS status;
511 char buffer[256], *buf_ptr = buffer;
512 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
513 DWORD total_size;
515 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
516 name_len ? *name_len : 0, reserved, class, class_len, ft );
518 if (reserved) return ERROR_INVALID_PARAMETER;
519 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
521 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
522 buffer, sizeof(buffer), &total_size );
524 while (status == STATUS_BUFFER_OVERFLOW)
526 /* retry with a dynamically allocated buffer */
527 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
528 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
529 return ERROR_NOT_ENOUGH_MEMORY;
530 info = (KEY_NODE_INFORMATION *)buf_ptr;
531 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
532 buf_ptr, total_size, &total_size );
535 if (!status)
537 DWORD len = info->NameLength / sizeof(WCHAR);
538 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
540 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
542 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
543 status = STATUS_BUFFER_OVERFLOW;
544 else
546 *name_len = len;
547 memcpy( name, info->Name, info->NameLength );
548 name[len] = 0;
549 if (class_len)
551 *class_len = cls_len;
552 if (class)
554 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
555 class[cls_len] = 0;
561 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
562 return RtlNtStatusToDosError( status );
566 /******************************************************************************
567 * RegEnumKeyExA [ADVAPI32.@]
569 * See RegEnumKeyExW.
571 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
572 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
574 NTSTATUS status;
575 char buffer[256], *buf_ptr = buffer;
576 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
577 DWORD total_size;
579 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
580 name_len ? *name_len : 0, reserved, class, class_len, ft );
582 if (reserved) return ERROR_INVALID_PARAMETER;
583 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
585 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
586 buffer, sizeof(buffer), &total_size );
588 while (status == STATUS_BUFFER_OVERFLOW)
590 /* retry with a dynamically allocated buffer */
591 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
592 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
593 return ERROR_NOT_ENOUGH_MEMORY;
594 info = (KEY_NODE_INFORMATION *)buf_ptr;
595 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
596 buf_ptr, total_size, &total_size );
599 if (!status)
601 DWORD len, cls_len;
603 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
604 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
605 info->ClassLength );
606 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
608 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
609 status = STATUS_BUFFER_OVERFLOW;
610 else
612 *name_len = len;
613 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
614 name[len] = 0;
615 if (class_len)
617 *class_len = cls_len;
618 if (class)
620 RtlUnicodeToMultiByteN( class, cls_len, NULL,
621 (WCHAR *)(buf_ptr + info->ClassOffset),
622 info->ClassLength );
623 class[cls_len] = 0;
629 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
630 return RtlNtStatusToDosError( status );
634 /******************************************************************************
635 * RegEnumKeyW [ADVAPI32.@]
637 * Enumerates subkeys of the specified open reg key.
639 * PARAMS
640 * hKey [I] Handle to an open key.
641 * dwIndex [I] Index of the subkey of hKey to retrieve.
642 * lpName [O] Name of the subkey.
643 * cchName [I] Size of lpName in TCHARS.
645 * RETURNS
646 * Success: ERROR_SUCCESS
647 * Failure: system error code. If there are no more subkeys available, the
648 * function returns ERROR_NO_MORE_ITEMS.
650 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
652 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
656 /******************************************************************************
657 * RegEnumKeyA [ADVAPI32.@]
659 * See RegEnumKeyW.
661 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
663 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
667 /******************************************************************************
668 * RegQueryInfoKeyW [ADVAPI32.@]
670 * Retrieves information about the specified registry key.
672 * PARAMS
673 * hkey [I] Handle to key to query
674 * class [O] Buffer for class string
675 * class_len [O] Size of class string buffer
676 * reserved [I] Reserved
677 * subkeys [O] Buffer for number of subkeys
678 * max_subkey [O] Buffer for longest subkey name length
679 * max_class [O] Buffer for longest class string length
680 * values [O] Buffer for number of value entries
681 * max_value [O] Buffer for longest value name length
682 * max_data [O] Buffer for longest value data length
683 * security [O] Buffer for security descriptor length
684 * modif [O] Modification time
686 * RETURNS
687 * Success: ERROR_SUCCESS
688 * Failure: system error code.
690 * NOTES
691 * - win95 allows class to be valid and class_len to be NULL
692 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
693 * - both allow class to be NULL and class_len to be NULL
694 * (it's hard to test validity, so test !NULL instead)
696 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
697 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
698 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
699 LPDWORD security, FILETIME *modif )
701 NTSTATUS status;
702 char buffer[256], *buf_ptr = buffer;
703 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
704 DWORD total_size;
706 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
707 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
709 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
710 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
712 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
713 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
715 if (class)
717 /* retry with a dynamically allocated buffer */
718 while (status == STATUS_BUFFER_OVERFLOW)
720 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
721 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
722 return ERROR_NOT_ENOUGH_MEMORY;
723 info = (KEY_FULL_INFORMATION *)buf_ptr;
724 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
727 if (status) goto done;
729 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
731 status = STATUS_BUFFER_OVERFLOW;
733 else
735 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
736 class[info->ClassLength/sizeof(WCHAR)] = 0;
739 else status = STATUS_SUCCESS;
741 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
742 if (subkeys) *subkeys = info->SubKeys;
743 if (max_subkey) *max_subkey = info->MaxNameLen;
744 if (max_class) *max_class = info->MaxClassLen;
745 if (values) *values = info->Values;
746 if (max_value) *max_value = info->MaxValueNameLen;
747 if (max_data) *max_data = info->MaxValueDataLen;
748 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
750 done:
751 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
752 return RtlNtStatusToDosError( status );
756 /******************************************************************************
757 * RegQueryMultipleValuesA [ADVAPI32.@]
759 * Retrieves the type and data for a list of value names associated with a key.
761 * PARAMS
762 * hKey [I] Handle to an open key.
763 * val_list [O] Array of VALENT structures that describes the entries.
764 * num_vals [I] Number of elements in val_list.
765 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
766 * ldwTotsize [I/O] Size of lpValueBuf.
768 * RETURNS
769 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
770 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
771 * bytes.
773 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
774 LPSTR lpValueBuf, LPDWORD ldwTotsize )
776 unsigned int i;
777 DWORD maxBytes = *ldwTotsize;
778 HRESULT status;
779 LPSTR bufptr = lpValueBuf;
780 *ldwTotsize = 0;
782 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
784 for(i=0; i < num_vals; ++i)
787 val_list[i].ve_valuelen=0;
788 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
789 if(status != ERROR_SUCCESS)
791 return status;
794 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
796 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
797 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
798 if(status != ERROR_SUCCESS)
800 return status;
803 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
805 bufptr += val_list[i].ve_valuelen;
808 *ldwTotsize += val_list[i].ve_valuelen;
810 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
814 /******************************************************************************
815 * RegQueryMultipleValuesW [ADVAPI32.@]
817 * See RegQueryMultipleValuesA.
819 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
820 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
822 unsigned int i;
823 DWORD maxBytes = *ldwTotsize;
824 HRESULT status;
825 LPSTR bufptr = (LPSTR)lpValueBuf;
826 *ldwTotsize = 0;
828 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
830 for(i=0; i < num_vals; ++i)
832 val_list[i].ve_valuelen=0;
833 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
834 if(status != ERROR_SUCCESS)
836 return status;
839 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
841 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
842 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
843 if(status != ERROR_SUCCESS)
845 return status;
848 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
850 bufptr += val_list[i].ve_valuelen;
853 *ldwTotsize += val_list[i].ve_valuelen;
855 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
858 /******************************************************************************
859 * RegQueryInfoKeyA [ADVAPI32.@]
861 * Retrieves information about a registry key.
863 * PARAMS
864 * hKey [I] Handle to an open key.
865 * lpClass [O] Class string of the key.
866 * lpcClass [I/O] size of lpClass.
867 * lpReserved [I] Reserved; must be NULL.
868 * lpcSubKeys [O] Number of subkeys contained by the key.
869 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
870 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
871 * class in TCHARS.
872 * lpcValues [O] Number of values associated with the key.
873 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
874 * lpcMaxValueLen [O] Longest data component among the key's values
875 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
876 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
878 * RETURNS
879 * Success: ERROR_SUCCESS
880 * Failure: nonzero error code from Winerror.h
882 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
883 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
884 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
885 LPDWORD security, FILETIME *modif )
887 NTSTATUS status;
888 char buffer[256], *buf_ptr = buffer;
889 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
890 DWORD total_size, len;
892 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
893 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
895 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
896 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
898 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
899 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
901 if (class || class_len)
903 /* retry with a dynamically allocated buffer */
904 while (status == STATUS_BUFFER_OVERFLOW)
906 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
907 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
908 return ERROR_NOT_ENOUGH_MEMORY;
909 info = (KEY_FULL_INFORMATION *)buf_ptr;
910 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
913 if (status) goto done;
915 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
916 if (class_len)
918 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
919 *class_len = len;
921 if (class && !status)
923 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
924 info->ClassLength );
925 class[len] = 0;
928 else status = STATUS_SUCCESS;
930 if (subkeys) *subkeys = info->SubKeys;
931 if (max_subkey) *max_subkey = info->MaxNameLen;
932 if (max_class) *max_class = info->MaxClassLen;
933 if (values) *values = info->Values;
934 if (max_value) *max_value = info->MaxValueNameLen;
935 if (max_data) *max_data = info->MaxValueDataLen;
936 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
938 done:
939 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
940 return RtlNtStatusToDosError( status );
944 /******************************************************************************
945 * RegCloseKey [ADVAPI32.@]
947 * Close an open registry key.
949 * PARAMS
950 * hkey [I] Handle of key to close
952 * RETURNS
953 * Success: ERROR_SUCCESS
954 * Failure: Error code
956 LSTATUS WINAPI RegCloseKey( HKEY hkey )
958 if (!hkey) return ERROR_INVALID_HANDLE;
959 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
960 return RtlNtStatusToDosError( NtClose( hkey ) );
964 /******************************************************************************
965 * RegDeleteKeyExW [ADVAPI32.@]
967 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
969 DWORD ret;
970 HKEY tmp;
972 if (!name) return ERROR_INVALID_PARAMETER;
974 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
976 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
977 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
979 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
980 RegCloseKey( tmp );
982 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
983 return ret;
987 /******************************************************************************
988 * RegDeleteKeyW [ADVAPI32.@]
990 * See RegDeleteKeyA.
992 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
994 return RegDeleteKeyExW( hkey, name, 0, 0 );
998 /******************************************************************************
999 * RegDeleteKeyExA [ADVAPI32.@]
1001 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1003 DWORD ret;
1004 HKEY tmp;
1006 if (!name) return ERROR_INVALID_PARAMETER;
1008 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1010 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1011 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1013 if (!is_version_nt()) /* win95 does recursive key deletes */
1015 CHAR name[MAX_PATH];
1017 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
1019 if(RegDeleteKeyExA(tmp, name, access, reserved)) /* recurse */
1020 break;
1023 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1024 RegCloseKey( tmp );
1026 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1027 return ret;
1031 /******************************************************************************
1032 * RegDeleteKeyA [ADVAPI32.@]
1034 * Delete a registry key.
1036 * PARAMS
1037 * hkey [I] Handle to parent key containing the key to delete
1038 * name [I] Name of the key user hkey to delete
1040 * NOTES
1042 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1043 * right. In reality, it opens a new handle with DELETE access.
1045 * RETURNS
1046 * Success: ERROR_SUCCESS
1047 * Failure: Error code
1049 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1051 return RegDeleteKeyExA( hkey, name, 0, 0 );
1056 /******************************************************************************
1057 * RegSetValueExW [ADVAPI32.@]
1059 * Set the data and contents of a registry value.
1061 * PARAMS
1062 * hkey [I] Handle of key to set value for
1063 * name [I] Name of value to set
1064 * reserved [I] Reserved, must be zero
1065 * type [I] Type of the value being set
1066 * data [I] The new contents of the value to set
1067 * count [I] Size of data
1069 * RETURNS
1070 * Success: ERROR_SUCCESS
1071 * Failure: Error code
1073 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1074 DWORD type, CONST BYTE *data, DWORD count )
1076 UNICODE_STRING nameW;
1078 /* no need for version check, not implemented on win9x anyway */
1079 if (count && is_string(type))
1081 LPCWSTR str = (LPCWSTR)data;
1082 /* if user forgot to count terminating null, add it (yes NT does this) */
1083 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1084 count += sizeof(WCHAR);
1086 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1088 RtlInitUnicodeString( &nameW, name );
1089 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1093 /******************************************************************************
1094 * RegSetValueExA [ADVAPI32.@]
1096 * See RegSetValueExW.
1098 * NOTES
1099 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1100 * NT does definitely care (aj)
1102 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1103 CONST BYTE *data, DWORD count )
1105 ANSI_STRING nameA;
1106 UNICODE_STRING nameW;
1107 WCHAR *dataW = NULL;
1108 NTSTATUS status;
1110 if (!is_version_nt()) /* win95 */
1112 if (type == REG_SZ)
1114 if (!data) return ERROR_INVALID_PARAMETER;
1115 count = strlen((const char *)data) + 1;
1118 else if (count && is_string(type))
1120 /* if user forgot to count terminating null, add it (yes NT does this) */
1121 if (data[count-1] && !data[count]) count++;
1124 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1126 if (is_string( type )) /* need to convert to Unicode */
1128 DWORD lenW;
1129 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1130 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1131 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1132 count = lenW;
1133 data = (BYTE *)dataW;
1136 RtlInitAnsiString( &nameA, name );
1137 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1139 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1140 RtlFreeUnicodeString( &nameW );
1142 HeapFree( GetProcessHeap(), 0, dataW );
1143 return RtlNtStatusToDosError( status );
1147 /******************************************************************************
1148 * RegSetValueW [ADVAPI32.@]
1150 * Sets the data for the default or unnamed value of a reg key.
1152 * PARAMS
1153 * hKey [I] Handle to an open key.
1154 * lpSubKey [I] Name of a subkey of hKey.
1155 * dwType [I] Type of information to store.
1156 * lpData [I] String that contains the data to set for the default value.
1157 * cbData [I] Ignored.
1159 * RETURNS
1160 * Success: ERROR_SUCCESS
1161 * Failure: nonzero error code from Winerror.h
1163 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1165 HKEY subkey = hkey;
1166 DWORD ret;
1168 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1170 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1172 if (name && name[0]) /* need to create the subkey */
1174 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1177 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1178 (strlenW( data ) + 1) * sizeof(WCHAR) );
1179 if (subkey != hkey) RegCloseKey( subkey );
1180 return ret;
1184 /******************************************************************************
1185 * RegSetValueA [ADVAPI32.@]
1187 * See RegSetValueW.
1189 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1191 HKEY subkey = hkey;
1192 DWORD ret;
1194 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1196 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1198 if (name && name[0]) /* need to create the subkey */
1200 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1202 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1203 if (subkey != hkey) RegCloseKey( subkey );
1204 return ret;
1209 /******************************************************************************
1210 * RegQueryValueExW [ADVAPI32.@]
1212 * See RegQueryValueExA.
1214 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1215 LPBYTE data, LPDWORD count )
1217 NTSTATUS status;
1218 UNICODE_STRING name_str;
1219 DWORD total_size;
1220 char buffer[256], *buf_ptr = buffer;
1221 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1222 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1224 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1225 hkey, debugstr_w(name), reserved, type, data, count,
1226 (count && data) ? *count : 0 );
1228 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1229 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1231 RtlInitUnicodeString( &name_str, name );
1233 if (data) total_size = min( sizeof(buffer), *count + info_size );
1234 else
1236 total_size = info_size;
1237 if (count) *count = 0;
1240 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1241 buffer, total_size, &total_size );
1242 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1244 if (data)
1246 /* retry with a dynamically allocated buffer */
1247 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1249 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1250 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1251 return ERROR_NOT_ENOUGH_MEMORY;
1252 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1253 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1254 buf_ptr, total_size, &total_size );
1257 if (!status)
1259 memcpy( data, buf_ptr + info_size, total_size - info_size );
1260 /* if the type is REG_SZ and data is not 0-terminated
1261 * and there is enough space in the buffer NT appends a \0 */
1262 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1264 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1265 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1268 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1270 else status = STATUS_SUCCESS;
1272 if (type) *type = info->Type;
1273 if (count) *count = total_size - info_size;
1275 done:
1276 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1277 return RtlNtStatusToDosError(status);
1281 /******************************************************************************
1282 * RegQueryValueExA [ADVAPI32.@]
1284 * Get the type and contents of a specified value under with a key.
1286 * PARAMS
1287 * hkey [I] Handle of the key to query
1288 * name [I] Name of value under hkey to query
1289 * reserved [I] Reserved - must be NULL
1290 * type [O] Destination for the value type, or NULL if not required
1291 * data [O] Destination for the values contents, or NULL if not required
1292 * count [I/O] Size of data, updated with the number of bytes returned
1294 * RETURNS
1295 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1296 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1297 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1298 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1300 * NOTES
1301 * MSDN states that if data is too small it is partially filled. In reality
1302 * it remains untouched.
1304 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1305 LPBYTE data, LPDWORD count )
1307 NTSTATUS status;
1308 ANSI_STRING nameA;
1309 UNICODE_STRING nameW;
1310 DWORD total_size, datalen = 0;
1311 char buffer[256], *buf_ptr = buffer;
1312 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1313 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1315 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1316 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1318 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1319 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1321 if (count) datalen = *count;
1322 if (!data && count) *count = 0;
1324 /* this matches Win9x behaviour - NT sets *type to a random value */
1325 if (type) *type = REG_NONE;
1327 RtlInitAnsiString( &nameA, name );
1328 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1329 return RtlNtStatusToDosError(status);
1331 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1332 buffer, sizeof(buffer), &total_size );
1333 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1335 /* we need to fetch the contents for a string type even if not requested,
1336 * because we need to compute the length of the ASCII string. */
1337 if (data || is_string(info->Type))
1339 /* retry with a dynamically allocated buffer */
1340 while (status == STATUS_BUFFER_OVERFLOW)
1342 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1343 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1345 status = STATUS_NO_MEMORY;
1346 goto done;
1348 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1349 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1350 buf_ptr, total_size, &total_size );
1353 if (status) goto done;
1355 if (is_string(info->Type))
1357 DWORD len;
1359 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1360 total_size - info_size );
1361 if (data && len)
1363 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1364 else
1366 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1367 total_size - info_size );
1368 /* if the type is REG_SZ and data is not 0-terminated
1369 * and there is enough space in the buffer NT appends a \0 */
1370 if (len < datalen && data[len-1]) data[len] = 0;
1373 total_size = len + info_size;
1375 else if (data)
1377 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1378 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1381 else status = STATUS_SUCCESS;
1383 if (type) *type = info->Type;
1384 if (count) *count = total_size - info_size;
1386 done:
1387 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1388 RtlFreeUnicodeString( &nameW );
1389 return RtlNtStatusToDosError(status);
1393 /******************************************************************************
1394 * RegQueryValueW [ADVAPI32.@]
1396 * Retrieves the data associated with the default or unnamed value of a key.
1398 * PARAMS
1399 * hkey [I] Handle to an open key.
1400 * name [I] Name of the subkey of hKey.
1401 * data [O] Receives the string associated with the default value
1402 * of the key.
1403 * count [I/O] Size of lpValue in bytes.
1405 * RETURNS
1406 * Success: ERROR_SUCCESS
1407 * Failure: nonzero error code from Winerror.h
1409 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1411 DWORD ret;
1412 HKEY subkey = hkey;
1414 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1416 if (name && name[0])
1418 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1420 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1421 if (subkey != hkey) RegCloseKey( subkey );
1422 if (ret == ERROR_FILE_NOT_FOUND)
1424 /* return empty string if default value not found */
1425 if (data) *data = 0;
1426 if (count) *count = sizeof(WCHAR);
1427 ret = ERROR_SUCCESS;
1429 return ret;
1433 /******************************************************************************
1434 * RegQueryValueA [ADVAPI32.@]
1436 * See RegQueryValueW.
1438 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1440 DWORD ret;
1441 HKEY subkey = hkey;
1443 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1445 if (name && name[0])
1447 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1449 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1450 if (subkey != hkey) RegCloseKey( subkey );
1451 if (ret == ERROR_FILE_NOT_FOUND)
1453 /* return empty string if default value not found */
1454 if (data) *data = 0;
1455 if (count) *count = 1;
1456 ret = ERROR_SUCCESS;
1458 return ret;
1462 /******************************************************************************
1463 * ADVAPI_ApplyRestrictions [internal]
1465 * Helper function for RegGetValueA/W.
1467 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1468 DWORD cbData, PLONG ret )
1470 /* Check if the type is restricted by the passed flags */
1471 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1473 DWORD dwMask = 0;
1475 switch (dwType)
1477 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1478 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1479 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1480 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1481 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1482 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1483 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1486 if (dwFlags & dwMask)
1488 /* Type is not restricted, check for size mismatch */
1489 if (dwType == REG_BINARY)
1491 DWORD cbExpect = 0;
1493 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1494 cbExpect = 4;
1495 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1496 cbExpect = 8;
1498 if (cbExpect && cbData != cbExpect)
1499 *ret = ERROR_DATATYPE_MISMATCH;
1502 else *ret = ERROR_UNSUPPORTED_TYPE;
1507 /******************************************************************************
1508 * RegGetValueW [ADVAPI32.@]
1510 * Retrieves the type and data for a value name associated with a key,
1511 * optionally expanding its content and restricting its type.
1513 * PARAMS
1514 * hKey [I] Handle to an open key.
1515 * pszSubKey [I] Name of the subkey of hKey.
1516 * pszValue [I] Name of value under hKey/szSubKey to query.
1517 * dwFlags [I] Flags restricting the value type to retrieve.
1518 * pdwType [O] Destination for the values type, may be NULL.
1519 * pvData [O] Destination for the values content, may be NULL.
1520 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1521 * retrieve the whole content, including the trailing '\0'
1522 * for strings.
1524 * RETURNS
1525 * Success: ERROR_SUCCESS
1526 * Failure: nonzero error code from Winerror.h
1528 * NOTES
1529 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1530 * expanded and pdwType is set to REG_SZ instead.
1531 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1532 * without RRF_NOEXPAND is thus not allowed.
1533 * An exception is the case where RRF_RT_ANY is specified, because then
1534 * RRF_NOEXPAND is allowed.
1536 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1537 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1538 LPDWORD pcbData )
1540 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1541 PVOID pvBuf = NULL;
1542 LONG ret;
1544 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1545 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1546 pvData, pcbData, cbData);
1548 if (pvData && !pcbData)
1549 return ERROR_INVALID_PARAMETER;
1550 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1551 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1552 return ERROR_INVALID_PARAMETER;
1554 if (pszSubKey && pszSubKey[0])
1556 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1557 if (ret != ERROR_SUCCESS) return ret;
1560 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1562 /* If we are going to expand we need to read in the whole the value even
1563 * if the passed buffer was too small as the expanded string might be
1564 * smaller than the unexpanded one and could fit into cbData bytes. */
1565 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1566 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1568 do {
1569 HeapFree(GetProcessHeap(), 0, pvBuf);
1571 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1572 if (!pvBuf)
1574 ret = ERROR_NOT_ENOUGH_MEMORY;
1575 break;
1578 if (ret == ERROR_MORE_DATA || !pvData)
1579 ret = RegQueryValueExW(hKey, pszValue, NULL,
1580 &dwType, pvBuf, &cbData);
1581 else
1583 /* Even if cbData was large enough we have to copy the
1584 * string since ExpandEnvironmentStrings can't handle
1585 * overlapping buffers. */
1586 CopyMemory(pvBuf, pvData, cbData);
1589 /* Both the type or the value itself could have been modified in
1590 * between so we have to keep retrying until the buffer is large
1591 * enough or we no longer have to expand the value. */
1592 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1594 if (ret == ERROR_SUCCESS)
1596 /* Recheck dwType in case it changed since the first call */
1597 if (dwType == REG_EXPAND_SZ)
1599 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1600 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1601 dwType = REG_SZ;
1602 if(pvData && pcbData && cbData > *pcbData)
1603 ret = ERROR_MORE_DATA;
1605 else if (pvData)
1606 CopyMemory(pvData, pvBuf, *pcbData);
1609 HeapFree(GetProcessHeap(), 0, pvBuf);
1612 if (pszSubKey && pszSubKey[0])
1613 RegCloseKey(hKey);
1615 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1617 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1618 ZeroMemory(pvData, *pcbData);
1620 if (pdwType) *pdwType = dwType;
1621 if (pcbData) *pcbData = cbData;
1623 return ret;
1627 /******************************************************************************
1628 * RegGetValueA [ADVAPI32.@]
1630 * See RegGetValueW.
1632 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1633 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1634 LPDWORD pcbData )
1636 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1637 PVOID pvBuf = NULL;
1638 LONG ret;
1640 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1641 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1642 cbData);
1644 if (pvData && !pcbData)
1645 return ERROR_INVALID_PARAMETER;
1646 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1647 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1648 return ERROR_INVALID_PARAMETER;
1650 if (pszSubKey && pszSubKey[0])
1652 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1653 if (ret != ERROR_SUCCESS) return ret;
1656 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1658 /* If we are going to expand we need to read in the whole the value even
1659 * if the passed buffer was too small as the expanded string might be
1660 * smaller than the unexpanded one and could fit into cbData bytes. */
1661 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1662 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1664 do {
1665 HeapFree(GetProcessHeap(), 0, pvBuf);
1667 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1668 if (!pvBuf)
1670 ret = ERROR_NOT_ENOUGH_MEMORY;
1671 break;
1674 if (ret == ERROR_MORE_DATA || !pvData)
1675 ret = RegQueryValueExA(hKey, pszValue, NULL,
1676 &dwType, pvBuf, &cbData);
1677 else
1679 /* Even if cbData was large enough we have to copy the
1680 * string since ExpandEnvironmentStrings can't handle
1681 * overlapping buffers. */
1682 CopyMemory(pvBuf, pvData, cbData);
1685 /* Both the type or the value itself could have been modified in
1686 * between so we have to keep retrying until the buffer is large
1687 * enough or we no longer have to expand the value. */
1688 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1690 if (ret == ERROR_SUCCESS)
1692 /* Recheck dwType in case it changed since the first call */
1693 if (dwType == REG_EXPAND_SZ)
1695 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1696 pcbData ? *pcbData : 0);
1697 dwType = REG_SZ;
1698 if(pvData && pcbData && cbData > *pcbData)
1699 ret = ERROR_MORE_DATA;
1701 else if (pvData)
1702 CopyMemory(pvData, pvBuf, *pcbData);
1705 HeapFree(GetProcessHeap(), 0, pvBuf);
1708 if (pszSubKey && pszSubKey[0])
1709 RegCloseKey(hKey);
1711 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1713 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1714 ZeroMemory(pvData, *pcbData);
1716 if (pdwType) *pdwType = dwType;
1717 if (pcbData) *pcbData = cbData;
1719 return ret;
1723 /******************************************************************************
1724 * RegEnumValueW [ADVAPI32.@]
1726 * Enumerates the values for the specified open registry key.
1728 * PARAMS
1729 * hkey [I] Handle to key to query
1730 * index [I] Index of value to query
1731 * value [O] Value string
1732 * val_count [I/O] Size of value buffer (in wchars)
1733 * reserved [I] Reserved
1734 * type [O] Type code
1735 * data [O] Value data
1736 * count [I/O] Size of data buffer (in bytes)
1738 * RETURNS
1739 * Success: ERROR_SUCCESS
1740 * Failure: nonzero error code from Winerror.h
1743 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1744 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1746 NTSTATUS status;
1747 DWORD total_size;
1748 char buffer[256], *buf_ptr = buffer;
1749 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1750 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1752 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1753 hkey, index, value, val_count, reserved, type, data, count );
1755 /* NT only checks count, not val_count */
1756 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1757 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1759 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1760 if (data) total_size += *count;
1761 total_size = min( sizeof(buffer), total_size );
1763 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1764 buffer, total_size, &total_size );
1765 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1767 if (value || data)
1769 /* retry with a dynamically allocated buffer */
1770 while (status == STATUS_BUFFER_OVERFLOW)
1772 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1773 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1774 return ERROR_NOT_ENOUGH_MEMORY;
1775 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1776 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1777 buf_ptr, total_size, &total_size );
1780 if (status) goto done;
1782 if (value)
1784 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1786 status = STATUS_BUFFER_OVERFLOW;
1787 goto overflow;
1789 memcpy( value, info->Name, info->NameLength );
1790 *val_count = info->NameLength / sizeof(WCHAR);
1791 value[*val_count] = 0;
1794 if (data)
1796 if (total_size - info->DataOffset > *count)
1798 status = STATUS_BUFFER_OVERFLOW;
1799 goto overflow;
1801 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1802 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1804 /* if the type is REG_SZ and data is not 0-terminated
1805 * and there is enough space in the buffer NT appends a \0 */
1806 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1807 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1811 else status = STATUS_SUCCESS;
1813 overflow:
1814 if (type) *type = info->Type;
1815 if (count) *count = info->DataLength;
1817 done:
1818 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1819 return RtlNtStatusToDosError(status);
1823 /******************************************************************************
1824 * RegEnumValueA [ADVAPI32.@]
1826 * See RegEnumValueW.
1828 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1829 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1831 NTSTATUS status;
1832 DWORD total_size;
1833 char buffer[256], *buf_ptr = buffer;
1834 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1835 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1837 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1838 hkey, index, value, val_count, reserved, type, data, count );
1840 /* NT only checks count, not val_count */
1841 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1842 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1844 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1845 if (data) total_size += *count;
1846 total_size = min( sizeof(buffer), total_size );
1848 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1849 buffer, total_size, &total_size );
1850 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1852 /* we need to fetch the contents for a string type even if not requested,
1853 * because we need to compute the length of the ASCII string. */
1854 if (value || data || is_string(info->Type))
1856 /* retry with a dynamically allocated buffer */
1857 while (status == STATUS_BUFFER_OVERFLOW)
1859 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1860 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1861 return ERROR_NOT_ENOUGH_MEMORY;
1862 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1863 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1864 buf_ptr, total_size, &total_size );
1867 if (status) goto done;
1869 if (is_string(info->Type))
1871 DWORD len;
1872 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1873 total_size - info->DataOffset );
1874 if (data && len)
1876 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1877 else
1879 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1880 total_size - info->DataOffset );
1881 /* if the type is REG_SZ and data is not 0-terminated
1882 * and there is enough space in the buffer NT appends a \0 */
1883 if (len < *count && data[len-1]) data[len] = 0;
1886 info->DataLength = len;
1888 else if (data)
1890 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1891 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1894 if (value && !status)
1896 DWORD len;
1898 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1899 if (len >= *val_count)
1901 status = STATUS_BUFFER_OVERFLOW;
1902 if (*val_count)
1904 len = *val_count - 1;
1905 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1906 value[len] = 0;
1909 else
1911 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1912 value[len] = 0;
1913 *val_count = len;
1917 else status = STATUS_SUCCESS;
1919 if (type) *type = info->Type;
1920 if (count) *count = info->DataLength;
1922 done:
1923 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1924 return RtlNtStatusToDosError(status);
1929 /******************************************************************************
1930 * RegDeleteValueW [ADVAPI32.@]
1932 * See RegDeleteValueA.
1934 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1936 UNICODE_STRING nameW;
1938 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1940 RtlInitUnicodeString( &nameW, name );
1941 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1945 /******************************************************************************
1946 * RegDeleteValueA [ADVAPI32.@]
1948 * Delete a value from the registry.
1950 * PARAMS
1951 * hkey [I] Registry handle of the key holding the value
1952 * name [I] Name of the value under hkey to delete
1954 * RETURNS
1955 * Success: ERROR_SUCCESS
1956 * Failure: nonzero error code from Winerror.h
1958 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1960 ANSI_STRING nameA;
1961 UNICODE_STRING nameW;
1962 NTSTATUS status;
1964 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1966 RtlInitAnsiString( &nameA, name );
1967 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1969 status = NtDeleteValueKey( hkey, &nameW );
1970 RtlFreeUnicodeString( &nameW );
1972 return RtlNtStatusToDosError( status );
1976 /******************************************************************************
1977 * RegLoadKeyW [ADVAPI32.@]
1979 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1980 * registration information from a specified file into that subkey.
1982 * PARAMS
1983 * hkey [I] Handle of open key
1984 * subkey [I] Address of name of subkey
1985 * filename [I] Address of filename for registry information
1987 * RETURNS
1988 * Success: ERROR_SUCCESS
1989 * Failure: nonzero error code from Winerror.h
1991 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1993 OBJECT_ATTRIBUTES destkey, file;
1994 UNICODE_STRING subkeyW, filenameW;
1995 NTSTATUS status;
1997 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
1999 destkey.Length = sizeof(destkey);
2000 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2001 destkey.ObjectName = &subkeyW; /* name of the key */
2002 destkey.Attributes = 0;
2003 destkey.SecurityDescriptor = NULL;
2004 destkey.SecurityQualityOfService = NULL;
2005 RtlInitUnicodeString(&subkeyW, subkey);
2007 file.Length = sizeof(file);
2008 file.RootDirectory = NULL;
2009 file.ObjectName = &filenameW; /* file containing the hive */
2010 file.Attributes = OBJ_CASE_INSENSITIVE;
2011 file.SecurityDescriptor = NULL;
2012 file.SecurityQualityOfService = NULL;
2013 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2015 status = NtLoadKey(&destkey, &file);
2016 RtlFreeUnicodeString(&filenameW);
2017 return RtlNtStatusToDosError( status );
2021 /******************************************************************************
2022 * RegLoadKeyA [ADVAPI32.@]
2024 * See RegLoadKeyW.
2026 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2028 UNICODE_STRING subkeyW, filenameW;
2029 STRING subkeyA, filenameA;
2030 NTSTATUS status;
2031 LONG ret;
2033 RtlInitAnsiString(&subkeyA, subkey);
2034 RtlInitAnsiString(&filenameA, filename);
2036 RtlInitUnicodeString(&subkeyW, NULL);
2037 RtlInitUnicodeString(&filenameW, NULL);
2038 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2039 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2041 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2043 else ret = RtlNtStatusToDosError(status);
2044 RtlFreeUnicodeString(&subkeyW);
2045 RtlFreeUnicodeString(&filenameW);
2046 return ret;
2050 /******************************************************************************
2051 * RegSaveKeyW [ADVAPI32.@]
2053 * Save a key and all of its subkeys and values to a new file in the standard format.
2055 * PARAMS
2056 * hkey [I] Handle of key where save begins
2057 * lpFile [I] Address of filename to save to
2058 * sa [I] Address of security structure
2060 * RETURNS
2061 * Success: ERROR_SUCCESS
2062 * Failure: nonzero error code from Winerror.h
2064 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2066 static const WCHAR format[] =
2067 {'r','e','g','%','0','4','x','.','t','m','p',0};
2068 WCHAR buffer[MAX_PATH];
2069 int count = 0;
2070 LPWSTR nameW;
2071 DWORD ret, err;
2072 HANDLE handle;
2074 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2076 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2077 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2079 err = GetLastError();
2080 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2082 for (;;)
2084 snprintfW( nameW, 16, format, count++ );
2085 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2086 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2087 if (handle != INVALID_HANDLE_VALUE) break;
2088 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2090 /* Something gone haywire ? Please report if this happens abnormally */
2091 if (count >= 100)
2092 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);
2095 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2097 CloseHandle( handle );
2098 if (!ret)
2100 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2102 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2103 debugstr_w(file) );
2104 ret = GetLastError();
2107 if (ret) DeleteFileW( buffer );
2109 done:
2110 SetLastError( err ); /* restore last error code */
2111 return ret;
2115 /******************************************************************************
2116 * RegSaveKeyA [ADVAPI32.@]
2118 * See RegSaveKeyW.
2120 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2122 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2123 NTSTATUS status;
2124 STRING fileA;
2126 RtlInitAnsiString(&fileA, file);
2127 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2128 return RtlNtStatusToDosError( status );
2129 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2133 /******************************************************************************
2134 * RegRestoreKeyW [ADVAPI32.@]
2136 * Read the registry information from a file and copy it over a key.
2138 * PARAMS
2139 * hkey [I] Handle of key where restore begins
2140 * lpFile [I] Address of filename containing saved tree
2141 * dwFlags [I] Optional flags
2143 * RETURNS
2144 * Success: ERROR_SUCCESS
2145 * Failure: nonzero error code from Winerror.h
2147 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2149 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2151 /* It seems to do this check before the hkey check */
2152 if (!lpFile || !*lpFile)
2153 return ERROR_INVALID_PARAMETER;
2155 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2157 /* Check for file existence */
2159 return ERROR_SUCCESS;
2163 /******************************************************************************
2164 * RegRestoreKeyA [ADVAPI32.@]
2166 * See RegRestoreKeyW.
2168 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2170 UNICODE_STRING lpFileW;
2171 LONG ret;
2173 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2174 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2175 RtlFreeUnicodeString( &lpFileW );
2176 return ret;
2180 /******************************************************************************
2181 * RegUnLoadKeyW [ADVAPI32.@]
2183 * Unload a registry key and its subkeys from the registry.
2185 * PARAMS
2186 * hkey [I] Handle of open key
2187 * lpSubKey [I] Address of name of subkey to unload
2189 * RETURNS
2190 * Success: ERROR_SUCCESS
2191 * Failure: nonzero error code from Winerror.h
2193 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2195 DWORD ret;
2196 HKEY shkey;
2197 OBJECT_ATTRIBUTES attr;
2198 UNICODE_STRING subkey;
2200 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2202 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2203 if( ret )
2204 return ERROR_INVALID_PARAMETER;
2206 RtlInitUnicodeString(&subkey, lpSubKey);
2207 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2208 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2210 RegCloseKey(shkey);
2212 return ret;
2216 /******************************************************************************
2217 * RegUnLoadKeyA [ADVAPI32.@]
2219 * See RegUnLoadKeyW.
2221 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2223 UNICODE_STRING lpSubKeyW;
2224 LONG ret;
2226 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2227 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2228 RtlFreeUnicodeString( &lpSubKeyW );
2229 return ret;
2233 /******************************************************************************
2234 * RegReplaceKeyW [ADVAPI32.@]
2236 * Replace the file backing a registry key and all its subkeys with another file.
2238 * PARAMS
2239 * hkey [I] Handle of open key
2240 * lpSubKey [I] Address of name of subkey
2241 * lpNewFile [I] Address of filename for file with new data
2242 * lpOldFile [I] Address of filename for backup file
2244 * RETURNS
2245 * Success: ERROR_SUCCESS
2246 * Failure: nonzero error code from Winerror.h
2248 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2249 LPCWSTR lpOldFile )
2251 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2252 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2253 return ERROR_SUCCESS;
2257 /******************************************************************************
2258 * RegReplaceKeyA [ADVAPI32.@]
2260 * See RegReplaceKeyW.
2262 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2263 LPCSTR lpOldFile )
2265 UNICODE_STRING lpSubKeyW;
2266 UNICODE_STRING lpNewFileW;
2267 UNICODE_STRING lpOldFileW;
2268 LONG ret;
2270 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2271 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2272 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2273 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2274 RtlFreeUnicodeString( &lpOldFileW );
2275 RtlFreeUnicodeString( &lpNewFileW );
2276 RtlFreeUnicodeString( &lpSubKeyW );
2277 return ret;
2281 /******************************************************************************
2282 * RegSetKeySecurity [ADVAPI32.@]
2284 * Set the security of an open registry key.
2286 * PARAMS
2287 * hkey [I] Open handle of key to set
2288 * SecurityInfo [I] Descriptor contents
2289 * pSecurityDesc [I] Address of descriptor for key
2291 * RETURNS
2292 * Success: ERROR_SUCCESS
2293 * Failure: nonzero error code from Winerror.h
2295 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2296 PSECURITY_DESCRIPTOR pSecurityDesc )
2298 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2300 /* It seems to perform this check before the hkey check */
2301 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2302 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2303 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2304 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2305 /* Param OK */
2306 } else
2307 return ERROR_INVALID_PARAMETER;
2309 if (!pSecurityDesc)
2310 return ERROR_INVALID_PARAMETER;
2312 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2314 return ERROR_SUCCESS;
2318 /******************************************************************************
2319 * RegGetKeySecurity [ADVAPI32.@]
2321 * Get a copy of the security descriptor for a given registry key.
2323 * PARAMS
2324 * hkey [I] Open handle of key to set
2325 * SecurityInformation [I] Descriptor contents
2326 * pSecurityDescriptor [O] Address of descriptor for key
2327 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2329 * RETURNS
2330 * Success: ERROR_SUCCESS
2331 * Failure: Error code
2333 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2334 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2335 LPDWORD lpcbSecurityDescriptor )
2337 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2338 *lpcbSecurityDescriptor);
2340 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2342 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2343 SecurityInformation, pSecurityDescriptor,
2344 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2348 /******************************************************************************
2349 * RegFlushKey [ADVAPI32.@]
2351 * Immediately write a registry key to registry.
2353 * PARAMS
2354 * hkey [I] Handle of key to write
2356 * RETURNS
2357 * Success: ERROR_SUCCESS
2358 * Failure: Error code
2360 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2362 hkey = get_special_root_hkey( hkey );
2363 if (!hkey) return ERROR_INVALID_HANDLE;
2365 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2369 /******************************************************************************
2370 * RegConnectRegistryW [ADVAPI32.@]
2372 * Establish a connection to a predefined registry key on another computer.
2374 * PARAMS
2375 * lpMachineName [I] Address of name of remote computer
2376 * hHey [I] Predefined registry handle
2377 * phkResult [I] Address of buffer for remote registry handle
2379 * RETURNS
2380 * Success: ERROR_SUCCESS
2381 * Failure: nonzero error code from Winerror.h
2383 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2384 PHKEY phkResult )
2386 LONG ret;
2388 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2390 if (!lpMachineName || !*lpMachineName) {
2391 /* Use the local machine name */
2392 ret = RegOpenKeyW( hKey, NULL, phkResult );
2394 else {
2395 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2396 DWORD len = sizeof(compName) / sizeof(WCHAR);
2398 /* MSDN says lpMachineName must start with \\ : not so */
2399 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2400 lpMachineName += 2;
2401 if (GetComputerNameW(compName, &len))
2403 if (!strcmpiW(lpMachineName, compName))
2404 ret = RegOpenKeyW(hKey, NULL, phkResult);
2405 else
2407 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2408 ret = ERROR_BAD_NETPATH;
2411 else
2412 ret = GetLastError();
2414 return ret;
2418 /******************************************************************************
2419 * RegConnectRegistryA [ADVAPI32.@]
2421 * See RegConnectRegistryW.
2423 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2425 UNICODE_STRING machineW;
2426 LONG ret;
2428 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2429 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2430 RtlFreeUnicodeString( &machineW );
2431 return ret;
2435 /******************************************************************************
2436 * RegNotifyChangeKeyValue [ADVAPI32.@]
2438 * Notify the caller about changes to the attributes or contents of a registry key.
2440 * PARAMS
2441 * hkey [I] Handle of key to watch
2442 * fWatchSubTree [I] Flag for subkey notification
2443 * fdwNotifyFilter [I] Changes to be reported
2444 * hEvent [I] Handle of signaled event
2445 * fAsync [I] Flag for asynchronous reporting
2447 * RETURNS
2448 * Success: ERROR_SUCCESS
2449 * Failure: nonzero error code from Winerror.h
2451 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2452 DWORD fdwNotifyFilter, HANDLE hEvent,
2453 BOOL fAsync )
2455 NTSTATUS status;
2456 IO_STATUS_BLOCK iosb;
2458 hkey = get_special_root_hkey( hkey );
2459 if (!hkey) return ERROR_INVALID_HANDLE;
2461 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2462 hEvent, fAsync);
2464 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2465 fdwNotifyFilter, fAsync, NULL, 0,
2466 fWatchSubTree);
2468 if (status && status != STATUS_TIMEOUT)
2469 return RtlNtStatusToDosError( status );
2471 return ERROR_SUCCESS;
2474 /******************************************************************************
2475 * RegOpenUserClassesRoot [ADVAPI32.@]
2477 * Open the HKEY_CLASSES_ROOT key for a user.
2479 * PARAMS
2480 * hToken [I] Handle of token representing the user
2481 * dwOptions [I] Reserved, must be 0
2482 * samDesired [I] Desired access rights
2483 * phkResult [O] Destination for the resulting key handle
2485 * RETURNS
2486 * Success: ERROR_SUCCESS
2487 * Failure: nonzero error code from Winerror.h
2489 * NOTES
2490 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2491 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2492 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2494 LSTATUS WINAPI RegOpenUserClassesRoot(
2495 HANDLE hToken,
2496 DWORD dwOptions,
2497 REGSAM samDesired,
2498 PHKEY phkResult
2501 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2503 *phkResult = HKEY_CLASSES_ROOT;
2504 return ERROR_SUCCESS;
2507 /******************************************************************************
2508 * load_string [Internal]
2510 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2511 * avoid importing user32, which is higher level than advapi32. Helper for
2512 * RegLoadMUIString.
2514 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2516 HGLOBAL hMemory;
2517 HRSRC hResource;
2518 WCHAR *pString;
2519 int idxString;
2521 /* Negative values have to be inverted. */
2522 if (HIWORD(resId) == 0xffff)
2523 resId = (UINT)(-((INT)resId));
2525 /* Load the resource into memory and get a pointer to it. */
2526 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2527 if (!hResource) return 0;
2528 hMemory = LoadResource(hModule, hResource);
2529 if (!hMemory) return 0;
2530 pString = LockResource(hMemory);
2532 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2533 idxString = resId & 0xf;
2534 while (idxString--) pString += *pString + 1;
2536 /* If no buffer is given, return length of the string. */
2537 if (!pwszBuffer) return *pString;
2539 /* Else copy over the string, respecting the buffer size. */
2540 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2541 if (cMaxChars >= 0) {
2542 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2543 pwszBuffer[cMaxChars] = '\0';
2546 return cMaxChars;
2549 /******************************************************************************
2550 * RegLoadMUIStringW [ADVAPI32.@]
2552 * Load the localized version of a string resource from some PE, respective
2553 * id and path of which are given in the registry value in the format
2554 * @[path]\dllname,-resourceId
2556 * PARAMS
2557 * hKey [I] Key, of which to load the string value from.
2558 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2559 * pszBuffer [O] Buffer to store the localized string in.
2560 * cbBuffer [I] Size of the destination buffer in bytes.
2561 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2562 * dwFlags [I] None supported yet.
2563 * pszBaseDir [I] Not supported yet.
2565 * RETURNS
2566 * Success: ERROR_SUCCESS,
2567 * Failure: nonzero error code from winerror.h
2569 * NOTES
2570 * This is an API of Windows Vista, which wasn't available at the time this code
2571 * was written. We have to check for the correct behaviour once it's available.
2573 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2574 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2576 DWORD dwValueType, cbData;
2577 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2578 LONG result;
2580 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2581 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2582 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2584 /* Parameter sanity checks. */
2585 if (!hKey || !pwszBuffer)
2586 return ERROR_INVALID_PARAMETER;
2588 if (pwszBaseDir && *pwszBaseDir) {
2589 FIXME("BaseDir parameter not yet supported!\n");
2590 return ERROR_INVALID_PARAMETER;
2593 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2594 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2595 if (result != ERROR_SUCCESS) goto cleanup;
2596 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2597 result = ERROR_FILE_NOT_FOUND;
2598 goto cleanup;
2600 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2601 if (!pwszTempBuffer) {
2602 result = ERROR_NOT_ENOUGH_MEMORY;
2603 goto cleanup;
2605 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2606 if (result != ERROR_SUCCESS) goto cleanup;
2608 /* Expand environment variables, if appropriate, or copy the original string over. */
2609 if (dwValueType == REG_EXPAND_SZ) {
2610 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2611 if (!cbData) goto cleanup;
2612 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2613 if (!pwszExpandedBuffer) {
2614 result = ERROR_NOT_ENOUGH_MEMORY;
2615 goto cleanup;
2617 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2618 } else {
2619 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2620 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2623 /* If the value references a resource based string, parse the value and load the string.
2624 * Else just copy over the original value. */
2625 result = ERROR_SUCCESS;
2626 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2627 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2628 } else {
2629 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2630 UINT uiStringId;
2631 HMODULE hModule;
2633 /* Format of the expanded value is 'path_to_dll,-resId' */
2634 if (!pComma || pComma[1] != '-') {
2635 result = ERROR_BADKEY;
2636 goto cleanup;
2639 uiStringId = atoiW(pComma+2);
2640 *pComma = '\0';
2642 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2643 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2644 result = ERROR_BADKEY;
2645 FreeLibrary(hModule);
2648 cleanup:
2649 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2650 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2651 return result;
2654 /******************************************************************************
2655 * RegLoadMUIStringA [ADVAPI32.@]
2657 * See RegLoadMUIStringW
2659 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2660 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2662 UNICODE_STRING valueW, baseDirW;
2663 WCHAR *pwszBuffer;
2664 DWORD cbData = cbBuffer * sizeof(WCHAR);
2665 LONG result;
2667 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2668 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2669 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2670 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2672 result = ERROR_NOT_ENOUGH_MEMORY;
2673 goto cleanup;
2676 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2677 baseDirW.Buffer);
2679 if (result == ERROR_SUCCESS) {
2680 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2681 if (pcbData)
2682 *pcbData = cbData;
2685 cleanup:
2686 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2687 RtlFreeUnicodeString(&baseDirW);
2688 RtlFreeUnicodeString(&valueW);
2690 return result;
2693 /******************************************************************************
2694 * RegDisablePredefinedCache [ADVAPI32.@]
2696 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2698 * PARAMS
2699 * None.
2701 * RETURNS
2702 * Success: ERROR_SUCCESS
2703 * Failure: nonzero error code from Winerror.h
2705 * NOTES
2706 * This is useful for services that use impersonation.
2708 LSTATUS WINAPI RegDisablePredefinedCache(void)
2710 HKEY hkey_current_user;
2711 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2713 /* prevent caching of future requests */
2714 hkcu_cache_disabled = TRUE;
2716 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2718 if (hkey_current_user)
2719 NtClose( hkey_current_user );
2721 return ERROR_SUCCESS;
2724 /******************************************************************************
2725 * RegDeleteTreeW [ADVAPI32.@]
2728 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2730 LONG ret;
2731 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2732 DWORD dwMaxLen, dwSize;
2733 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2734 HKEY hSubKey = hKey;
2736 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2738 if(lpszSubKey)
2740 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2741 if (ret) return ret;
2744 /* Get highest length for keys, values */
2745 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2746 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2747 if (ret) goto cleanup;
2749 dwMaxSubkeyLen++;
2750 dwMaxValueLen++;
2751 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2752 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2754 /* Name too big: alloc a buffer for it */
2755 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2757 ret = ERROR_NOT_ENOUGH_MEMORY;
2758 goto cleanup;
2763 /* Recursively delete all the subkeys */
2764 while (TRUE)
2766 dwSize = dwMaxLen;
2767 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2768 NULL, NULL, NULL)) break;
2770 ret = RegDeleteTreeW(hSubKey, lpszName);
2771 if (ret) goto cleanup;
2774 if (lpszSubKey)
2775 ret = RegDeleteKeyW(hKey, lpszSubKey);
2776 else
2777 while (TRUE)
2779 dwSize = dwMaxLen;
2780 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2781 NULL, NULL, NULL, NULL)) break;
2783 ret = RegDeleteValueW(hKey, lpszName);
2784 if (ret) goto cleanup;
2787 cleanup:
2788 /* Free buffer if allocated */
2789 if (lpszName != szNameBuf)
2790 HeapFree( GetProcessHeap(), 0, lpszName);
2791 if(lpszSubKey)
2792 RegCloseKey(hSubKey);
2793 return ret;
2796 /******************************************************************************
2797 * RegDeleteTreeA [ADVAPI32.@]
2800 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2802 LONG ret;
2803 UNICODE_STRING lpszSubKeyW;
2805 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2806 else lpszSubKeyW.Buffer = NULL;
2807 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2808 RtlFreeUnicodeString( &lpszSubKeyW );
2809 return ret;