push 6e61d6ca5bcaf95ac09a664b4ba4f88238c927be
[wine/hacks.git] / dlls / advapi32 / registry.c
blobdd3f516becfdc959e83544a2d96fd97ba664df79
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 WCHAR *dataW = NULL;
1107 NTSTATUS status;
1109 if (!is_version_nt()) /* win95 */
1111 if (type == REG_SZ)
1113 if (!data) return ERROR_INVALID_PARAMETER;
1114 count = strlen((const char *)data) + 1;
1117 else if (count && is_string(type))
1119 /* if user forgot to count terminating null, add it (yes NT does this) */
1120 if (data[count-1] && !data[count]) count++;
1123 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1125 if (is_string( type )) /* need to convert to Unicode */
1127 DWORD lenW;
1128 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1129 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1130 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1131 count = lenW;
1132 data = (BYTE *)dataW;
1135 RtlInitAnsiString( &nameA, name );
1136 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1137 &nameA, FALSE )))
1139 status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
1141 HeapFree( GetProcessHeap(), 0, dataW );
1142 return RtlNtStatusToDosError( status );
1146 /******************************************************************************
1147 * RegSetValueW [ADVAPI32.@]
1149 * Sets the data for the default or unnamed value of a reg key.
1151 * PARAMS
1152 * hKey [I] Handle to an open key.
1153 * lpSubKey [I] Name of a subkey of hKey.
1154 * dwType [I] Type of information to store.
1155 * lpData [I] String that contains the data to set for the default value.
1156 * cbData [I] Ignored.
1158 * RETURNS
1159 * Success: ERROR_SUCCESS
1160 * Failure: nonzero error code from Winerror.h
1162 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1164 HKEY subkey = hkey;
1165 DWORD ret;
1167 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1169 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1171 if (name && name[0]) /* need to create the subkey */
1173 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1176 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1177 (strlenW( data ) + 1) * sizeof(WCHAR) );
1178 if (subkey != hkey) RegCloseKey( subkey );
1179 return ret;
1183 /******************************************************************************
1184 * RegSetValueA [ADVAPI32.@]
1186 * See RegSetValueW.
1188 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1190 HKEY subkey = hkey;
1191 DWORD ret;
1193 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1195 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1197 if (name && name[0]) /* need to create the subkey */
1199 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1201 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1202 if (subkey != hkey) RegCloseKey( subkey );
1203 return ret;
1208 /******************************************************************************
1209 * RegQueryValueExW [ADVAPI32.@]
1211 * See RegQueryValueExA.
1213 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1214 LPBYTE data, LPDWORD count )
1216 NTSTATUS status;
1217 UNICODE_STRING name_str;
1218 DWORD total_size;
1219 char buffer[256], *buf_ptr = buffer;
1220 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1221 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1223 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1224 hkey, debugstr_w(name), reserved, type, data, count,
1225 (count && data) ? *count : 0 );
1227 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1228 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1230 RtlInitUnicodeString( &name_str, name );
1232 if (data) total_size = min( sizeof(buffer), *count + info_size );
1233 else
1235 total_size = info_size;
1236 if (count) *count = 0;
1239 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1240 buffer, total_size, &total_size );
1241 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1243 if (data)
1245 /* retry with a dynamically allocated buffer */
1246 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1248 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1249 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1250 return ERROR_NOT_ENOUGH_MEMORY;
1251 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1252 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1253 buf_ptr, total_size, &total_size );
1256 if (!status)
1258 memcpy( data, buf_ptr + info_size, total_size - info_size );
1259 /* if the type is REG_SZ and data is not 0-terminated
1260 * and there is enough space in the buffer NT appends a \0 */
1261 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1263 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1264 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1267 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1269 else status = STATUS_SUCCESS;
1271 if (type) *type = info->Type;
1272 if (count) *count = total_size - info_size;
1274 done:
1275 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1276 return RtlNtStatusToDosError(status);
1280 /******************************************************************************
1281 * RegQueryValueExA [ADVAPI32.@]
1283 * Get the type and contents of a specified value under with a key.
1285 * PARAMS
1286 * hkey [I] Handle of the key to query
1287 * name [I] Name of value under hkey to query
1288 * reserved [I] Reserved - must be NULL
1289 * type [O] Destination for the value type, or NULL if not required
1290 * data [O] Destination for the values contents, or NULL if not required
1291 * count [I/O] Size of data, updated with the number of bytes returned
1293 * RETURNS
1294 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1295 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1296 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1297 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1299 * NOTES
1300 * MSDN states that if data is too small it is partially filled. In reality
1301 * it remains untouched.
1303 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1304 LPBYTE data, LPDWORD count )
1306 NTSTATUS status;
1307 ANSI_STRING nameA;
1308 DWORD total_size, datalen = 0;
1309 char buffer[256], *buf_ptr = buffer;
1310 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1311 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1313 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1314 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1316 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1317 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1319 if (count) datalen = *count;
1320 if (!data && count) *count = 0;
1322 /* this matches Win9x behaviour - NT sets *type to a random value */
1323 if (type) *type = REG_NONE;
1325 RtlInitAnsiString( &nameA, name );
1326 if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1327 &nameA, FALSE )))
1328 return RtlNtStatusToDosError(status);
1330 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1331 KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
1332 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1334 /* we need to fetch the contents for a string type even if not requested,
1335 * because we need to compute the length of the ASCII string. */
1336 if (data || is_string(info->Type))
1338 /* retry with a dynamically allocated buffer */
1339 while (status == STATUS_BUFFER_OVERFLOW)
1341 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1342 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1344 status = STATUS_NO_MEMORY;
1345 goto done;
1347 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1348 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1349 KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1352 if (status) goto done;
1354 if (is_string(info->Type))
1356 DWORD len;
1358 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1359 total_size - info_size );
1360 if (data && len)
1362 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1363 else
1365 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1366 total_size - info_size );
1367 /* if the type is REG_SZ and data is not 0-terminated
1368 * and there is enough space in the buffer NT appends a \0 */
1369 if (len < datalen && data[len-1]) data[len] = 0;
1372 total_size = len + info_size;
1374 else if (data)
1376 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1377 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1380 else status = STATUS_SUCCESS;
1382 if (type) *type = info->Type;
1383 if (count) *count = total_size - info_size;
1385 done:
1386 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1387 return RtlNtStatusToDosError(status);
1391 /******************************************************************************
1392 * RegQueryValueW [ADVAPI32.@]
1394 * Retrieves the data associated with the default or unnamed value of a key.
1396 * PARAMS
1397 * hkey [I] Handle to an open key.
1398 * name [I] Name of the subkey of hKey.
1399 * data [O] Receives the string associated with the default value
1400 * of the key.
1401 * count [I/O] Size of lpValue in bytes.
1403 * RETURNS
1404 * Success: ERROR_SUCCESS
1405 * Failure: nonzero error code from Winerror.h
1407 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1409 DWORD ret;
1410 HKEY subkey = hkey;
1412 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1414 if (name && name[0])
1416 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1418 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1419 if (subkey != hkey) RegCloseKey( subkey );
1420 if (ret == ERROR_FILE_NOT_FOUND)
1422 /* return empty string if default value not found */
1423 if (data) *data = 0;
1424 if (count) *count = sizeof(WCHAR);
1425 ret = ERROR_SUCCESS;
1427 return ret;
1431 /******************************************************************************
1432 * RegQueryValueA [ADVAPI32.@]
1434 * See RegQueryValueW.
1436 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1438 DWORD ret;
1439 HKEY subkey = hkey;
1441 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1443 if (name && name[0])
1445 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1447 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1448 if (subkey != hkey) RegCloseKey( subkey );
1449 if (ret == ERROR_FILE_NOT_FOUND)
1451 /* return empty string if default value not found */
1452 if (data) *data = 0;
1453 if (count) *count = 1;
1454 ret = ERROR_SUCCESS;
1456 return ret;
1460 /******************************************************************************
1461 * ADVAPI_ApplyRestrictions [internal]
1463 * Helper function for RegGetValueA/W.
1465 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1466 DWORD cbData, PLONG ret )
1468 /* Check if the type is restricted by the passed flags */
1469 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1471 DWORD dwMask = 0;
1473 switch (dwType)
1475 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1476 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1477 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1478 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1479 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1480 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1481 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1484 if (dwFlags & dwMask)
1486 /* Type is not restricted, check for size mismatch */
1487 if (dwType == REG_BINARY)
1489 DWORD cbExpect = 0;
1491 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1492 cbExpect = 4;
1493 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1494 cbExpect = 8;
1496 if (cbExpect && cbData != cbExpect)
1497 *ret = ERROR_DATATYPE_MISMATCH;
1500 else *ret = ERROR_UNSUPPORTED_TYPE;
1505 /******************************************************************************
1506 * RegGetValueW [ADVAPI32.@]
1508 * Retrieves the type and data for a value name associated with a key,
1509 * optionally expanding its content and restricting its type.
1511 * PARAMS
1512 * hKey [I] Handle to an open key.
1513 * pszSubKey [I] Name of the subkey of hKey.
1514 * pszValue [I] Name of value under hKey/szSubKey to query.
1515 * dwFlags [I] Flags restricting the value type to retrieve.
1516 * pdwType [O] Destination for the values type, may be NULL.
1517 * pvData [O] Destination for the values content, may be NULL.
1518 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1519 * retrieve the whole content, including the trailing '\0'
1520 * for strings.
1522 * RETURNS
1523 * Success: ERROR_SUCCESS
1524 * Failure: nonzero error code from Winerror.h
1526 * NOTES
1527 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1528 * expanded and pdwType is set to REG_SZ instead.
1529 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1530 * without RRF_NOEXPAND is thus not allowed.
1531 * An exception is the case where RRF_RT_ANY is specified, because then
1532 * RRF_NOEXPAND is allowed.
1534 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1535 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1536 LPDWORD pcbData )
1538 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1539 PVOID pvBuf = NULL;
1540 LONG ret;
1542 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1543 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1544 pvData, pcbData, cbData);
1546 if (pvData && !pcbData)
1547 return ERROR_INVALID_PARAMETER;
1548 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1549 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1550 return ERROR_INVALID_PARAMETER;
1552 if (pszSubKey && pszSubKey[0])
1554 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1555 if (ret != ERROR_SUCCESS) return ret;
1558 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1560 /* If we are going to expand we need to read in the whole the value even
1561 * if the passed buffer was too small as the expanded string might be
1562 * smaller than the unexpanded one and could fit into cbData bytes. */
1563 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1564 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1566 do {
1567 HeapFree(GetProcessHeap(), 0, pvBuf);
1569 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1570 if (!pvBuf)
1572 ret = ERROR_NOT_ENOUGH_MEMORY;
1573 break;
1576 if (ret == ERROR_MORE_DATA || !pvData)
1577 ret = RegQueryValueExW(hKey, pszValue, NULL,
1578 &dwType, pvBuf, &cbData);
1579 else
1581 /* Even if cbData was large enough we have to copy the
1582 * string since ExpandEnvironmentStrings can't handle
1583 * overlapping buffers. */
1584 CopyMemory(pvBuf, pvData, cbData);
1587 /* Both the type or the value itself could have been modified in
1588 * between so we have to keep retrying until the buffer is large
1589 * enough or we no longer have to expand the value. */
1590 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1592 if (ret == ERROR_SUCCESS)
1594 /* Recheck dwType in case it changed since the first call */
1595 if (dwType == REG_EXPAND_SZ)
1597 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1598 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1599 dwType = REG_SZ;
1600 if(pvData && pcbData && cbData > *pcbData)
1601 ret = ERROR_MORE_DATA;
1603 else if (pvData)
1604 CopyMemory(pvData, pvBuf, *pcbData);
1607 HeapFree(GetProcessHeap(), 0, pvBuf);
1610 if (pszSubKey && pszSubKey[0])
1611 RegCloseKey(hKey);
1613 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1615 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1616 ZeroMemory(pvData, *pcbData);
1618 if (pdwType) *pdwType = dwType;
1619 if (pcbData) *pcbData = cbData;
1621 return ret;
1625 /******************************************************************************
1626 * RegGetValueA [ADVAPI32.@]
1628 * See RegGetValueW.
1630 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1631 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1632 LPDWORD pcbData )
1634 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1635 PVOID pvBuf = NULL;
1636 LONG ret;
1638 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1639 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1640 cbData);
1642 if (pvData && !pcbData)
1643 return ERROR_INVALID_PARAMETER;
1644 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1645 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1646 return ERROR_INVALID_PARAMETER;
1648 if (pszSubKey && pszSubKey[0])
1650 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1651 if (ret != ERROR_SUCCESS) return ret;
1654 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1656 /* If we are going to expand we need to read in the whole the value even
1657 * if the passed buffer was too small as the expanded string might be
1658 * smaller than the unexpanded one and could fit into cbData bytes. */
1659 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1660 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1662 do {
1663 HeapFree(GetProcessHeap(), 0, pvBuf);
1665 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1666 if (!pvBuf)
1668 ret = ERROR_NOT_ENOUGH_MEMORY;
1669 break;
1672 if (ret == ERROR_MORE_DATA || !pvData)
1673 ret = RegQueryValueExA(hKey, pszValue, NULL,
1674 &dwType, pvBuf, &cbData);
1675 else
1677 /* Even if cbData was large enough we have to copy the
1678 * string since ExpandEnvironmentStrings can't handle
1679 * overlapping buffers. */
1680 CopyMemory(pvBuf, pvData, cbData);
1683 /* Both the type or the value itself could have been modified in
1684 * between so we have to keep retrying until the buffer is large
1685 * enough or we no longer have to expand the value. */
1686 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1688 if (ret == ERROR_SUCCESS)
1690 /* Recheck dwType in case it changed since the first call */
1691 if (dwType == REG_EXPAND_SZ)
1693 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1694 pcbData ? *pcbData : 0);
1695 dwType = REG_SZ;
1696 if(pvData && pcbData && cbData > *pcbData)
1697 ret = ERROR_MORE_DATA;
1699 else if (pvData)
1700 CopyMemory(pvData, pvBuf, *pcbData);
1703 HeapFree(GetProcessHeap(), 0, pvBuf);
1706 if (pszSubKey && pszSubKey[0])
1707 RegCloseKey(hKey);
1709 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1711 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1712 ZeroMemory(pvData, *pcbData);
1714 if (pdwType) *pdwType = dwType;
1715 if (pcbData) *pcbData = cbData;
1717 return ret;
1721 /******************************************************************************
1722 * RegEnumValueW [ADVAPI32.@]
1724 * Enumerates the values for the specified open registry key.
1726 * PARAMS
1727 * hkey [I] Handle to key to query
1728 * index [I] Index of value to query
1729 * value [O] Value string
1730 * val_count [I/O] Size of value buffer (in wchars)
1731 * reserved [I] Reserved
1732 * type [O] Type code
1733 * data [O] Value data
1734 * count [I/O] Size of data buffer (in bytes)
1736 * RETURNS
1737 * Success: ERROR_SUCCESS
1738 * Failure: nonzero error code from Winerror.h
1741 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1742 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1744 NTSTATUS status;
1745 DWORD total_size;
1746 char buffer[256], *buf_ptr = buffer;
1747 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1748 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1750 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1751 hkey, index, value, val_count, reserved, type, data, count );
1753 /* NT only checks count, not val_count */
1754 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1755 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1757 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1758 if (data) total_size += *count;
1759 total_size = min( sizeof(buffer), total_size );
1761 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1762 buffer, total_size, &total_size );
1763 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1765 if (value || data)
1767 /* retry with a dynamically allocated buffer */
1768 while (status == STATUS_BUFFER_OVERFLOW)
1770 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1771 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1772 return ERROR_NOT_ENOUGH_MEMORY;
1773 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1774 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1775 buf_ptr, total_size, &total_size );
1778 if (status) goto done;
1780 if (value)
1782 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1784 status = STATUS_BUFFER_OVERFLOW;
1785 goto overflow;
1787 memcpy( value, info->Name, info->NameLength );
1788 *val_count = info->NameLength / sizeof(WCHAR);
1789 value[*val_count] = 0;
1792 if (data)
1794 if (total_size - info->DataOffset > *count)
1796 status = STATUS_BUFFER_OVERFLOW;
1797 goto overflow;
1799 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1800 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1802 /* if the type is REG_SZ and data is not 0-terminated
1803 * and there is enough space in the buffer NT appends a \0 */
1804 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1805 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1809 else status = STATUS_SUCCESS;
1811 overflow:
1812 if (type) *type = info->Type;
1813 if (count) *count = info->DataLength;
1815 done:
1816 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1817 return RtlNtStatusToDosError(status);
1821 /******************************************************************************
1822 * RegEnumValueA [ADVAPI32.@]
1824 * See RegEnumValueW.
1826 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1827 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1829 NTSTATUS status;
1830 DWORD total_size;
1831 char buffer[256], *buf_ptr = buffer;
1832 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1833 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1835 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1836 hkey, index, value, val_count, reserved, type, data, count );
1838 /* NT only checks count, not val_count */
1839 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1840 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1842 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1843 if (data) total_size += *count;
1844 total_size = min( sizeof(buffer), total_size );
1846 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1847 buffer, total_size, &total_size );
1848 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1850 /* we need to fetch the contents for a string type even if not requested,
1851 * because we need to compute the length of the ASCII string. */
1852 if (value || data || is_string(info->Type))
1854 /* retry with a dynamically allocated buffer */
1855 while (status == STATUS_BUFFER_OVERFLOW)
1857 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1858 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1859 return ERROR_NOT_ENOUGH_MEMORY;
1860 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1861 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1862 buf_ptr, total_size, &total_size );
1865 if (status) goto done;
1867 if (is_string(info->Type))
1869 DWORD len;
1870 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1871 total_size - info->DataOffset );
1872 if (data && len)
1874 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1875 else
1877 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1878 total_size - info->DataOffset );
1879 /* if the type is REG_SZ and data is not 0-terminated
1880 * and there is enough space in the buffer NT appends a \0 */
1881 if (len < *count && data[len-1]) data[len] = 0;
1884 info->DataLength = len;
1886 else if (data)
1888 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1889 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1892 if (value && !status)
1894 DWORD len;
1896 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1897 if (len >= *val_count)
1899 status = STATUS_BUFFER_OVERFLOW;
1900 if (*val_count)
1902 len = *val_count - 1;
1903 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1904 value[len] = 0;
1907 else
1909 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1910 value[len] = 0;
1911 *val_count = len;
1915 else status = STATUS_SUCCESS;
1917 if (type) *type = info->Type;
1918 if (count) *count = info->DataLength;
1920 done:
1921 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1922 return RtlNtStatusToDosError(status);
1927 /******************************************************************************
1928 * RegDeleteValueW [ADVAPI32.@]
1930 * See RegDeleteValueA.
1932 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1934 UNICODE_STRING nameW;
1936 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1938 RtlInitUnicodeString( &nameW, name );
1939 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1943 /******************************************************************************
1944 * RegDeleteValueA [ADVAPI32.@]
1946 * Delete a value from the registry.
1948 * PARAMS
1949 * hkey [I] Registry handle of the key holding the value
1950 * name [I] Name of the value under hkey to delete
1952 * RETURNS
1953 * Success: ERROR_SUCCESS
1954 * Failure: nonzero error code from Winerror.h
1956 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1958 STRING nameA;
1959 NTSTATUS status;
1961 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1963 RtlInitAnsiString( &nameA, name );
1964 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1965 &nameA, FALSE )))
1966 status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1967 return RtlNtStatusToDosError( status );
1971 /******************************************************************************
1972 * RegLoadKeyW [ADVAPI32.@]
1974 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1975 * registration information from a specified file into that subkey.
1977 * PARAMS
1978 * hkey [I] Handle of open key
1979 * subkey [I] Address of name of subkey
1980 * filename [I] Address of filename for registry information
1982 * RETURNS
1983 * Success: ERROR_SUCCESS
1984 * Failure: nonzero error code from Winerror.h
1986 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1988 OBJECT_ATTRIBUTES destkey, file;
1989 UNICODE_STRING subkeyW, filenameW;
1990 NTSTATUS status;
1992 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
1994 destkey.Length = sizeof(destkey);
1995 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
1996 destkey.ObjectName = &subkeyW; /* name of the key */
1997 destkey.Attributes = 0;
1998 destkey.SecurityDescriptor = NULL;
1999 destkey.SecurityQualityOfService = NULL;
2000 RtlInitUnicodeString(&subkeyW, subkey);
2002 file.Length = sizeof(file);
2003 file.RootDirectory = NULL;
2004 file.ObjectName = &filenameW; /* file containing the hive */
2005 file.Attributes = OBJ_CASE_INSENSITIVE;
2006 file.SecurityDescriptor = NULL;
2007 file.SecurityQualityOfService = NULL;
2008 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2010 status = NtLoadKey(&destkey, &file);
2011 RtlFreeUnicodeString(&filenameW);
2012 return RtlNtStatusToDosError( status );
2016 /******************************************************************************
2017 * RegLoadKeyA [ADVAPI32.@]
2019 * See RegLoadKeyW.
2021 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2023 UNICODE_STRING subkeyW, filenameW;
2024 STRING subkeyA, filenameA;
2025 NTSTATUS status;
2026 LONG ret;
2028 RtlInitAnsiString(&subkeyA, subkey);
2029 RtlInitAnsiString(&filenameA, filename);
2031 RtlInitUnicodeString(&subkeyW, NULL);
2032 RtlInitUnicodeString(&filenameW, NULL);
2033 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2034 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2036 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2038 else ret = RtlNtStatusToDosError(status);
2039 RtlFreeUnicodeString(&subkeyW);
2040 RtlFreeUnicodeString(&filenameW);
2041 return ret;
2045 /******************************************************************************
2046 * RegSaveKeyW [ADVAPI32.@]
2048 * Save a key and all of its subkeys and values to a new file in the standard format.
2050 * PARAMS
2051 * hkey [I] Handle of key where save begins
2052 * lpFile [I] Address of filename to save to
2053 * sa [I] Address of security structure
2055 * RETURNS
2056 * Success: ERROR_SUCCESS
2057 * Failure: nonzero error code from Winerror.h
2059 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2061 static const WCHAR format[] =
2062 {'r','e','g','%','0','4','x','.','t','m','p',0};
2063 WCHAR buffer[MAX_PATH];
2064 int count = 0;
2065 LPWSTR nameW;
2066 DWORD ret, err;
2067 HANDLE handle;
2069 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2071 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2072 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2074 err = GetLastError();
2075 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2077 for (;;)
2079 snprintfW( nameW, 16, format, count++ );
2080 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2081 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2082 if (handle != INVALID_HANDLE_VALUE) break;
2083 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2085 /* Something gone haywire ? Please report if this happens abnormally */
2086 if (count >= 100)
2087 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);
2090 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2092 CloseHandle( handle );
2093 if (!ret)
2095 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2097 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2098 debugstr_w(file) );
2099 ret = GetLastError();
2102 if (ret) DeleteFileW( buffer );
2104 done:
2105 SetLastError( err ); /* restore last error code */
2106 return ret;
2110 /******************************************************************************
2111 * RegSaveKeyA [ADVAPI32.@]
2113 * See RegSaveKeyW.
2115 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2117 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2118 NTSTATUS status;
2119 STRING fileA;
2121 RtlInitAnsiString(&fileA, file);
2122 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2123 return RtlNtStatusToDosError( status );
2124 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2128 /******************************************************************************
2129 * RegRestoreKeyW [ADVAPI32.@]
2131 * Read the registry information from a file and copy it over a key.
2133 * PARAMS
2134 * hkey [I] Handle of key where restore begins
2135 * lpFile [I] Address of filename containing saved tree
2136 * dwFlags [I] Optional flags
2138 * RETURNS
2139 * Success: ERROR_SUCCESS
2140 * Failure: nonzero error code from Winerror.h
2142 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2144 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2146 /* It seems to do this check before the hkey check */
2147 if (!lpFile || !*lpFile)
2148 return ERROR_INVALID_PARAMETER;
2150 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2152 /* Check for file existence */
2154 return ERROR_SUCCESS;
2158 /******************************************************************************
2159 * RegRestoreKeyA [ADVAPI32.@]
2161 * See RegRestoreKeyW.
2163 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2165 UNICODE_STRING lpFileW;
2166 LONG ret;
2168 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2169 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2170 RtlFreeUnicodeString( &lpFileW );
2171 return ret;
2175 /******************************************************************************
2176 * RegUnLoadKeyW [ADVAPI32.@]
2178 * Unload a registry key and its subkeys from the registry.
2180 * PARAMS
2181 * hkey [I] Handle of open key
2182 * lpSubKey [I] Address of name of subkey to unload
2184 * RETURNS
2185 * Success: ERROR_SUCCESS
2186 * Failure: nonzero error code from Winerror.h
2188 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2190 DWORD ret;
2191 HKEY shkey;
2192 OBJECT_ATTRIBUTES attr;
2193 UNICODE_STRING subkey;
2195 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2197 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2198 if( ret )
2199 return ERROR_INVALID_PARAMETER;
2201 RtlInitUnicodeString(&subkey, lpSubKey);
2202 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2203 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2205 RegCloseKey(shkey);
2207 return ret;
2211 /******************************************************************************
2212 * RegUnLoadKeyA [ADVAPI32.@]
2214 * See RegUnLoadKeyW.
2216 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2218 UNICODE_STRING lpSubKeyW;
2219 LONG ret;
2221 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2222 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2223 RtlFreeUnicodeString( &lpSubKeyW );
2224 return ret;
2228 /******************************************************************************
2229 * RegReplaceKeyW [ADVAPI32.@]
2231 * Replace the file backing a registry key and all its subkeys with another file.
2233 * PARAMS
2234 * hkey [I] Handle of open key
2235 * lpSubKey [I] Address of name of subkey
2236 * lpNewFile [I] Address of filename for file with new data
2237 * lpOldFile [I] Address of filename for backup file
2239 * RETURNS
2240 * Success: ERROR_SUCCESS
2241 * Failure: nonzero error code from Winerror.h
2243 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2244 LPCWSTR lpOldFile )
2246 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2247 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2248 return ERROR_SUCCESS;
2252 /******************************************************************************
2253 * RegReplaceKeyA [ADVAPI32.@]
2255 * See RegReplaceKeyW.
2257 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2258 LPCSTR lpOldFile )
2260 UNICODE_STRING lpSubKeyW;
2261 UNICODE_STRING lpNewFileW;
2262 UNICODE_STRING lpOldFileW;
2263 LONG ret;
2265 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2266 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2267 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2268 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2269 RtlFreeUnicodeString( &lpOldFileW );
2270 RtlFreeUnicodeString( &lpNewFileW );
2271 RtlFreeUnicodeString( &lpSubKeyW );
2272 return ret;
2276 /******************************************************************************
2277 * RegSetKeySecurity [ADVAPI32.@]
2279 * Set the security of an open registry key.
2281 * PARAMS
2282 * hkey [I] Open handle of key to set
2283 * SecurityInfo [I] Descriptor contents
2284 * pSecurityDesc [I] Address of descriptor for key
2286 * RETURNS
2287 * Success: ERROR_SUCCESS
2288 * Failure: nonzero error code from Winerror.h
2290 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2291 PSECURITY_DESCRIPTOR pSecurityDesc )
2293 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2295 /* It seems to perform this check before the hkey check */
2296 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2297 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2298 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2299 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2300 /* Param OK */
2301 } else
2302 return ERROR_INVALID_PARAMETER;
2304 if (!pSecurityDesc)
2305 return ERROR_INVALID_PARAMETER;
2307 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2309 return ERROR_SUCCESS;
2313 /******************************************************************************
2314 * RegGetKeySecurity [ADVAPI32.@]
2316 * Get a copy of the security descriptor for a given registry key.
2318 * PARAMS
2319 * hkey [I] Open handle of key to set
2320 * SecurityInformation [I] Descriptor contents
2321 * pSecurityDescriptor [O] Address of descriptor for key
2322 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2324 * RETURNS
2325 * Success: ERROR_SUCCESS
2326 * Failure: Error code
2328 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2329 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2330 LPDWORD lpcbSecurityDescriptor )
2332 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2333 *lpcbSecurityDescriptor);
2335 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2337 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2338 SecurityInformation, pSecurityDescriptor,
2339 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2343 /******************************************************************************
2344 * RegFlushKey [ADVAPI32.@]
2346 * Immediately write a registry key to registry.
2348 * PARAMS
2349 * hkey [I] Handle of key to write
2351 * RETURNS
2352 * Success: ERROR_SUCCESS
2353 * Failure: Error code
2355 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2357 hkey = get_special_root_hkey( hkey );
2358 if (!hkey) return ERROR_INVALID_HANDLE;
2360 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2364 /******************************************************************************
2365 * RegConnectRegistryW [ADVAPI32.@]
2367 * Establish a connection to a predefined registry key on another computer.
2369 * PARAMS
2370 * lpMachineName [I] Address of name of remote computer
2371 * hHey [I] Predefined registry handle
2372 * phkResult [I] Address of buffer for remote registry handle
2374 * RETURNS
2375 * Success: ERROR_SUCCESS
2376 * Failure: nonzero error code from Winerror.h
2378 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2379 PHKEY phkResult )
2381 LONG ret;
2383 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2385 if (!lpMachineName || !*lpMachineName) {
2386 /* Use the local machine name */
2387 ret = RegOpenKeyW( hKey, NULL, phkResult );
2389 else {
2390 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2391 DWORD len = sizeof(compName) / sizeof(WCHAR);
2393 /* MSDN says lpMachineName must start with \\ : not so */
2394 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2395 lpMachineName += 2;
2396 if (GetComputerNameW(compName, &len))
2398 if (!strcmpiW(lpMachineName, compName))
2399 ret = RegOpenKeyW(hKey, NULL, phkResult);
2400 else
2402 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2403 ret = ERROR_BAD_NETPATH;
2406 else
2407 ret = GetLastError();
2409 return ret;
2413 /******************************************************************************
2414 * RegConnectRegistryA [ADVAPI32.@]
2416 * See RegConnectRegistryW.
2418 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2420 UNICODE_STRING machineW;
2421 LONG ret;
2423 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2424 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2425 RtlFreeUnicodeString( &machineW );
2426 return ret;
2430 /******************************************************************************
2431 * RegNotifyChangeKeyValue [ADVAPI32.@]
2433 * Notify the caller about changes to the attributes or contents of a registry key.
2435 * PARAMS
2436 * hkey [I] Handle of key to watch
2437 * fWatchSubTree [I] Flag for subkey notification
2438 * fdwNotifyFilter [I] Changes to be reported
2439 * hEvent [I] Handle of signaled event
2440 * fAsync [I] Flag for asynchronous reporting
2442 * RETURNS
2443 * Success: ERROR_SUCCESS
2444 * Failure: nonzero error code from Winerror.h
2446 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2447 DWORD fdwNotifyFilter, HANDLE hEvent,
2448 BOOL fAsync )
2450 NTSTATUS status;
2451 IO_STATUS_BLOCK iosb;
2453 hkey = get_special_root_hkey( hkey );
2454 if (!hkey) return ERROR_INVALID_HANDLE;
2456 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2457 hEvent, fAsync);
2459 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2460 fdwNotifyFilter, fAsync, NULL, 0,
2461 fWatchSubTree);
2463 if (status && status != STATUS_TIMEOUT)
2464 return RtlNtStatusToDosError( status );
2466 return ERROR_SUCCESS;
2469 /******************************************************************************
2470 * RegOpenUserClassesRoot [ADVAPI32.@]
2472 * Open the HKEY_CLASSES_ROOT key for a user.
2474 * PARAMS
2475 * hToken [I] Handle of token representing the user
2476 * dwOptions [I] Reserved, must be 0
2477 * samDesired [I] Desired access rights
2478 * phkResult [O] Destination for the resulting key handle
2480 * RETURNS
2481 * Success: ERROR_SUCCESS
2482 * Failure: nonzero error code from Winerror.h
2484 * NOTES
2485 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2486 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2487 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2489 LSTATUS WINAPI RegOpenUserClassesRoot(
2490 HANDLE hToken,
2491 DWORD dwOptions,
2492 REGSAM samDesired,
2493 PHKEY phkResult
2496 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2498 *phkResult = HKEY_CLASSES_ROOT;
2499 return ERROR_SUCCESS;
2502 /******************************************************************************
2503 * load_string [Internal]
2505 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2506 * avoid importing user32, which is higher level than advapi32. Helper for
2507 * RegLoadMUIString.
2509 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2511 HGLOBAL hMemory;
2512 HRSRC hResource;
2513 WCHAR *pString;
2514 int idxString;
2516 /* Negative values have to be inverted. */
2517 if (HIWORD(resId) == 0xffff)
2518 resId = (UINT)(-((INT)resId));
2520 /* Load the resource into memory and get a pointer to it. */
2521 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2522 if (!hResource) return 0;
2523 hMemory = LoadResource(hModule, hResource);
2524 if (!hMemory) return 0;
2525 pString = LockResource(hMemory);
2527 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2528 idxString = resId & 0xf;
2529 while (idxString--) pString += *pString + 1;
2531 /* If no buffer is given, return length of the string. */
2532 if (!pwszBuffer) return *pString;
2534 /* Else copy over the string, respecting the buffer size. */
2535 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2536 if (cMaxChars >= 0) {
2537 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2538 pwszBuffer[cMaxChars] = '\0';
2541 return cMaxChars;
2544 /******************************************************************************
2545 * RegLoadMUIStringW [ADVAPI32.@]
2547 * Load the localized version of a string resource from some PE, respective
2548 * id and path of which are given in the registry value in the format
2549 * @[path]\dllname,-resourceId
2551 * PARAMS
2552 * hKey [I] Key, of which to load the string value from.
2553 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2554 * pszBuffer [O] Buffer to store the localized string in.
2555 * cbBuffer [I] Size of the destination buffer in bytes.
2556 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2557 * dwFlags [I] None supported yet.
2558 * pszBaseDir [I] Not supported yet.
2560 * RETURNS
2561 * Success: ERROR_SUCCESS,
2562 * Failure: nonzero error code from winerror.h
2564 * NOTES
2565 * This is an API of Windows Vista, which wasn't available at the time this code
2566 * was written. We have to check for the correct behaviour once it's available.
2568 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2569 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2571 DWORD dwValueType, cbData;
2572 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2573 LONG result;
2575 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2576 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2577 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2579 /* Parameter sanity checks. */
2580 if (!hKey || !pwszBuffer)
2581 return ERROR_INVALID_PARAMETER;
2583 if (pwszBaseDir && *pwszBaseDir) {
2584 FIXME("BaseDir parameter not yet supported!\n");
2585 return ERROR_INVALID_PARAMETER;
2588 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2589 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2590 if (result != ERROR_SUCCESS) goto cleanup;
2591 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2592 result = ERROR_FILE_NOT_FOUND;
2593 goto cleanup;
2595 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2596 if (!pwszTempBuffer) {
2597 result = ERROR_NOT_ENOUGH_MEMORY;
2598 goto cleanup;
2600 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2601 if (result != ERROR_SUCCESS) goto cleanup;
2603 /* Expand environment variables, if appropriate, or copy the original string over. */
2604 if (dwValueType == REG_EXPAND_SZ) {
2605 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2606 if (!cbData) goto cleanup;
2607 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2608 if (!pwszExpandedBuffer) {
2609 result = ERROR_NOT_ENOUGH_MEMORY;
2610 goto cleanup;
2612 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2613 } else {
2614 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2615 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2618 /* If the value references a resource based string, parse the value and load the string.
2619 * Else just copy over the original value. */
2620 result = ERROR_SUCCESS;
2621 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2622 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2623 } else {
2624 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2625 UINT uiStringId;
2626 HMODULE hModule;
2628 /* Format of the expanded value is 'path_to_dll,-resId' */
2629 if (!pComma || pComma[1] != '-') {
2630 result = ERROR_BADKEY;
2631 goto cleanup;
2634 uiStringId = atoiW(pComma+2);
2635 *pComma = '\0';
2637 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2638 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2639 result = ERROR_BADKEY;
2640 FreeLibrary(hModule);
2643 cleanup:
2644 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2645 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2646 return result;
2649 /******************************************************************************
2650 * RegLoadMUIStringA [ADVAPI32.@]
2652 * See RegLoadMUIStringW
2654 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2655 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2657 UNICODE_STRING valueW, baseDirW;
2658 WCHAR *pwszBuffer;
2659 DWORD cbData = cbBuffer * sizeof(WCHAR);
2660 LONG result;
2662 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2663 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2664 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2665 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2667 result = ERROR_NOT_ENOUGH_MEMORY;
2668 goto cleanup;
2671 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2672 baseDirW.Buffer);
2674 if (result == ERROR_SUCCESS) {
2675 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2676 if (pcbData)
2677 *pcbData = cbData;
2680 cleanup:
2681 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2682 RtlFreeUnicodeString(&baseDirW);
2683 RtlFreeUnicodeString(&valueW);
2685 return result;
2688 /******************************************************************************
2689 * RegDisablePredefinedCache [ADVAPI32.@]
2691 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2693 * PARAMS
2694 * None.
2696 * RETURNS
2697 * Success: ERROR_SUCCESS
2698 * Failure: nonzero error code from Winerror.h
2700 * NOTES
2701 * This is useful for services that use impersonation.
2703 LSTATUS WINAPI RegDisablePredefinedCache(void)
2705 HKEY hkey_current_user;
2706 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2708 /* prevent caching of future requests */
2709 hkcu_cache_disabled = TRUE;
2711 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2713 if (hkey_current_user)
2714 NtClose( hkey_current_user );
2716 return ERROR_SUCCESS;
2719 /******************************************************************************
2720 * RegDeleteTreeW [ADVAPI32.@]
2723 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2725 LONG ret;
2726 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2727 DWORD dwMaxLen, dwSize;
2728 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2729 HKEY hSubKey = hKey;
2731 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2733 if(lpszSubKey)
2735 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2736 if (ret) return ret;
2739 /* Get highest length for keys, values */
2740 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2741 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2742 if (ret) goto cleanup;
2744 dwMaxSubkeyLen++;
2745 dwMaxValueLen++;
2746 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2747 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2749 /* Name too big: alloc a buffer for it */
2750 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2752 ret = ERROR_NOT_ENOUGH_MEMORY;
2753 goto cleanup;
2758 /* Recursively delete all the subkeys */
2759 while (TRUE)
2761 dwSize = dwMaxLen;
2762 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2763 NULL, NULL, NULL)) break;
2765 ret = RegDeleteTreeW(hSubKey, lpszName);
2766 if (ret) goto cleanup;
2769 if (lpszSubKey)
2770 ret = RegDeleteKeyW(hKey, lpszSubKey);
2771 else
2772 while (TRUE)
2774 dwSize = dwMaxLen;
2775 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2776 NULL, NULL, NULL, NULL)) break;
2778 ret = RegDeleteValueW(hKey, lpszName);
2779 if (ret) goto cleanup;
2782 cleanup:
2783 /* Free buffer if allocated */
2784 if (lpszName != szNameBuf)
2785 HeapFree( GetProcessHeap(), 0, lpszName);
2786 if(lpszSubKey)
2787 RegCloseKey(hSubKey);
2788 return ret;
2791 /******************************************************************************
2792 * RegDeleteTreeA [ADVAPI32.@]
2795 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2797 LONG ret;
2798 UNICODE_STRING lpszSubKeyW;
2800 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2801 else lpszSubKeyW.Buffer = NULL;
2802 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2803 RtlFreeUnicodeString( &lpszSubKeyW );
2804 return ret;