kernel32: Silence a fixme in GetNativeSystemInfo.
[wine/multimedia.git] / dlls / advapi32 / registry.c
blobd7f6dc454c480a6308c505ed033afe115afde9a8
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 file is concerned about handle management and interaction with the Wine server.
12 * Registry file I/O is in misc/registry.c.
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38 #include "winerror.h"
39 #include "winternl.h"
40 #include "winuser.h"
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(reg);
47 /* allowed bits for access mask */
48 #define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
50 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
51 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
52 #define NB_SPECIAL_ROOT_KEYS ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
54 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
55 static BOOL hkcu_cache_disabled;
57 static const WCHAR name_CLASSES_ROOT[] =
58 {'M','a','c','h','i','n','e','\\',
59 'S','o','f','t','w','a','r','e','\\',
60 'C','l','a','s','s','e','s',0};
61 static const WCHAR name_LOCAL_MACHINE[] =
62 {'M','a','c','h','i','n','e',0};
63 static const WCHAR name_USERS[] =
64 {'U','s','e','r',0};
65 static const WCHAR name_PERFORMANCE_DATA[] =
66 {'P','e','r','f','D','a','t','a',0};
67 static const WCHAR name_CURRENT_CONFIG[] =
68 {'M','a','c','h','i','n','e','\\',
69 'S','y','s','t','e','m','\\',
70 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
71 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
72 'C','u','r','r','e','n','t',0};
73 static const WCHAR name_DYN_DATA[] =
74 {'D','y','n','D','a','t','a',0};
76 static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] =
78 name_CLASSES_ROOT,
79 NULL, /* HKEY_CURRENT_USER is determined dynamically */
80 name_LOCAL_MACHINE,
81 name_USERS,
82 name_PERFORMANCE_DATA,
83 name_CURRENT_CONFIG,
84 name_DYN_DATA
88 /* check if value type needs string conversion (Ansi<->Unicode) */
89 static inline int is_string( DWORD type )
91 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
94 /* check if current version is NT or Win95 */
95 static inline int is_version_nt(void)
97 return !(GetVersion() & 0x80000000);
100 /* create one of the HKEY_* special root keys */
101 static HKEY create_special_root_hkey( HANDLE hkey, DWORD access )
103 HKEY ret = 0;
104 int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
106 if (hkey == HKEY_CURRENT_USER)
108 if (RtlOpenCurrentUser( access, &hkey )) return 0;
109 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
111 /* don't cache the key in the table if caching is disabled */
112 if (hkcu_cache_disabled)
113 return hkey;
115 else
117 OBJECT_ATTRIBUTES attr;
118 UNICODE_STRING name;
120 attr.Length = sizeof(attr);
121 attr.RootDirectory = 0;
122 attr.ObjectName = &name;
123 attr.Attributes = 0;
124 attr.SecurityDescriptor = NULL;
125 attr.SecurityQualityOfService = NULL;
126 RtlInitUnicodeString( &name, root_key_names[idx] );
127 if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
128 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
131 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
132 ret = hkey;
133 else
134 NtClose( hkey ); /* somebody beat us to it */
135 return ret;
138 /* map the hkey from special root to normal key if necessary */
139 static inline HKEY get_special_root_hkey( HKEY hkey )
141 HKEY ret = hkey;
143 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
145 if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
146 ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
148 return ret;
152 /******************************************************************************
153 * RegCreateKeyExW [ADVAPI32.@]
155 * See RegCreateKeyExA.
157 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
158 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
159 PHKEY retkey, LPDWORD dispos )
161 OBJECT_ATTRIBUTES attr;
162 UNICODE_STRING nameW, classW;
164 if (reserved) return ERROR_INVALID_PARAMETER;
165 if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
166 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
168 attr.Length = sizeof(attr);
169 attr.RootDirectory = hkey;
170 attr.ObjectName = &nameW;
171 attr.Attributes = 0;
172 attr.SecurityDescriptor = NULL;
173 attr.SecurityQualityOfService = NULL;
174 RtlInitUnicodeString( &nameW, name );
175 RtlInitUnicodeString( &classW, class );
177 return RtlNtStatusToDosError( NtCreateKey( (PHANDLE)retkey, access, &attr, 0,
178 &classW, options, dispos ) );
182 /******************************************************************************
183 * RegCreateKeyExA [ADVAPI32.@]
185 * Open a registry key, creating it if it doesn't exist.
187 * PARAMS
188 * hkey [I] Handle of the parent registry key
189 * name [I] Name of the new key to open or create
190 * reserved [I] Reserved, pass 0
191 * class [I] The object type of the new key
192 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
193 * access [I] Access level desired
194 * sa [I] Security attributes for the key
195 * retkey [O] Destination for the resulting handle
196 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
198 * RETURNS
199 * Success: ERROR_SUCCESS.
200 * Failure: A standard Win32 error code. retkey remains untouched.
202 * FIXME
203 * MAXIMUM_ALLOWED in access mask not supported by server
205 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
206 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
207 PHKEY retkey, LPDWORD dispos )
209 OBJECT_ATTRIBUTES attr;
210 UNICODE_STRING classW;
211 ANSI_STRING nameA, classA;
212 NTSTATUS status;
214 if (reserved) return ERROR_INVALID_PARAMETER;
215 if (!is_version_nt())
217 access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
218 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
220 else if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
221 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
223 attr.Length = sizeof(attr);
224 attr.RootDirectory = hkey;
225 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
226 attr.Attributes = 0;
227 attr.SecurityDescriptor = NULL;
228 attr.SecurityQualityOfService = NULL;
229 RtlInitAnsiString( &nameA, name );
230 RtlInitAnsiString( &classA, class );
232 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
233 &nameA, FALSE )))
235 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
237 status = NtCreateKey( (PHANDLE)retkey, access, &attr, 0, &classW, options, dispos );
238 RtlFreeUnicodeString( &classW );
241 return RtlNtStatusToDosError( status );
245 /******************************************************************************
246 * RegCreateKeyW [ADVAPI32.@]
248 * Creates the specified reg key.
250 * PARAMS
251 * hKey [I] Handle to an open key.
252 * lpSubKey [I] Name of a key that will be opened or created.
253 * phkResult [O] Receives a handle to the opened or created key.
255 * RETURNS
256 * Success: ERROR_SUCCESS
257 * Failure: nonzero error code defined in Winerror.h
259 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
261 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
262 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
263 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
264 KEY_ALL_ACCESS, NULL, phkResult, NULL );
268 /******************************************************************************
269 * RegCreateKeyA [ADVAPI32.@]
271 * See RegCreateKeyW.
273 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
275 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
276 KEY_ALL_ACCESS, NULL, phkResult, NULL );
281 /******************************************************************************
282 * RegOpenKeyExW [ADVAPI32.@]
284 * See RegOpenKeyExA.
286 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
288 OBJECT_ATTRIBUTES attr;
289 UNICODE_STRING nameW;
291 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
293 attr.Length = sizeof(attr);
294 attr.RootDirectory = hkey;
295 attr.ObjectName = &nameW;
296 attr.Attributes = 0;
297 attr.SecurityDescriptor = NULL;
298 attr.SecurityQualityOfService = NULL;
299 RtlInitUnicodeString( &nameW, name );
300 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE)retkey, access, &attr ) );
304 /******************************************************************************
305 * RegOpenKeyExA [ADVAPI32.@]
307 * Open a registry key.
309 * PARAMS
310 * hkey [I] Handle of open key
311 * name [I] Name of subkey to open
312 * reserved [I] Reserved - must be zero
313 * access [I] Security access mask
314 * retkey [O] Handle to open key
316 * RETURNS
317 * Success: ERROR_SUCCESS
318 * Failure: A standard Win32 error code. retkey is set to 0.
320 * NOTES
321 * Unlike RegCreateKeyExA(), this function will not create the key if it
322 * does not exist.
324 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
326 OBJECT_ATTRIBUTES attr;
327 STRING nameA;
328 NTSTATUS status;
330 if (!is_version_nt()) access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
332 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
334 attr.Length = sizeof(attr);
335 attr.RootDirectory = hkey;
336 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
337 attr.Attributes = 0;
338 attr.SecurityDescriptor = NULL;
339 attr.SecurityQualityOfService = NULL;
341 RtlInitAnsiString( &nameA, name );
342 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
343 &nameA, FALSE )))
345 status = NtOpenKey( (PHANDLE)retkey, access, &attr );
347 return RtlNtStatusToDosError( status );
351 /******************************************************************************
352 * RegOpenKeyW [ADVAPI32.@]
354 * See RegOpenKeyA.
356 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
358 if (!name || !*name)
360 *retkey = hkey;
361 return ERROR_SUCCESS;
363 return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
367 /******************************************************************************
368 * RegOpenKeyA [ADVAPI32.@]
370 * Open a registry key.
372 * PARAMS
373 * hkey [I] Handle of parent key to open the new key under
374 * name [I] Name of the key under hkey to open
375 * retkey [O] Destination for the resulting Handle
377 * RETURNS
378 * Success: ERROR_SUCCESS
379 * Failure: A standard Win32 error code. retkey is set to 0.
381 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
383 if (!name || !*name)
385 *retkey = hkey;
386 return ERROR_SUCCESS;
388 return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
392 /******************************************************************************
393 * RegOpenCurrentUser [ADVAPI32.@]
395 * Get a handle to the HKEY_CURRENT_USER key for the user
396 * the current thread is impersonating.
398 * PARAMS
399 * access [I] Desired access rights to the key
400 * retkey [O] Handle to the opened key
402 * RETURNS
403 * Success: ERROR_SUCCESS
404 * Failure: nonzero error code from Winerror.h
406 * FIXME
407 * This function is supposed to retrieve a handle to the
408 * HKEY_CURRENT_USER for the user the current thread is impersonating.
409 * Since Wine does not currently allow threads to impersonate other users,
410 * this stub should work fine.
412 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
414 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
419 /******************************************************************************
420 * RegEnumKeyExW [ADVAPI32.@]
422 * Enumerate subkeys of the specified open registry key.
424 * PARAMS
425 * hkey [I] Handle to key to enumerate
426 * index [I] Index of subkey to enumerate
427 * name [O] Buffer for subkey name
428 * name_len [O] Size of subkey buffer
429 * reserved [I] Reserved
430 * class [O] Buffer for class string
431 * class_len [O] Size of class buffer
432 * ft [O] Time key last written to
434 * RETURNS
435 * Success: ERROR_SUCCESS
436 * Failure: System error code. If there are no more subkeys available, the
437 * function returns ERROR_NO_MORE_ITEMS.
439 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
440 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
442 NTSTATUS status;
443 char buffer[256], *buf_ptr = buffer;
444 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
445 DWORD total_size;
447 TRACE( "(%p,%d,%p,%p(%d),%p,%p,%p,%p)\n", hkey, index, name, name_len,
448 name_len ? *name_len : -1, reserved, class, class_len, ft );
450 if (reserved) return ERROR_INVALID_PARAMETER;
451 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
453 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
454 buffer, sizeof(buffer), &total_size );
456 while (status == STATUS_BUFFER_OVERFLOW)
458 /* retry with a dynamically allocated buffer */
459 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
460 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
461 return ERROR_NOT_ENOUGH_MEMORY;
462 info = (KEY_NODE_INFORMATION *)buf_ptr;
463 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
464 buf_ptr, total_size, &total_size );
467 if (!status)
469 DWORD len = info->NameLength / sizeof(WCHAR);
470 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
472 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
474 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
475 status = STATUS_BUFFER_OVERFLOW;
476 else
478 *name_len = len;
479 memcpy( name, info->Name, info->NameLength );
480 name[len] = 0;
481 if (class_len)
483 *class_len = cls_len;
484 if (class)
486 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
487 class[cls_len] = 0;
493 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
494 return RtlNtStatusToDosError( status );
498 /******************************************************************************
499 * RegEnumKeyExA [ADVAPI32.@]
501 * See RegEnumKeyExW.
503 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
504 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
506 NTSTATUS status;
507 char buffer[256], *buf_ptr = buffer;
508 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
509 DWORD total_size;
511 TRACE( "(%p,%d,%p,%p(%d),%p,%p,%p,%p)\n", hkey, index, name, name_len,
512 name_len ? *name_len : -1, reserved, class, class_len, ft );
514 if (reserved) return ERROR_INVALID_PARAMETER;
515 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
517 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
518 buffer, sizeof(buffer), &total_size );
520 while (status == STATUS_BUFFER_OVERFLOW)
522 /* retry with a dynamically allocated buffer */
523 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
524 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
525 return ERROR_NOT_ENOUGH_MEMORY;
526 info = (KEY_NODE_INFORMATION *)buf_ptr;
527 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
528 buf_ptr, total_size, &total_size );
531 if (!status)
533 DWORD len, cls_len;
535 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
536 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
537 info->ClassLength );
538 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
540 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
541 status = STATUS_BUFFER_OVERFLOW;
542 else
544 *name_len = len;
545 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
546 name[len] = 0;
547 if (class_len)
549 *class_len = cls_len;
550 if (class)
552 RtlUnicodeToMultiByteN( class, cls_len, NULL,
553 (WCHAR *)(buf_ptr + info->ClassOffset),
554 info->ClassLength );
555 class[cls_len] = 0;
561 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
562 return RtlNtStatusToDosError( status );
566 /******************************************************************************
567 * RegEnumKeyW [ADVAPI32.@]
569 * Enumerates subkeys of the specified open reg key.
571 * PARAMS
572 * hKey [I] Handle to an open key.
573 * dwIndex [I] Index of the subkey of hKey to retrieve.
574 * lpName [O] Name of the subkey.
575 * cchName [I] Size of lpName in TCHARS.
577 * RETURNS
578 * Success: ERROR_SUCCESS
579 * Failure: system error code. If there are no more subkeys available, the
580 * function returns ERROR_NO_MORE_ITEMS.
582 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
584 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
588 /******************************************************************************
589 * RegEnumKeyA [ADVAPI32.@]
591 * See RegEnumKeyW.
593 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
595 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
599 /******************************************************************************
600 * RegQueryInfoKeyW [ADVAPI32.@]
602 * Retrieves information about the specified registry key.
604 * PARAMS
605 * hkey [I] Handle to key to query
606 * class [O] Buffer for class string
607 * class_len [O] Size of class string buffer
608 * reserved [I] Reserved
609 * subkeys [O] Buffer for number of subkeys
610 * max_subkey [O] Buffer for longest subkey name length
611 * max_class [O] Buffer for longest class string length
612 * values [O] Buffer for number of value entries
613 * max_value [O] Buffer for longest value name length
614 * max_data [O] Buffer for longest value data length
615 * security [O] Buffer for security descriptor length
616 * modif [O] Modification time
618 * RETURNS
619 * Success: ERROR_SUCCESS
620 * Failure: system error code.
622 * NOTES
623 * - win95 allows class to be valid and class_len to be NULL
624 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
625 * - both allow class to be NULL and class_len to be NULL
626 * (it's hard to test validity, so test !NULL instead)
628 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
629 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
630 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
631 LPDWORD security, FILETIME *modif )
633 NTSTATUS status;
634 char buffer[256], *buf_ptr = buffer;
635 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
636 DWORD total_size;
638 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
639 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
641 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
642 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
644 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
645 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
647 if (class)
649 /* retry with a dynamically allocated buffer */
650 while (status == STATUS_BUFFER_OVERFLOW)
652 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
653 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
654 return ERROR_NOT_ENOUGH_MEMORY;
655 info = (KEY_FULL_INFORMATION *)buf_ptr;
656 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
659 if (status) goto done;
661 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
663 status = STATUS_BUFFER_OVERFLOW;
665 else
667 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
668 class[info->ClassLength/sizeof(WCHAR)] = 0;
671 else status = STATUS_SUCCESS;
673 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
674 if (subkeys) *subkeys = info->SubKeys;
675 if (max_subkey) *max_subkey = info->MaxNameLen;
676 if (max_class) *max_class = info->MaxClassLen;
677 if (values) *values = info->Values;
678 if (max_value) *max_value = info->MaxValueNameLen;
679 if (max_data) *max_data = info->MaxValueDataLen;
680 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
682 done:
683 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
684 return RtlNtStatusToDosError( status );
688 /******************************************************************************
689 * RegQueryMultipleValuesA [ADVAPI32.@]
691 * Retrieves the type and data for a list of value names associated with a key.
693 * PARAMS
694 * hKey [I] Handle to an open key.
695 * val_list [O] Array of VALENT structures that describes the entries.
696 * num_vals [I] Number of elements in val_list.
697 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
698 * ldwTotsize [I/O] Size of lpValueBuf.
700 * RETURNS
701 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
702 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
703 * bytes.
705 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
706 LPSTR lpValueBuf, LPDWORD ldwTotsize )
708 unsigned int i;
709 DWORD maxBytes = *ldwTotsize;
710 HRESULT status;
711 LPSTR bufptr = lpValueBuf;
712 *ldwTotsize = 0;
714 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
716 for(i=0; i < num_vals; ++i)
719 val_list[i].ve_valuelen=0;
720 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
721 if(status != ERROR_SUCCESS)
723 return status;
726 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
728 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
729 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
730 if(status != ERROR_SUCCESS)
732 return status;
735 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
737 bufptr += val_list[i].ve_valuelen;
740 *ldwTotsize += val_list[i].ve_valuelen;
742 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
746 /******************************************************************************
747 * RegQueryMultipleValuesW [ADVAPI32.@]
749 * See RegQueryMultipleValuesA.
751 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
752 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
754 unsigned int i;
755 DWORD maxBytes = *ldwTotsize;
756 HRESULT status;
757 LPSTR bufptr = (LPSTR)lpValueBuf;
758 *ldwTotsize = 0;
760 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
762 for(i=0; i < num_vals; ++i)
764 val_list[i].ve_valuelen=0;
765 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
766 if(status != ERROR_SUCCESS)
768 return status;
771 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
773 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
774 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
775 if(status != ERROR_SUCCESS)
777 return status;
780 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
782 bufptr += val_list[i].ve_valuelen;
785 *ldwTotsize += val_list[i].ve_valuelen;
787 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
790 /******************************************************************************
791 * RegQueryInfoKeyA [ADVAPI32.@]
793 * Retrieves information about a registry key.
795 * PARAMS
796 * hKey [I] Handle to an open key.
797 * lpClass [O] Class string of the key.
798 * lpcClass [I/O] size of lpClass.
799 * lpReserved [I] Reserved; must be NULL.
800 * lpcSubKeys [O] Number of subkeys contained by the key.
801 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
802 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
803 * class in TCHARS.
804 * lpcValues [O] Number of values associated with the key.
805 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
806 * lpcMaxValueLen [O] Longest data component among the key's values
807 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
808 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
810 * RETURNS
811 * Success: ERROR_SUCCESS
812 * Failure: nonzero error code from Winerror.h
814 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
815 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
816 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
817 LPDWORD security, FILETIME *modif )
819 NTSTATUS status;
820 char buffer[256], *buf_ptr = buffer;
821 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
822 DWORD total_size, len;
824 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
825 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
827 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
828 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
830 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
831 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
833 if (class || class_len)
835 /* retry with a dynamically allocated buffer */
836 while (status == STATUS_BUFFER_OVERFLOW)
838 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
839 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
840 return ERROR_NOT_ENOUGH_MEMORY;
841 info = (KEY_FULL_INFORMATION *)buf_ptr;
842 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
845 if (status) goto done;
847 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
848 if (class_len)
850 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
851 *class_len = len;
853 if (class && !status)
855 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
856 info->ClassLength );
857 class[len] = 0;
860 else status = STATUS_SUCCESS;
862 if (subkeys) *subkeys = info->SubKeys;
863 if (max_subkey) *max_subkey = info->MaxNameLen;
864 if (max_class) *max_class = info->MaxClassLen;
865 if (values) *values = info->Values;
866 if (max_value) *max_value = info->MaxValueNameLen;
867 if (max_data) *max_data = info->MaxValueDataLen;
868 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
870 done:
871 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
872 return RtlNtStatusToDosError( status );
876 /******************************************************************************
877 * RegCloseKey [ADVAPI32.@]
879 * Close an open registry key.
881 * PARAMS
882 * hkey [I] Handle of key to close
884 * RETURNS
885 * Success: ERROR_SUCCESS
886 * Failure: Error code
888 LSTATUS WINAPI RegCloseKey( HKEY hkey )
890 if (!hkey) return ERROR_INVALID_HANDLE;
891 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
892 return RtlNtStatusToDosError( NtClose( hkey ) );
896 /******************************************************************************
897 * RegDeleteKeyW [ADVAPI32.@]
899 * See RegDeleteKeyA.
901 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
903 DWORD ret;
904 HKEY tmp;
906 if (!name) return ERROR_INVALID_PARAMETER;
908 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
910 if (!(ret = RegOpenKeyExW( hkey, name, 0, DELETE, &tmp )))
912 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
913 RegCloseKey( tmp );
915 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
916 return ret;
920 /******************************************************************************
921 * RegDeleteKeyA [ADVAPI32.@]
923 * Delete a registry key.
925 * PARAMS
926 * hkey [I] Handle to parent key containing the key to delete
927 * name [I] Name of the key user hkey to delete
929 * NOTES
931 * MSDN is wrong when it says that hkey must be opened with the DELETE access
932 * right. In reality, it opens a new handle with DELETE access.
934 * RETURNS
935 * Success: ERROR_SUCCESS
936 * Failure: Error code
938 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
940 DWORD ret;
941 HKEY tmp;
943 if (!name) return ERROR_INVALID_PARAMETER;
945 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
947 if (!(ret = RegOpenKeyExA( hkey, name, 0, DELETE, &tmp )))
949 if (!is_version_nt()) /* win95 does recursive key deletes */
951 CHAR name[MAX_PATH];
953 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
955 if(RegDeleteKeyA(tmp, name)) /* recurse */
956 break;
959 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
960 RegCloseKey( tmp );
962 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
963 return ret;
968 /******************************************************************************
969 * RegSetValueExW [ADVAPI32.@]
971 * Set the data and contents of a registry value.
973 * PARAMS
974 * hkey [I] Handle of key to set value for
975 * name [I] Name of value to set
976 * reserved [I] Reserved, must be zero
977 * type [I] Type of the value being set
978 * data [I] The new contents of the value to set
979 * count [I] Size of data
981 * RETURNS
982 * Success: ERROR_SUCCESS
983 * Failure: Error code
985 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
986 DWORD type, CONST BYTE *data, DWORD count )
988 UNICODE_STRING nameW;
990 /* no need for version check, not implemented on win9x anyway */
991 if (count && is_string(type))
993 LPCWSTR str = (LPCWSTR)data;
994 /* if user forgot to count terminating null, add it (yes NT does this) */
995 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
996 count += sizeof(WCHAR);
998 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1000 RtlInitUnicodeString( &nameW, name );
1001 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1005 /******************************************************************************
1006 * RegSetValueExA [ADVAPI32.@]
1008 * See RegSetValueExW.
1010 * NOTES
1011 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1012 * NT does definitely care (aj)
1014 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1015 CONST BYTE *data, DWORD count )
1017 ANSI_STRING nameA;
1018 WCHAR *dataW = NULL;
1019 NTSTATUS status;
1021 if (!is_version_nt()) /* win95 */
1023 if (type == REG_SZ)
1025 if (!data) return ERROR_INVALID_PARAMETER;
1026 count = strlen((const char *)data) + 1;
1029 else if (count && is_string(type))
1031 /* if user forgot to count terminating null, add it (yes NT does this) */
1032 if (data[count-1] && !data[count]) count++;
1035 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1037 if (is_string( type )) /* need to convert to Unicode */
1039 DWORD lenW;
1040 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1041 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1042 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1043 count = lenW;
1044 data = (BYTE *)dataW;
1047 RtlInitAnsiString( &nameA, name );
1048 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1049 &nameA, FALSE )))
1051 status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
1053 HeapFree( GetProcessHeap(), 0, dataW );
1054 return RtlNtStatusToDosError( status );
1058 /******************************************************************************
1059 * RegSetValueW [ADVAPI32.@]
1061 * Sets the data for the default or unnamed value of a reg key.
1063 * PARAMS
1064 * hKey [I] Handle to an open key.
1065 * lpSubKey [I] Name of a subkey of hKey.
1066 * dwType [I] Type of information to store.
1067 * lpData [I] String that contains the data to set for the default value.
1068 * cbData [I] Size of lpData.
1070 * RETURNS
1071 * Success: ERROR_SUCCESS
1072 * Failure: nonzero error code from Winerror.h
1074 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1076 HKEY subkey = hkey;
1077 DWORD ret;
1079 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1081 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
1083 if (name && name[0]) /* need to create the subkey */
1085 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1088 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1089 (strlenW( data ) + 1) * sizeof(WCHAR) );
1090 if (subkey != hkey) RegCloseKey( subkey );
1091 return ret;
1095 /******************************************************************************
1096 * RegSetValueA [ADVAPI32.@]
1098 * See RegSetValueW.
1100 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1102 HKEY subkey = hkey;
1103 DWORD ret;
1105 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1107 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
1109 if (name && name[0]) /* need to create the subkey */
1111 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1113 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1114 if (subkey != hkey) RegCloseKey( subkey );
1115 return ret;
1120 /******************************************************************************
1121 * RegQueryValueExW [ADVAPI32.@]
1123 * See RegQueryValueExA.
1125 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1126 LPBYTE data, LPDWORD count )
1128 NTSTATUS status;
1129 UNICODE_STRING name_str;
1130 DWORD total_size;
1131 char buffer[256], *buf_ptr = buffer;
1132 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1133 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1135 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1136 hkey, debugstr_w(name), reserved, type, data, count,
1137 (count && data) ? *count : 0 );
1139 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1140 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1142 RtlInitUnicodeString( &name_str, name );
1144 if (data) total_size = min( sizeof(buffer), *count + info_size );
1145 else
1147 total_size = info_size;
1148 if (count) *count = 0;
1151 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1152 buffer, total_size, &total_size );
1153 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1155 if (data)
1157 /* retry with a dynamically allocated buffer */
1158 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1160 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1161 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1162 return ERROR_NOT_ENOUGH_MEMORY;
1163 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1164 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1165 buf_ptr, total_size, &total_size );
1168 if (!status)
1170 memcpy( data, buf_ptr + info_size, total_size - info_size );
1171 /* if the type is REG_SZ and data is not 0-terminated
1172 * and there is enough space in the buffer NT appends a \0 */
1173 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1175 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1176 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1179 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1181 else status = STATUS_SUCCESS;
1183 if (type) *type = info->Type;
1184 if (count) *count = total_size - info_size;
1186 done:
1187 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1188 return RtlNtStatusToDosError(status);
1192 /******************************************************************************
1193 * RegQueryValueExA [ADVAPI32.@]
1195 * Get the type and contents of a specified value under with a key.
1197 * PARAMS
1198 * hkey [I] Handle of the key to query
1199 * name [I] Name of value under hkey to query
1200 * reserved [I] Reserved - must be NULL
1201 * type [O] Destination for the value type, or NULL if not required
1202 * data [O] Destination for the values contents, or NULL if not required
1203 * count [I/O] Size of data, updated with the number of bytes returned
1205 * RETURNS
1206 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1207 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1208 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1209 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1211 * NOTES
1212 * MSDN states that if data is too small it is partially filled. In reality
1213 * it remains untouched.
1215 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1216 LPBYTE data, LPDWORD count )
1218 NTSTATUS status;
1219 ANSI_STRING nameA;
1220 DWORD total_size, datalen = 0;
1221 char buffer[256], *buf_ptr = buffer;
1222 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1223 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1225 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1226 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1228 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1229 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1231 if (count) datalen = *count;
1232 if (!data && count) *count = 0;
1234 /* this matches Win9x behaviour - NT sets *type to a random value */
1235 if (type) *type = REG_NONE;
1237 RtlInitAnsiString( &nameA, name );
1238 if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1239 &nameA, FALSE )))
1240 return RtlNtStatusToDosError(status);
1242 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1243 KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
1244 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1246 /* we need to fetch the contents for a string type even if not requested,
1247 * because we need to compute the length of the ASCII string. */
1248 if (data || is_string(info->Type))
1250 /* retry with a dynamically allocated buffer */
1251 while (status == STATUS_BUFFER_OVERFLOW)
1253 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1254 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1256 status = STATUS_NO_MEMORY;
1257 goto done;
1259 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1260 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1261 KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1264 if (status) goto done;
1266 if (is_string(info->Type))
1268 DWORD len;
1270 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1271 total_size - info_size );
1272 if (data && len)
1274 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1275 else
1277 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1278 total_size - info_size );
1279 /* if the type is REG_SZ and data is not 0-terminated
1280 * and there is enough space in the buffer NT appends a \0 */
1281 if (len < datalen && data[len-1]) data[len] = 0;
1284 total_size = len + info_size;
1286 else if (data)
1288 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1289 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1292 else status = STATUS_SUCCESS;
1294 if (type) *type = info->Type;
1295 if (count) *count = total_size - info_size;
1297 done:
1298 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1299 return RtlNtStatusToDosError(status);
1303 /******************************************************************************
1304 * RegQueryValueW [ADVAPI32.@]
1306 * Retrieves the data associated with the default or unnamed value of a key.
1308 * PARAMS
1309 * hkey [I] Handle to an open key.
1310 * name [I] Name of the subkey of hKey.
1311 * data [O] Receives the string associated with the default value
1312 * of the key.
1313 * count [I/O] Size of lpValue in bytes.
1315 * RETURNS
1316 * Success: ERROR_SUCCESS
1317 * Failure: nonzero error code from Winerror.h
1319 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1321 DWORD ret;
1322 HKEY subkey = hkey;
1324 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1326 if (name && name[0])
1328 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1330 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1331 if (subkey != hkey) RegCloseKey( subkey );
1332 if (ret == ERROR_FILE_NOT_FOUND)
1334 /* return empty string if default value not found */
1335 if (data) *data = 0;
1336 if (count) *count = sizeof(WCHAR);
1337 ret = ERROR_SUCCESS;
1339 return ret;
1343 /******************************************************************************
1344 * RegQueryValueA [ADVAPI32.@]
1346 * See RegQueryValueW.
1348 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1350 DWORD ret;
1351 HKEY subkey = hkey;
1353 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1355 if (name && name[0])
1357 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1359 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1360 if (subkey != hkey) RegCloseKey( subkey );
1361 if (ret == ERROR_FILE_NOT_FOUND)
1363 /* return empty string if default value not found */
1364 if (data) *data = 0;
1365 if (count) *count = 1;
1366 ret = ERROR_SUCCESS;
1368 return ret;
1372 /******************************************************************************
1373 * ADVAPI_ApplyRestrictions [internal]
1375 * Helper function for RegGetValueA/W.
1377 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1378 DWORD cbData, PLONG ret )
1380 /* Check if the type is restricted by the passed flags */
1381 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1383 DWORD dwMask = 0;
1385 switch (dwType)
1387 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1388 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1389 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1390 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1391 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1392 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1393 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1396 if (dwFlags & dwMask)
1398 /* Type is not restricted, check for size mismatch */
1399 if (dwType == REG_BINARY)
1401 DWORD cbExpect = 0;
1403 if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD)
1404 cbExpect = 4;
1405 else if ((dwFlags & RRF_RT_QWORD) == RRF_RT_QWORD)
1406 cbExpect = 8;
1408 if (cbExpect && cbData != cbExpect)
1409 *ret = ERROR_DATATYPE_MISMATCH;
1412 else *ret = ERROR_UNSUPPORTED_TYPE;
1417 /******************************************************************************
1418 * RegGetValueW [ADVAPI32.@]
1420 * Retrieves the type and data for a value name associated with a key
1421 * optionally expanding it's content and restricting it's type.
1423 * PARAMS
1424 * hKey [I] Handle to an open key.
1425 * pszSubKey [I] Name of the subkey of hKey.
1426 * pszValue [I] Name of value under hKey/szSubKey to query.
1427 * dwFlags [I] Flags restricting the value type to retrieve.
1428 * pdwType [O] Destination for the values type, may be NULL.
1429 * pvData [O] Destination for the values content, may be NULL.
1430 * pcbData [I/O] Size of pvData, updated with the size required to
1431 * retrieve the whole content.
1433 * RETURNS
1434 * Success: ERROR_SUCCESS
1435 * Failure: nonzero error code from Winerror.h
1437 * NOTES
1438 * - Unless RRF_NOEXPAND is specified REG_EXPAND_SZ is automatically expanded
1439 * and REG_SZ is retrieved instead.
1440 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1441 * without RRF_NOEXPAND is thus not allowed.
1443 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1444 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1445 LPDWORD pcbData )
1447 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1448 PVOID pvBuf = NULL;
1449 LONG ret;
1451 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1452 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1453 pvData, pcbData, cbData);
1455 if (pvData && !pcbData)
1456 return ERROR_INVALID_PARAMETER;
1457 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
1458 return ERROR_INVALID_PARAMETER;
1460 if (pszSubKey && pszSubKey[0])
1462 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1463 if (ret != ERROR_SUCCESS) return ret;
1466 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1468 /* If we are going to expand we need to read in the whole the value even
1469 * if the passed buffer was too small as the expanded string might be
1470 * smaller than the unexpanded one and could fit into cbData bytes. */
1471 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1472 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1474 do {
1475 HeapFree(GetProcessHeap(), 0, pvBuf);
1477 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1478 if (!pvBuf)
1480 ret = ERROR_NOT_ENOUGH_MEMORY;
1481 break;
1484 if (ret == ERROR_MORE_DATA || !pvData)
1485 ret = RegQueryValueExW(hKey, pszValue, NULL,
1486 &dwType, pvBuf, &cbData);
1487 else
1489 /* Even if cbData was large enough we have to copy the
1490 * string since ExpandEnvironmentStrings can't handle
1491 * overlapping buffers. */
1492 CopyMemory(pvBuf, pvData, cbData);
1495 /* Both the type or the value itself could have been modified in
1496 * between so we have to keep retrying until the buffer is large
1497 * enough or we no longer have to expand the value. */
1498 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1500 if (ret == ERROR_SUCCESS)
1502 /* Recheck dwType in case it changed since the first call */
1503 if (dwType == REG_EXPAND_SZ)
1505 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1506 pcbData ? *pcbData : 0);
1507 dwType = REG_SZ;
1508 if(pcbData && cbData > *pcbData)
1509 ret = ERROR_MORE_DATA;
1511 else if (pvData)
1512 CopyMemory(pvData, pvBuf, *pcbData);
1515 HeapFree(GetProcessHeap(), 0, pvBuf);
1518 if (pszSubKey && pszSubKey[0])
1519 RegCloseKey(hKey);
1521 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1523 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1524 ZeroMemory(pvData, *pcbData);
1526 if (pdwType) *pdwType = dwType;
1527 if (pcbData) *pcbData = cbData;
1529 return ret;
1533 /******************************************************************************
1534 * RegGetValueA [ADVAPI32.@]
1536 * See RegGetValueW.
1538 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1539 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1540 LPDWORD pcbData )
1542 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1543 PVOID pvBuf = NULL;
1544 LONG ret;
1546 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1547 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1548 cbData);
1550 if (pvData && !pcbData)
1551 return ERROR_INVALID_PARAMETER;
1552 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
1553 return ERROR_INVALID_PARAMETER;
1555 if (pszSubKey && pszSubKey[0])
1557 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1558 if (ret != ERROR_SUCCESS) return ret;
1561 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1563 /* If we are going to expand we need to read in the whole the value even
1564 * if the passed buffer was too small as the expanded string might be
1565 * smaller than the unexpanded one and could fit into cbData bytes. */
1566 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1567 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1569 do {
1570 HeapFree(GetProcessHeap(), 0, pvBuf);
1572 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1573 if (!pvBuf)
1575 ret = ERROR_NOT_ENOUGH_MEMORY;
1576 break;
1579 if (ret == ERROR_MORE_DATA || !pvData)
1580 ret = RegQueryValueExA(hKey, pszValue, NULL,
1581 &dwType, pvBuf, &cbData);
1582 else
1584 /* Even if cbData was large enough we have to copy the
1585 * string since ExpandEnvironmentStrings can't handle
1586 * overlapping buffers. */
1587 CopyMemory(pvBuf, pvData, cbData);
1590 /* Both the type or the value itself could have been modified in
1591 * between so we have to keep retrying until the buffer is large
1592 * enough or we no longer have to expand the value. */
1593 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1595 if (ret == ERROR_SUCCESS)
1597 /* Recheck dwType in case it changed since the first call */
1598 if (dwType == REG_EXPAND_SZ)
1600 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1601 pcbData ? *pcbData : 0);
1602 dwType = REG_SZ;
1603 if(pcbData && cbData > *pcbData)
1604 ret = ERROR_MORE_DATA;
1606 else if (pvData)
1607 CopyMemory(pvData, pvBuf, *pcbData);
1610 HeapFree(GetProcessHeap(), 0, pvBuf);
1613 if (pszSubKey && pszSubKey[0])
1614 RegCloseKey(hKey);
1616 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1618 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1619 ZeroMemory(pvData, *pcbData);
1621 if (pdwType) *pdwType = dwType;
1622 if (pcbData) *pcbData = cbData;
1624 return ret;
1628 /******************************************************************************
1629 * RegEnumValueW [ADVAPI32.@]
1631 * Enumerates the values for the specified open registry key.
1633 * PARAMS
1634 * hkey [I] Handle to key to query
1635 * index [I] Index of value to query
1636 * value [O] Value string
1637 * val_count [I/O] Size of value buffer (in wchars)
1638 * reserved [I] Reserved
1639 * type [O] Type code
1640 * data [O] Value data
1641 * count [I/O] Size of data buffer (in bytes)
1643 * RETURNS
1644 * Success: ERROR_SUCCESS
1645 * Failure: nonzero error code from Winerror.h
1648 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1649 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1651 NTSTATUS status;
1652 DWORD total_size;
1653 char buffer[256], *buf_ptr = buffer;
1654 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1655 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1657 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1658 hkey, index, value, val_count, reserved, type, data, count );
1660 /* NT only checks count, not val_count */
1661 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1662 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1664 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1665 if (data) total_size += *count;
1666 total_size = min( sizeof(buffer), total_size );
1668 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1669 buffer, total_size, &total_size );
1670 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1672 if (value || data)
1674 /* retry with a dynamically allocated buffer */
1675 while (status == STATUS_BUFFER_OVERFLOW)
1677 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1678 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1679 return ERROR_NOT_ENOUGH_MEMORY;
1680 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1681 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1682 buf_ptr, total_size, &total_size );
1685 if (status) goto done;
1687 if (value)
1689 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1691 status = STATUS_BUFFER_OVERFLOW;
1692 goto overflow;
1694 memcpy( value, info->Name, info->NameLength );
1695 *val_count = info->NameLength / sizeof(WCHAR);
1696 value[*val_count] = 0;
1699 if (data)
1701 if (total_size - info->DataOffset > *count)
1703 status = STATUS_BUFFER_OVERFLOW;
1704 goto overflow;
1706 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1707 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1709 /* if the type is REG_SZ and data is not 0-terminated
1710 * and there is enough space in the buffer NT appends a \0 */
1711 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1712 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1716 else status = STATUS_SUCCESS;
1718 overflow:
1719 if (type) *type = info->Type;
1720 if (count) *count = info->DataLength;
1722 done:
1723 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1724 return RtlNtStatusToDosError(status);
1728 /******************************************************************************
1729 * RegEnumValueA [ADVAPI32.@]
1731 * See RegEnumValueW.
1733 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1734 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1736 NTSTATUS status;
1737 DWORD total_size;
1738 char buffer[256], *buf_ptr = buffer;
1739 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1740 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1742 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1743 hkey, index, value, val_count, reserved, type, data, count );
1745 /* NT only checks count, not val_count */
1746 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1747 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1749 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1750 if (data) total_size += *count;
1751 total_size = min( sizeof(buffer), total_size );
1753 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1754 buffer, total_size, &total_size );
1755 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1757 /* we need to fetch the contents for a string type even if not requested,
1758 * because we need to compute the length of the ASCII string. */
1759 if (value || data || is_string(info->Type))
1761 /* retry with a dynamically allocated buffer */
1762 while (status == STATUS_BUFFER_OVERFLOW)
1764 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1765 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1766 return ERROR_NOT_ENOUGH_MEMORY;
1767 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1768 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1769 buf_ptr, total_size, &total_size );
1772 if (status) goto done;
1774 if (is_string(info->Type))
1776 DWORD len;
1777 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1778 total_size - info->DataOffset );
1779 if (data && len)
1781 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1782 else
1784 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1785 total_size - info->DataOffset );
1786 /* if the type is REG_SZ and data is not 0-terminated
1787 * and there is enough space in the buffer NT appends a \0 */
1788 if (len < *count && data[len-1]) data[len] = 0;
1791 info->DataLength = len;
1793 else if (data)
1795 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1796 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1799 if (value && !status)
1801 DWORD len;
1803 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1804 if (len >= *val_count)
1806 status = STATUS_BUFFER_OVERFLOW;
1807 if (*val_count)
1809 len = *val_count - 1;
1810 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1811 value[len] = 0;
1814 else
1816 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1817 value[len] = 0;
1818 *val_count = len;
1822 else status = STATUS_SUCCESS;
1824 if (type) *type = info->Type;
1825 if (count) *count = info->DataLength;
1827 done:
1828 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1829 return RtlNtStatusToDosError(status);
1834 /******************************************************************************
1835 * RegDeleteValueW [ADVAPI32.@]
1837 * See RegDeleteValueA.
1839 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1841 UNICODE_STRING nameW;
1843 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1845 RtlInitUnicodeString( &nameW, name );
1846 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1850 /******************************************************************************
1851 * RegDeleteValueA [ADVAPI32.@]
1853 * Delete a value from the registry.
1855 * PARAMS
1856 * hkey [I] Registry handle of the key holding the value
1857 * name [I] Name of the value under hkey to delete
1859 * RETURNS
1860 * Success: ERROR_SUCCESS
1861 * Failure: nonzero error code from Winerror.h
1863 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1865 STRING nameA;
1866 NTSTATUS status;
1868 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1870 RtlInitAnsiString( &nameA, name );
1871 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1872 &nameA, FALSE )))
1873 status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1874 return RtlNtStatusToDosError( status );
1878 /******************************************************************************
1879 * RegLoadKeyW [ADVAPI32.@]
1881 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1882 * registration information from a specified file into that subkey.
1884 * PARAMS
1885 * hkey [I] Handle of open key
1886 * subkey [I] Address of name of subkey
1887 * filename [I] Address of filename for registry information
1889 * RETURNS
1890 * Success: ERROR_SUCCESS
1891 * Failure: nonzero error code from Winerror.h
1893 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1895 OBJECT_ATTRIBUTES destkey, file;
1896 UNICODE_STRING subkeyW, filenameW;
1897 NTSTATUS status;
1899 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
1901 destkey.Length = sizeof(destkey);
1902 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
1903 destkey.ObjectName = &subkeyW; /* name of the key */
1904 destkey.Attributes = 0;
1905 destkey.SecurityDescriptor = NULL;
1906 destkey.SecurityQualityOfService = NULL;
1907 RtlInitUnicodeString(&subkeyW, subkey);
1909 file.Length = sizeof(file);
1910 file.RootDirectory = NULL;
1911 file.ObjectName = &filenameW; /* file containing the hive */
1912 file.Attributes = OBJ_CASE_INSENSITIVE;
1913 file.SecurityDescriptor = NULL;
1914 file.SecurityQualityOfService = NULL;
1915 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
1917 status = NtLoadKey(&destkey, &file);
1918 RtlFreeUnicodeString(&filenameW);
1919 return RtlNtStatusToDosError( status );
1923 /******************************************************************************
1924 * RegLoadKeyA [ADVAPI32.@]
1926 * See RegLoadKeyW.
1928 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1930 UNICODE_STRING subkeyW, filenameW;
1931 STRING subkeyA, filenameA;
1932 NTSTATUS status;
1933 LONG ret;
1935 RtlInitAnsiString(&subkeyA, subkey);
1936 RtlInitAnsiString(&filenameA, filename);
1938 RtlInitUnicodeString(&subkeyW, NULL);
1939 RtlInitUnicodeString(&filenameW, NULL);
1940 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
1941 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
1943 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
1945 else ret = RtlNtStatusToDosError(status);
1946 RtlFreeUnicodeString(&subkeyW);
1947 RtlFreeUnicodeString(&filenameW);
1948 return ret;
1952 /******************************************************************************
1953 * RegSaveKeyW [ADVAPI32.@]
1955 * Save a key and all of its subkeys and values to a new file in the standard format.
1957 * PARAMS
1958 * hkey [I] Handle of key where save begins
1959 * lpFile [I] Address of filename to save to
1960 * sa [I] Address of security structure
1962 * RETURNS
1963 * Success: ERROR_SUCCESS
1964 * Failure: nonzero error code from Winerror.h
1966 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1968 static const WCHAR format[] =
1969 {'r','e','g','%','0','4','x','.','t','m','p',0};
1970 WCHAR buffer[MAX_PATH];
1971 int count = 0;
1972 LPWSTR nameW;
1973 DWORD ret, err;
1974 HANDLE handle;
1976 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
1978 if (!file || !*file) return ERROR_INVALID_PARAMETER;
1979 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1981 err = GetLastError();
1982 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
1984 for (;;)
1986 snprintfW( nameW, 16, format, count++ );
1987 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1988 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1989 if (handle != INVALID_HANDLE_VALUE) break;
1990 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
1992 /* Something gone haywire ? Please report if this happens abnormally */
1993 if (count >= 100)
1994 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);
1997 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
1999 CloseHandle( handle );
2000 if (!ret)
2002 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2004 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2005 debugstr_w(file) );
2006 ret = GetLastError();
2009 if (ret) DeleteFileW( buffer );
2011 done:
2012 SetLastError( err ); /* restore last error code */
2013 return ret;
2017 /******************************************************************************
2018 * RegSaveKeyA [ADVAPI32.@]
2020 * See RegSaveKeyW.
2022 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2024 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2025 NTSTATUS status;
2026 STRING fileA;
2028 RtlInitAnsiString(&fileA, file);
2029 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2030 return RtlNtStatusToDosError( status );
2031 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2035 /******************************************************************************
2036 * RegRestoreKeyW [ADVAPI32.@]
2038 * Read the registry information from a file and copy it over a key.
2040 * PARAMS
2041 * hkey [I] Handle of key where restore begins
2042 * lpFile [I] Address of filename containing saved tree
2043 * dwFlags [I] Optional flags
2045 * RETURNS
2046 * Success: ERROR_SUCCESS
2047 * Failure: nonzero error code from Winerror.h
2049 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2051 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2053 /* It seems to do this check before the hkey check */
2054 if (!lpFile || !*lpFile)
2055 return ERROR_INVALID_PARAMETER;
2057 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2059 /* Check for file existence */
2061 return ERROR_SUCCESS;
2065 /******************************************************************************
2066 * RegRestoreKeyA [ADVAPI32.@]
2068 * See RegRestoreKeyW.
2070 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2072 UNICODE_STRING lpFileW;
2073 LONG ret;
2075 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2076 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2077 RtlFreeUnicodeString( &lpFileW );
2078 return ret;
2082 /******************************************************************************
2083 * RegUnLoadKeyW [ADVAPI32.@]
2085 * Unload a registry key and its subkeys from the registry.
2087 * PARAMS
2088 * hkey [I] Handle of open key
2089 * lpSubKey [I] Address of name of subkey to unload
2091 * RETURNS
2092 * Success: ERROR_SUCCESS
2093 * Failure: nonzero error code from Winerror.h
2095 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2097 DWORD ret;
2098 HKEY shkey;
2099 OBJECT_ATTRIBUTES attr;
2100 UNICODE_STRING subkey;
2102 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2104 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2105 if( ret )
2106 return ERROR_INVALID_PARAMETER;
2108 RtlInitUnicodeString(&subkey, lpSubKey);
2109 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2110 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2112 RegCloseKey(shkey);
2114 return ret;
2118 /******************************************************************************
2119 * RegUnLoadKeyA [ADVAPI32.@]
2121 * See RegUnLoadKeyW.
2123 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2125 UNICODE_STRING lpSubKeyW;
2126 LONG ret;
2128 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2129 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2130 RtlFreeUnicodeString( &lpSubKeyW );
2131 return ret;
2135 /******************************************************************************
2136 * RegReplaceKeyW [ADVAPI32.@]
2138 * Replace the file backing a registry key and all its subkeys with another file.
2140 * PARAMS
2141 * hkey [I] Handle of open key
2142 * lpSubKey [I] Address of name of subkey
2143 * lpNewFile [I] Address of filename for file with new data
2144 * lpOldFile [I] Address of filename for backup file
2146 * RETURNS
2147 * Success: ERROR_SUCCESS
2148 * Failure: nonzero error code from Winerror.h
2150 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2151 LPCWSTR lpOldFile )
2153 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2154 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2155 return ERROR_SUCCESS;
2159 /******************************************************************************
2160 * RegReplaceKeyA [ADVAPI32.@]
2162 * See RegReplaceKeyW.
2164 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2165 LPCSTR lpOldFile )
2167 UNICODE_STRING lpSubKeyW;
2168 UNICODE_STRING lpNewFileW;
2169 UNICODE_STRING lpOldFileW;
2170 LONG ret;
2172 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2173 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2174 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2175 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2176 RtlFreeUnicodeString( &lpOldFileW );
2177 RtlFreeUnicodeString( &lpNewFileW );
2178 RtlFreeUnicodeString( &lpSubKeyW );
2179 return ret;
2183 /******************************************************************************
2184 * RegSetKeySecurity [ADVAPI32.@]
2186 * Set the security of an open registry key.
2188 * PARAMS
2189 * hkey [I] Open handle of key to set
2190 * SecurityInfo [I] Descriptor contents
2191 * pSecurityDesc [I] Address of descriptor for key
2193 * RETURNS
2194 * Success: ERROR_SUCCESS
2195 * Failure: nonzero error code from Winerror.h
2197 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2198 PSECURITY_DESCRIPTOR pSecurityDesc )
2200 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2202 /* It seems to perform this check before the hkey check */
2203 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2204 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2205 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2206 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2207 /* Param OK */
2208 } else
2209 return ERROR_INVALID_PARAMETER;
2211 if (!pSecurityDesc)
2212 return ERROR_INVALID_PARAMETER;
2214 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2216 return ERROR_SUCCESS;
2220 /******************************************************************************
2221 * RegGetKeySecurity [ADVAPI32.@]
2223 * Get a copy of the security descriptor for a given registry key.
2225 * PARAMS
2226 * hkey [I] Open handle of key to set
2227 * SecurityInformation [I] Descriptor contents
2228 * pSecurityDescriptor [O] Address of descriptor for key
2229 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2231 * RETURNS
2232 * Success: ERROR_SUCCESS
2233 * Failure: Error code
2235 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2236 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2237 LPDWORD lpcbSecurityDescriptor )
2239 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2240 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
2242 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2244 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2245 SecurityInformation, pSecurityDescriptor,
2246 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2250 /******************************************************************************
2251 * RegFlushKey [ADVAPI32.@]
2253 * Immediately write a registry key to registry.
2255 * PARAMS
2256 * hkey [I] Handle of key to write
2258 * RETURNS
2259 * Success: ERROR_SUCCESS
2260 * Failure: Error code
2262 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2264 hkey = get_special_root_hkey( hkey );
2265 if (!hkey) return ERROR_INVALID_HANDLE;
2267 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2271 /******************************************************************************
2272 * RegConnectRegistryW [ADVAPI32.@]
2274 * Establish a connection to a predefined registry key on another computer.
2276 * PARAMS
2277 * lpMachineName [I] Address of name of remote computer
2278 * hHey [I] Predefined registry handle
2279 * phkResult [I] Address of buffer for remote registry handle
2281 * RETURNS
2282 * Success: ERROR_SUCCESS
2283 * Failure: nonzero error code from Winerror.h
2285 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2286 PHKEY phkResult )
2288 LONG ret;
2290 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2292 if (!lpMachineName || !*lpMachineName) {
2293 /* Use the local machine name */
2294 ret = RegOpenKeyW( hKey, NULL, phkResult );
2296 else {
2297 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2298 DWORD len = sizeof(compName) / sizeof(WCHAR);
2300 /* MSDN says lpMachineName must start with \\ : not so */
2301 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2302 lpMachineName += 2;
2303 if (GetComputerNameW(compName, &len))
2305 if (!strcmpiW(lpMachineName, compName))
2306 ret = RegOpenKeyW(hKey, NULL, phkResult);
2307 else
2309 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2310 ret = ERROR_BAD_NETPATH;
2313 else
2314 ret = GetLastError();
2316 return ret;
2320 /******************************************************************************
2321 * RegConnectRegistryA [ADVAPI32.@]
2323 * See RegConnectRegistryW.
2325 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2327 UNICODE_STRING machineW;
2328 LONG ret;
2330 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2331 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2332 RtlFreeUnicodeString( &machineW );
2333 return ret;
2337 /******************************************************************************
2338 * RegNotifyChangeKeyValue [ADVAPI32.@]
2340 * Notify the caller about changes to the attributes or contents of a registry key.
2342 * PARAMS
2343 * hkey [I] Handle of key to watch
2344 * fWatchSubTree [I] Flag for subkey notification
2345 * fdwNotifyFilter [I] Changes to be reported
2346 * hEvent [I] Handle of signaled event
2347 * fAsync [I] Flag for asynchronous reporting
2349 * RETURNS
2350 * Success: ERROR_SUCCESS
2351 * Failure: nonzero error code from Winerror.h
2353 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2354 DWORD fdwNotifyFilter, HANDLE hEvent,
2355 BOOL fAsync )
2357 NTSTATUS status;
2358 IO_STATUS_BLOCK iosb;
2360 hkey = get_special_root_hkey( hkey );
2361 if (!hkey) return ERROR_INVALID_HANDLE;
2363 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2364 hEvent, fAsync);
2366 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2367 fdwNotifyFilter, fAsync, NULL, 0,
2368 fWatchSubTree);
2370 if (status && status != STATUS_TIMEOUT)
2371 return RtlNtStatusToDosError( status );
2373 return ERROR_SUCCESS;
2376 /******************************************************************************
2377 * RegOpenUserClassesRoot [ADVAPI32.@]
2379 * Open the HKEY_CLASSES_ROOT key for a user.
2381 * PARAMS
2382 * hToken [I] Handle of token representing the user
2383 * dwOptions [I] Reserved, must be 0
2384 * samDesired [I] Desired access rights
2385 * phkResult [O] Destination for the resulting key handle
2387 * RETURNS
2388 * Success: ERROR_SUCCESS
2389 * Failure: nonzero error code from Winerror.h
2391 * NOTES
2392 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2393 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2394 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2396 LSTATUS WINAPI RegOpenUserClassesRoot(
2397 HANDLE hToken,
2398 DWORD dwOptions,
2399 REGSAM samDesired,
2400 PHKEY phkResult
2403 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2405 *phkResult = HKEY_CLASSES_ROOT;
2406 return ERROR_SUCCESS;
2409 /******************************************************************************
2410 * load_string [Internal]
2412 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2413 * avoid importing user32, which is higher level than advapi32. Helper for
2414 * RegLoadMUIString.
2416 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2418 HGLOBAL hMemory;
2419 HRSRC hResource;
2420 WCHAR *pString;
2421 int idxString;
2423 /* Negative values have to be inverted. */
2424 if (HIWORD(resId) == 0xffff)
2425 resId = (UINT)(-((INT)resId));
2427 /* Load the resource into memory and get a pointer to it. */
2428 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2429 if (!hResource) return 0;
2430 hMemory = LoadResource(hModule, hResource);
2431 if (!hMemory) return 0;
2432 pString = LockResource(hMemory);
2434 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2435 idxString = resId & 0xf;
2436 while (idxString--) pString += *pString + 1;
2438 /* If no buffer is given, return length of the string. */
2439 if (!pwszBuffer) return *pString;
2441 /* Else copy over the string, respecting the buffer size. */
2442 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2443 if (cMaxChars >= 0) {
2444 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2445 pwszBuffer[cMaxChars] = '\0';
2448 return cMaxChars;
2451 /******************************************************************************
2452 * RegLoadMUIStringW [ADVAPI32.@]
2454 * Load the localized version of a string resource from some PE, respective
2455 * id and path of which are given in the registry value in the format
2456 * @[path]\dllname,-resourceId
2458 * PARAMS
2459 * hKey [I] Key, of which to load the string value from.
2460 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2461 * pszBuffer [O] Buffer to store the localized string in.
2462 * cbBuffer [I] Size of the destination buffer in bytes.
2463 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2464 * dwFlags [I] None supported yet.
2465 * pszBaseDir [I] Not supported yet.
2467 * RETURNS
2468 * Success: ERROR_SUCCESS,
2469 * Failure: nonzero error code from winerror.h
2471 * NOTES
2472 * This is an API of Windows Vista, which wasn't available at the time this code
2473 * was written. We have to check for the correct behaviour once it's available.
2475 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2476 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2478 DWORD dwValueType, cbData;
2479 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2480 LONG result;
2482 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2483 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2484 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2486 /* Parameter sanity checks. */
2487 if (!hKey || !pwszBuffer)
2488 return ERROR_INVALID_PARAMETER;
2490 if (pwszBaseDir && *pwszBaseDir) {
2491 FIXME("BaseDir parameter not yet supported!\n");
2492 return ERROR_INVALID_PARAMETER;
2495 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2496 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2497 if (result != ERROR_SUCCESS) goto cleanup;
2498 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2499 result = ERROR_FILE_NOT_FOUND;
2500 goto cleanup;
2502 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2503 if (!pwszTempBuffer) {
2504 result = ERROR_NOT_ENOUGH_MEMORY;
2505 goto cleanup;
2507 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2508 if (result != ERROR_SUCCESS) goto cleanup;
2510 /* Expand environment variables, if appropriate, or copy the original string over. */
2511 if (dwValueType == REG_EXPAND_SZ) {
2512 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2513 if (!cbData) goto cleanup;
2514 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2515 if (!pwszExpandedBuffer) {
2516 result = ERROR_NOT_ENOUGH_MEMORY;
2517 goto cleanup;
2519 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2520 } else {
2521 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2522 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2525 /* If the value references a resource based string, parse the value and load the string.
2526 * Else just copy over the original value. */
2527 result = ERROR_SUCCESS;
2528 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2529 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2530 } else {
2531 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2532 UINT uiStringId;
2533 HMODULE hModule;
2535 /* Format of the expanded value is 'path_to_dll,-resId' */
2536 if (!pComma || pComma[1] != '-') {
2537 result = ERROR_BADKEY;
2538 goto cleanup;
2541 uiStringId = atoiW(pComma+2);
2542 *pComma = '\0';
2544 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2545 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2546 result = ERROR_BADKEY;
2547 FreeLibrary(hModule);
2550 cleanup:
2551 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2552 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2553 return result;
2556 /******************************************************************************
2557 * RegLoadMUIStringA [ADVAPI32.@]
2559 * See RegLoadMUIStringW
2561 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2562 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2564 UNICODE_STRING valueW, baseDirW;
2565 WCHAR *pwszBuffer;
2566 DWORD cbData = cbBuffer * sizeof(WCHAR);
2567 LONG result;
2569 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2570 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2571 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2572 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2574 result = ERROR_NOT_ENOUGH_MEMORY;
2575 goto cleanup;
2578 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2579 baseDirW.Buffer);
2581 if (result == ERROR_SUCCESS) {
2582 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2583 if (pcbData)
2584 *pcbData = cbData;
2587 cleanup:
2588 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2589 RtlFreeUnicodeString(&baseDirW);
2590 RtlFreeUnicodeString(&valueW);
2592 return result;
2595 /******************************************************************************
2596 * RegDisablePredefinedCache [ADVAPI32.@]
2598 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2600 * PARAMS
2601 * None.
2603 * RETURNS
2604 * Success: ERROR_SUCCESS
2605 * Failure: nonzero error code from Winerror.h
2607 * NOTES
2608 * This is useful for services that use impersonation.
2610 LSTATUS WINAPI RegDisablePredefinedCache(void)
2612 HKEY hkey_current_user;
2613 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2615 /* prevent caching of future requests */
2616 hkcu_cache_disabled = TRUE;
2618 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2620 if (hkey_current_user)
2621 NtClose( hkey_current_user );
2623 return ERROR_SUCCESS;
2626 /******************************************************************************
2627 * RegDeleteTreeW [ADVAPI32.@]
2630 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2632 LONG ret;
2633 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2634 DWORD dwMaxLen, dwSize;
2635 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2636 HKEY hSubKey = hKey;
2638 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2640 if(lpszSubKey)
2642 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2643 if (ret) return ret;
2646 /* Get highest length for keys, values */
2647 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2648 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2649 if (ret) goto cleanup;
2651 dwMaxSubkeyLen++;
2652 dwMaxValueLen++;
2653 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2654 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2656 /* Name too big: alloc a buffer for it */
2657 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2659 ret = ERROR_NOT_ENOUGH_MEMORY;
2660 goto cleanup;
2665 /* Recursively delete all the subkeys */
2666 while (TRUE)
2668 dwSize = dwMaxLen;
2669 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2670 NULL, NULL, NULL)) break;
2672 ret = RegDeleteTreeW(hSubKey, lpszName);
2673 if (ret) goto cleanup;
2676 if (lpszSubKey)
2677 ret = RegDeleteKeyW(hKey, lpszSubKey);
2678 else
2679 while (TRUE)
2681 dwSize = dwMaxLen;
2682 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2683 NULL, NULL, NULL, NULL)) break;
2685 ret = RegDeleteValueW(hKey, lpszName);
2686 if (ret) goto cleanup;
2689 cleanup:
2690 /* Free buffer if allocated */
2691 if (lpszName != szNameBuf)
2692 HeapFree( GetProcessHeap(), 0, lpszName);
2693 if(lpszSubKey)
2694 RegCloseKey(hSubKey);
2695 return ret;
2698 /******************************************************************************
2699 * RegDeleteTreeA [ADVAPI32.@]
2702 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2704 LONG ret;
2705 UNICODE_STRING lpszSubKeyW;
2707 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2708 else lpszSubKeyW.Buffer = NULL;
2709 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2710 RtlFreeUnicodeString( &lpszSubKeyW );
2711 return ret;