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
31 #define WIN32_NO_STATUS
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
[] =
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
] =
73 NULL
, /* HKEY_CURRENT_USER is determined dynamically */
76 name_PERFORMANCE_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
;
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
;
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
);
126 /* create one of the HKEY_* special root keys */
127 static HKEY
create_special_root_hkey( HKEY hkey
, DWORD access
)
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
)
143 OBJECT_ATTRIBUTES attr
;
146 attr
.Length
= sizeof(attr
);
147 attr
.RootDirectory
= 0;
148 attr
.ObjectName
= &name
;
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 )))
160 NtClose( hkey
); /* somebody beat us to it */
164 /* map the hkey from special root to normal key if necessary */
165 static inline HKEY
get_special_root_hkey( HKEY 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
);
178 /******************************************************************************
179 * RegOverridePredefKey [ADVAPI32.@]
181 LSTATUS WINAPI
RegOverridePredefKey( HKEY hkey
, HKEY override
)
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
;
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
;
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.
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
250 * Success: ERROR_SUCCESS.
251 * Failure: A standard Win32 error code. retkey remains untouched.
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
;
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
;
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
,
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.
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.
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.@]
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.@]
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
;
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.
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
373 * Success: ERROR_SUCCESS
374 * Failure: A standard Win32 error code. retkey is set to 0.
377 * Unlike RegCreateKeyExA(), this function will not create the key if it
380 LSTATUS WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD options
, REGSAM access
, PHKEY retkey
)
382 OBJECT_ATTRIBUTES attr
;
386 if (!is_version_nt()) access
= MAXIMUM_ALLOWED
; /* Win95 ignores the access mask */
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
;
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
,
407 status
= NtOpenKey( (PHANDLE
)retkey
, access
, &attr
);
409 return RtlNtStatusToDosError( status
);
413 /******************************************************************************
414 * RegOpenKeyW [ADVAPI32.@]
418 LSTATUS WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, PHKEY retkey
)
421 return ERROR_INVALID_PARAMETER
;
426 return ERROR_SUCCESS
;
428 return RegOpenKeyExW( hkey
, name
, 0, MAXIMUM_ALLOWED
, retkey
);
432 /******************************************************************************
433 * RegOpenKeyA [ADVAPI32.@]
435 * Open a registry key.
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
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
)
449 return ERROR_INVALID_PARAMETER
;
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.
467 * access [I] Desired access rights to the key
468 * retkey [O] Handle to the opened key
471 * Success: ERROR_SUCCESS
472 * Failure: nonzero error code from Winerror.h
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.
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
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
)
511 char buffer
[256], *buf_ptr
= buffer
;
512 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
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
);
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
;
547 memcpy( name
, info
->Name
, info
->NameLength
);
551 *class_len
= cls_len
;
554 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
561 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
562 return RtlNtStatusToDosError( status
);
566 /******************************************************************************
567 * RegEnumKeyExA [ADVAPI32.@]
571 LSTATUS WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
572 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
575 char buffer
[256], *buf_ptr
= buffer
;
576 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
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
);
603 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
604 RtlUnicodeToMultiByteSize( &cls_len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
606 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
608 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
609 status
= STATUS_BUFFER_OVERFLOW
;
613 RtlUnicodeToMultiByteN( name
, len
, NULL
, info
->Name
, info
->NameLength
);
617 *class_len
= cls_len
;
620 RtlUnicodeToMultiByteN( class, cls_len
, NULL
,
621 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
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.
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.
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.@]
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.
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
687 * Success: ERROR_SUCCESS
688 * Failure: system error code.
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
)
702 char buffer
[256], *buf_ptr
= buffer
;
703 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
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
;
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
;
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
;
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.
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.
769 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
770 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
773 LSTATUS WINAPI
RegQueryMultipleValuesA( HKEY hkey
, PVALENTA val_list
, DWORD num_vals
,
774 LPSTR lpValueBuf
, LPDWORD ldwTotsize
)
777 DWORD maxBytes
= *ldwTotsize
;
779 LPSTR bufptr
= lpValueBuf
;
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
)
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
)
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
)
823 DWORD maxBytes
= *ldwTotsize
;
825 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
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
)
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
)
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.
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
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.
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
)
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
);
918 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
921 if (class && !status
)
923 RtlUnicodeToMultiByteN( class, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
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
;
939 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
940 return RtlNtStatusToDosError( status
);
944 /******************************************************************************
945 * RegCloseKey [ADVAPI32.@]
947 * Close an open registry key.
950 * hkey [I] Handle of key to close
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
)
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
) );
982 TRACE("%s ret=%08x\n", debugstr_w(name
), ret
);
987 /******************************************************************************
988 * RegDeleteKeyW [ADVAPI32.@]
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
)
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 */
1023 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
1026 TRACE("%s ret=%08x\n", debugstr_a(name
), ret
);
1031 /******************************************************************************
1032 * RegDeleteKeyA [ADVAPI32.@]
1034 * Delete a registry key.
1037 * hkey [I] Handle to parent key containing the key to delete
1038 * name [I] Name of the key user hkey to delete
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.
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.
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
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.
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
)
1106 UNICODE_STRING nameW
;
1107 WCHAR
*dataW
= NULL
;
1110 if (!is_version_nt()) /* win95 */
1114 if (!data
) return ERROR_INVALID_PARAMETER
;
1115 count
= strlen((const char *)data
) + 1;
1118 else if (count
&& is_string(type
))
1120 /* if user forgot to count terminating null, add it (yes NT does this) */
1121 if (data
[count
-1] && !data
[count
]) count
++;
1124 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1126 if (is_string( type
)) /* need to convert to Unicode */
1129 RtlMultiByteToUnicodeSize( &lenW
, (const char *)data
, count
);
1130 if (!(dataW
= HeapAlloc( GetProcessHeap(), 0, lenW
))) return ERROR_OUTOFMEMORY
;
1131 RtlMultiByteToUnicodeN( dataW
, lenW
, NULL
, (const char *)data
, count
);
1133 data
= (BYTE
*)dataW
;
1136 RtlInitAnsiString( &nameA
, name
);
1137 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1139 status
= NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
);
1140 RtlFreeUnicodeString( &nameW
);
1142 HeapFree( GetProcessHeap(), 0, dataW
);
1143 return RtlNtStatusToDosError( status
);
1147 /******************************************************************************
1148 * RegSetValueW [ADVAPI32.@]
1150 * Sets the data for the default or unnamed value of a reg key.
1153 * hKey [I] Handle to an open key.
1154 * lpSubKey [I] Name of a subkey of hKey.
1155 * dwType [I] Type of information to store.
1156 * lpData [I] String that contains the data to set for the default value.
1157 * cbData [I] Ignored.
1160 * Success: ERROR_SUCCESS
1161 * Failure: nonzero error code from Winerror.h
1163 LSTATUS WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR name
, DWORD type
, LPCWSTR data
, DWORD count
)
1168 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_w(name
), type
, debugstr_w(data
), count
);
1170 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1172 if (name
&& name
[0]) /* need to create the subkey */
1174 if ((ret
= RegCreateKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1177 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)data
,
1178 (strlenW( data
) + 1) * sizeof(WCHAR
) );
1179 if (subkey
!= hkey
) RegCloseKey( subkey
);
1184 /******************************************************************************
1185 * RegSetValueA [ADVAPI32.@]
1189 LSTATUS WINAPI
RegSetValueA( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1194 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_a(name
), type
, debugstr_a(data
), count
);
1196 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1198 if (name
&& name
[0]) /* need to create the subkey */
1200 if ((ret
= RegCreateKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1202 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)data
, strlen(data
)+1 );
1203 if (subkey
!= hkey
) RegCloseKey( subkey
);
1209 /******************************************************************************
1210 * RegQueryValueExW [ADVAPI32.@]
1212 * See RegQueryValueExA.
1214 LSTATUS WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
1215 LPBYTE data
, LPDWORD count
)
1218 UNICODE_STRING name_str
;
1220 char buffer
[256], *buf_ptr
= buffer
;
1221 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1222 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1224 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1225 hkey
, debugstr_w(name
), reserved
, type
, data
, count
,
1226 (count
&& data
) ? *count
: 0 );
1228 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1229 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1231 RtlInitUnicodeString( &name_str
, name
);
1233 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
1236 total_size
= info_size
;
1237 if (count
) *count
= 0;
1240 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1241 buffer
, total_size
, &total_size
);
1242 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1246 /* retry with a dynamically allocated buffer */
1247 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
1249 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1250 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1251 return ERROR_NOT_ENOUGH_MEMORY
;
1252 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1253 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1254 buf_ptr
, total_size
, &total_size
);
1259 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1260 /* if the type is REG_SZ and data is not 0-terminated
1261 * and there is enough space in the buffer NT appends a \0 */
1262 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1264 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
1265 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1268 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1270 else status
= STATUS_SUCCESS
;
1272 if (type
) *type
= info
->Type
;
1273 if (count
) *count
= total_size
- info_size
;
1276 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1277 return RtlNtStatusToDosError(status
);
1281 /******************************************************************************
1282 * RegQueryValueExA [ADVAPI32.@]
1284 * Get the type and contents of a specified value under with a key.
1287 * hkey [I] Handle of the key to query
1288 * name [I] Name of value under hkey to query
1289 * reserved [I] Reserved - must be NULL
1290 * type [O] Destination for the value type, or NULL if not required
1291 * data [O] Destination for the values contents, or NULL if not required
1292 * count [I/O] Size of data, updated with the number of bytes returned
1295 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1296 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1297 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1298 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1301 * MSDN states that if data is too small it is partially filled. In reality
1302 * it remains untouched.
1304 LSTATUS WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1305 LPBYTE data
, LPDWORD count
)
1309 UNICODE_STRING nameW
;
1310 DWORD total_size
, datalen
= 0;
1311 char buffer
[256], *buf_ptr
= buffer
;
1312 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1313 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1315 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1316 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
1318 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1319 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1321 if (count
) datalen
= *count
;
1322 if (!data
&& count
) *count
= 0;
1324 /* this matches Win9x behaviour - NT sets *type to a random value */
1325 if (type
) *type
= REG_NONE
;
1327 RtlInitAnsiString( &nameA
, name
);
1328 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1329 return RtlNtStatusToDosError(status
);
1331 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1332 buffer
, sizeof(buffer
), &total_size
);
1333 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1335 /* we need to fetch the contents for a string type even if not requested,
1336 * because we need to compute the length of the ASCII string. */
1337 if (data
|| is_string(info
->Type
))
1339 /* retry with a dynamically allocated buffer */
1340 while (status
== STATUS_BUFFER_OVERFLOW
)
1342 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1343 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1345 status
= STATUS_NO_MEMORY
;
1348 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1349 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1350 buf_ptr
, total_size
, &total_size
);
1353 if (status
) goto done
;
1355 if (is_string(info
->Type
))
1359 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
1360 total_size
- info_size
);
1363 if (len
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1366 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
1367 total_size
- info_size
);
1368 /* if the type is REG_SZ and data is not 0-terminated
1369 * and there is enough space in the buffer NT appends a \0 */
1370 if (len
< datalen
&& data
[len
-1]) data
[len
] = 0;
1373 total_size
= len
+ info_size
;
1377 if (total_size
- info_size
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1378 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1381 else status
= STATUS_SUCCESS
;
1383 if (type
) *type
= info
->Type
;
1384 if (count
) *count
= total_size
- info_size
;
1387 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1388 RtlFreeUnicodeString( &nameW
);
1389 return RtlNtStatusToDosError(status
);
1393 /******************************************************************************
1394 * RegQueryValueW [ADVAPI32.@]
1396 * Retrieves the data associated with the default or unnamed value of a key.
1399 * hkey [I] Handle to an open key.
1400 * name [I] Name of the subkey of hKey.
1401 * data [O] Receives the string associated with the default value
1403 * count [I/O] Size of lpValue in bytes.
1406 * Success: ERROR_SUCCESS
1407 * Failure: nonzero error code from Winerror.h
1409 LSTATUS WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
1414 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
1416 if (name
&& name
[0])
1418 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1420 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1421 if (subkey
!= hkey
) RegCloseKey( subkey
);
1422 if (ret
== ERROR_FILE_NOT_FOUND
)
1424 /* return empty string if default value not found */
1425 if (data
) *data
= 0;
1426 if (count
) *count
= sizeof(WCHAR
);
1427 ret
= ERROR_SUCCESS
;
1433 /******************************************************************************
1434 * RegQueryValueA [ADVAPI32.@]
1436 * See RegQueryValueW.
1438 LSTATUS WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
1443 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
1445 if (name
&& name
[0])
1447 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1449 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1450 if (subkey
!= hkey
) RegCloseKey( subkey
);
1451 if (ret
== ERROR_FILE_NOT_FOUND
)
1453 /* return empty string if default value not found */
1454 if (data
) *data
= 0;
1455 if (count
) *count
= 1;
1456 ret
= ERROR_SUCCESS
;
1462 /******************************************************************************
1463 * ADVAPI_ApplyRestrictions [internal]
1465 * Helper function for RegGetValueA/W.
1467 static VOID
ADVAPI_ApplyRestrictions( DWORD dwFlags
, DWORD dwType
,
1468 DWORD cbData
, PLONG ret
)
1470 /* Check if the type is restricted by the passed flags */
1471 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1477 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1478 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1479 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1480 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1481 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1482 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1483 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1486 if (dwFlags
& dwMask
)
1488 /* Type is not restricted, check for size mismatch */
1489 if (dwType
== REG_BINARY
)
1493 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
1495 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
1498 if (cbExpect
&& cbData
!= cbExpect
)
1499 *ret
= ERROR_DATATYPE_MISMATCH
;
1502 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1507 /******************************************************************************
1508 * RegGetValueW [ADVAPI32.@]
1510 * Retrieves the type and data for a value name associated with a key,
1511 * optionally expanding its content and restricting its type.
1514 * hKey [I] Handle to an open key.
1515 * pszSubKey [I] Name of the subkey of hKey.
1516 * pszValue [I] Name of value under hKey/szSubKey to query.
1517 * dwFlags [I] Flags restricting the value type to retrieve.
1518 * pdwType [O] Destination for the values type, may be NULL.
1519 * pvData [O] Destination for the values content, may be NULL.
1520 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1521 * retrieve the whole content, including the trailing '\0'
1525 * Success: ERROR_SUCCESS
1526 * Failure: nonzero error code from Winerror.h
1529 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1530 * expanded and pdwType is set to REG_SZ instead.
1531 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1532 * without RRF_NOEXPAND is thus not allowed.
1533 * An exception is the case where RRF_RT_ANY is specified, because then
1534 * RRF_NOEXPAND is allowed.
1536 LSTATUS WINAPI
RegGetValueW( HKEY hKey
, LPCWSTR pszSubKey
, LPCWSTR pszValue
,
1537 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1540 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1544 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1545 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1546 pvData
, pcbData
, cbData
);
1548 if (pvData
&& !pcbData
)
1549 return ERROR_INVALID_PARAMETER
;
1550 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1551 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1552 return ERROR_INVALID_PARAMETER
;
1554 if (pszSubKey
&& pszSubKey
[0])
1556 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1557 if (ret
!= ERROR_SUCCESS
) return ret
;
1560 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1562 /* If we are going to expand we need to read in the whole the value even
1563 * if the passed buffer was too small as the expanded string might be
1564 * smaller than the unexpanded one and could fit into cbData bytes. */
1565 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1566 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1569 HeapFree(GetProcessHeap(), 0, pvBuf
);
1571 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1574 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1578 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1579 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
1580 &dwType
, pvBuf
, &cbData
);
1583 /* Even if cbData was large enough we have to copy the
1584 * string since ExpandEnvironmentStrings can't handle
1585 * overlapping buffers. */
1586 CopyMemory(pvBuf
, pvData
, cbData
);
1589 /* Both the type or the value itself could have been modified in
1590 * between so we have to keep retrying until the buffer is large
1591 * enough or we no longer have to expand the value. */
1592 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1594 if (ret
== ERROR_SUCCESS
)
1596 /* Recheck dwType in case it changed since the first call */
1597 if (dwType
== REG_EXPAND_SZ
)
1599 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
1600 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
1602 if(pvData
&& pcbData
&& cbData
> *pcbData
)
1603 ret
= ERROR_MORE_DATA
;
1606 CopyMemory(pvData
, pvBuf
, *pcbData
);
1609 HeapFree(GetProcessHeap(), 0, pvBuf
);
1612 if (pszSubKey
&& pszSubKey
[0])
1615 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1617 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1618 ZeroMemory(pvData
, *pcbData
);
1620 if (pdwType
) *pdwType
= dwType
;
1621 if (pcbData
) *pcbData
= cbData
;
1627 /******************************************************************************
1628 * RegGetValueA [ADVAPI32.@]
1632 LSTATUS WINAPI
RegGetValueA( HKEY hKey
, LPCSTR pszSubKey
, LPCSTR pszValue
,
1633 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1636 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1640 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1641 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
1644 if (pvData
&& !pcbData
)
1645 return ERROR_INVALID_PARAMETER
;
1646 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1647 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1648 return ERROR_INVALID_PARAMETER
;
1650 if (pszSubKey
&& pszSubKey
[0])
1652 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1653 if (ret
!= ERROR_SUCCESS
) return ret
;
1656 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1658 /* If we are going to expand we need to read in the whole the value even
1659 * if the passed buffer was too small as the expanded string might be
1660 * smaller than the unexpanded one and could fit into cbData bytes. */
1661 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1662 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1665 HeapFree(GetProcessHeap(), 0, pvBuf
);
1667 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1670 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1674 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1675 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
1676 &dwType
, pvBuf
, &cbData
);
1679 /* Even if cbData was large enough we have to copy the
1680 * string since ExpandEnvironmentStrings can't handle
1681 * overlapping buffers. */
1682 CopyMemory(pvBuf
, pvData
, cbData
);
1685 /* Both the type or the value itself could have been modified in
1686 * between so we have to keep retrying until the buffer is large
1687 * enough or we no longer have to expand the value. */
1688 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1690 if (ret
== ERROR_SUCCESS
)
1692 /* Recheck dwType in case it changed since the first call */
1693 if (dwType
== REG_EXPAND_SZ
)
1695 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
1696 pcbData
? *pcbData
: 0);
1698 if(pvData
&& pcbData
&& cbData
> *pcbData
)
1699 ret
= ERROR_MORE_DATA
;
1702 CopyMemory(pvData
, pvBuf
, *pcbData
);
1705 HeapFree(GetProcessHeap(), 0, pvBuf
);
1708 if (pszSubKey
&& pszSubKey
[0])
1711 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1713 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1714 ZeroMemory(pvData
, *pcbData
);
1716 if (pdwType
) *pdwType
= dwType
;
1717 if (pcbData
) *pcbData
= cbData
;
1723 /******************************************************************************
1724 * RegEnumValueW [ADVAPI32.@]
1726 * Enumerates the values for the specified open registry key.
1729 * hkey [I] Handle to key to query
1730 * index [I] Index of value to query
1731 * value [O] Value string
1732 * val_count [I/O] Size of value buffer (in wchars)
1733 * reserved [I] Reserved
1734 * type [O] Type code
1735 * data [O] Value data
1736 * count [I/O] Size of data buffer (in bytes)
1739 * Success: ERROR_SUCCESS
1740 * Failure: nonzero error code from Winerror.h
1743 LSTATUS WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
1744 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1748 char buffer
[256], *buf_ptr
= buffer
;
1749 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1750 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1752 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1753 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1755 /* NT only checks count, not val_count */
1756 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1757 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1759 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1760 if (data
) total_size
+= *count
;
1761 total_size
= min( sizeof(buffer
), total_size
);
1763 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1764 buffer
, total_size
, &total_size
);
1765 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1769 /* retry with a dynamically allocated buffer */
1770 while (status
== STATUS_BUFFER_OVERFLOW
)
1772 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1773 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1774 return ERROR_NOT_ENOUGH_MEMORY
;
1775 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1776 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1777 buf_ptr
, total_size
, &total_size
);
1780 if (status
) goto done
;
1784 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
1786 status
= STATUS_BUFFER_OVERFLOW
;
1789 memcpy( value
, info
->Name
, info
->NameLength
);
1790 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
1791 value
[*val_count
] = 0;
1796 if (total_size
- info
->DataOffset
> *count
)
1798 status
= STATUS_BUFFER_OVERFLOW
;
1801 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1802 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1804 /* if the type is REG_SZ and data is not 0-terminated
1805 * and there is enough space in the buffer NT appends a \0 */
1806 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
1807 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1811 else status
= STATUS_SUCCESS
;
1814 if (type
) *type
= info
->Type
;
1815 if (count
) *count
= info
->DataLength
;
1818 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1819 return RtlNtStatusToDosError(status
);
1823 /******************************************************************************
1824 * RegEnumValueA [ADVAPI32.@]
1826 * See RegEnumValueW.
1828 LSTATUS WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1829 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1833 char buffer
[256], *buf_ptr
= buffer
;
1834 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1835 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1837 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1838 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1840 /* NT only checks count, not val_count */
1841 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1842 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1844 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1845 if (data
) total_size
+= *count
;
1846 total_size
= min( sizeof(buffer
), total_size
);
1848 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1849 buffer
, total_size
, &total_size
);
1850 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1852 /* we need to fetch the contents for a string type even if not requested,
1853 * because we need to compute the length of the ASCII string. */
1854 if (value
|| data
|| is_string(info
->Type
))
1856 /* retry with a dynamically allocated buffer */
1857 while (status
== STATUS_BUFFER_OVERFLOW
)
1859 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1860 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1861 return ERROR_NOT_ENOUGH_MEMORY
;
1862 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1863 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1864 buf_ptr
, total_size
, &total_size
);
1867 if (status
) goto done
;
1869 if (is_string(info
->Type
))
1872 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1873 total_size
- info
->DataOffset
);
1876 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1879 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1880 total_size
- info
->DataOffset
);
1881 /* if the type is REG_SZ and data is not 0-terminated
1882 * and there is enough space in the buffer NT appends a \0 */
1883 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1886 info
->DataLength
= len
;
1890 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1891 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1894 if (value
&& !status
)
1898 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
1899 if (len
>= *val_count
)
1901 status
= STATUS_BUFFER_OVERFLOW
;
1904 len
= *val_count
- 1;
1905 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1911 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1917 else status
= STATUS_SUCCESS
;
1919 if (type
) *type
= info
->Type
;
1920 if (count
) *count
= info
->DataLength
;
1923 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1924 return RtlNtStatusToDosError(status
);
1929 /******************************************************************************
1930 * RegDeleteValueW [ADVAPI32.@]
1932 * See RegDeleteValueA.
1934 LSTATUS WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
1936 UNICODE_STRING nameW
;
1938 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1940 RtlInitUnicodeString( &nameW
, name
);
1941 return RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
1945 /******************************************************************************
1946 * RegDeleteValueA [ADVAPI32.@]
1948 * Delete a value from the registry.
1951 * hkey [I] Registry handle of the key holding the value
1952 * name [I] Name of the value under hkey to delete
1955 * Success: ERROR_SUCCESS
1956 * Failure: nonzero error code from Winerror.h
1958 LSTATUS WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
1961 UNICODE_STRING nameW
;
1964 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1966 RtlInitAnsiString( &nameA
, name
);
1967 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1969 status
= NtDeleteValueKey( hkey
, &nameW
);
1970 RtlFreeUnicodeString( &nameW
);
1972 return RtlNtStatusToDosError( status
);
1976 /******************************************************************************
1977 * RegLoadKeyW [ADVAPI32.@]
1979 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1980 * registration information from a specified file into that subkey.
1983 * hkey [I] Handle of open key
1984 * subkey [I] Address of name of subkey
1985 * filename [I] Address of filename for registry information
1988 * Success: ERROR_SUCCESS
1989 * Failure: nonzero error code from Winerror.h
1991 LSTATUS WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
1993 OBJECT_ATTRIBUTES destkey
, file
;
1994 UNICODE_STRING subkeyW
, filenameW
;
1997 if (!(hkey
= get_special_root_hkey(hkey
))) return ERROR_INVALID_HANDLE
;
1999 destkey
.Length
= sizeof(destkey
);
2000 destkey
.RootDirectory
= hkey
; /* root key: HKLM or HKU */
2001 destkey
.ObjectName
= &subkeyW
; /* name of the key */
2002 destkey
.Attributes
= 0;
2003 destkey
.SecurityDescriptor
= NULL
;
2004 destkey
.SecurityQualityOfService
= NULL
;
2005 RtlInitUnicodeString(&subkeyW
, subkey
);
2007 file
.Length
= sizeof(file
);
2008 file
.RootDirectory
= NULL
;
2009 file
.ObjectName
= &filenameW
; /* file containing the hive */
2010 file
.Attributes
= OBJ_CASE_INSENSITIVE
;
2011 file
.SecurityDescriptor
= NULL
;
2012 file
.SecurityQualityOfService
= NULL
;
2013 RtlDosPathNameToNtPathName_U(filename
, &filenameW
, NULL
, NULL
);
2015 status
= NtLoadKey(&destkey
, &file
);
2016 RtlFreeUnicodeString(&filenameW
);
2017 return RtlNtStatusToDosError( status
);
2021 /******************************************************************************
2022 * RegLoadKeyA [ADVAPI32.@]
2026 LSTATUS WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
2028 UNICODE_STRING subkeyW
, filenameW
;
2029 STRING subkeyA
, filenameA
;
2033 RtlInitAnsiString(&subkeyA
, subkey
);
2034 RtlInitAnsiString(&filenameA
, filename
);
2036 RtlInitUnicodeString(&subkeyW
, NULL
);
2037 RtlInitUnicodeString(&filenameW
, NULL
);
2038 if (!(status
= RtlAnsiStringToUnicodeString(&subkeyW
, &subkeyA
, TRUE
)) &&
2039 !(status
= RtlAnsiStringToUnicodeString(&filenameW
, &filenameA
, TRUE
)))
2041 ret
= RegLoadKeyW(hkey
, subkeyW
.Buffer
, filenameW
.Buffer
);
2043 else ret
= RtlNtStatusToDosError(status
);
2044 RtlFreeUnicodeString(&subkeyW
);
2045 RtlFreeUnicodeString(&filenameW
);
2050 /******************************************************************************
2051 * RegSaveKeyW [ADVAPI32.@]
2053 * Save a key and all of its subkeys and values to a new file in the standard format.
2056 * hkey [I] Handle of key where save begins
2057 * lpFile [I] Address of filename to save to
2058 * sa [I] Address of security structure
2061 * Success: ERROR_SUCCESS
2062 * Failure: nonzero error code from Winerror.h
2064 LSTATUS WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
2066 static const WCHAR format
[] =
2067 {'r','e','g','%','0','4','x','.','t','m','p',0};
2068 WCHAR buffer
[MAX_PATH
];
2074 TRACE( "(%p,%s,%p)\n", hkey
, debugstr_w(file
), sa
);
2076 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
2077 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
2079 err
= GetLastError();
2080 GetFullPathNameW( file
, sizeof(buffer
)/sizeof(WCHAR
), buffer
, &nameW
);
2084 snprintfW( nameW
, 16, format
, count
++ );
2085 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
2086 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
2087 if (handle
!= INVALID_HANDLE_VALUE
) break;
2088 if ((ret
= GetLastError()) != ERROR_FILE_EXISTS
) goto done
;
2090 /* Something gone haywire ? Please report if this happens abnormally */
2092 MESSAGE("Wow, we are already fiddling with a temp file %s with an ordinal as high as %d !\nYou might want to delete all corresponding temp files in that directory.\n", debugstr_w(buffer
), count
);
2095 ret
= RtlNtStatusToDosError(NtSaveKey(hkey
, handle
));
2097 CloseHandle( handle
);
2100 if (!MoveFileExW( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
2102 ERR( "Failed to move %s to %s\n", debugstr_w(buffer
),
2104 ret
= GetLastError();
2107 if (ret
) DeleteFileW( buffer
);
2110 SetLastError( err
); /* restore last error code */
2115 /******************************************************************************
2116 * RegSaveKeyA [ADVAPI32.@]
2120 LSTATUS WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
2122 UNICODE_STRING
*fileW
= &NtCurrentTeb()->StaticUnicodeString
;
2126 RtlInitAnsiString(&fileA
, file
);
2127 if ((status
= RtlAnsiStringToUnicodeString(fileW
, &fileA
, FALSE
)))
2128 return RtlNtStatusToDosError( status
);
2129 return RegSaveKeyW(hkey
, fileW
->Buffer
, sa
);
2133 /******************************************************************************
2134 * RegRestoreKeyW [ADVAPI32.@]
2136 * Read the registry information from a file and copy it over a key.
2139 * hkey [I] Handle of key where restore begins
2140 * lpFile [I] Address of filename containing saved tree
2141 * dwFlags [I] Optional flags
2144 * Success: ERROR_SUCCESS
2145 * Failure: nonzero error code from Winerror.h
2147 LSTATUS WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
2149 TRACE("(%p,%s,%d)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2151 /* It seems to do this check before the hkey check */
2152 if (!lpFile
|| !*lpFile
)
2153 return ERROR_INVALID_PARAMETER
;
2155 FIXME("(%p,%s,%d): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2157 /* Check for file existence */
2159 return ERROR_SUCCESS
;
2163 /******************************************************************************
2164 * RegRestoreKeyA [ADVAPI32.@]
2166 * See RegRestoreKeyW.
2168 LSTATUS WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
2170 UNICODE_STRING lpFileW
;
2173 RtlCreateUnicodeStringFromAsciiz( &lpFileW
, lpFile
);
2174 ret
= RegRestoreKeyW( hkey
, lpFileW
.Buffer
, dwFlags
);
2175 RtlFreeUnicodeString( &lpFileW
);
2180 /******************************************************************************
2181 * RegUnLoadKeyW [ADVAPI32.@]
2183 * Unload a registry key and its subkeys from the registry.
2186 * hkey [I] Handle of open key
2187 * lpSubKey [I] Address of name of subkey to unload
2190 * Success: ERROR_SUCCESS
2191 * Failure: nonzero error code from Winerror.h
2193 LSTATUS WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
2197 OBJECT_ATTRIBUTES attr
;
2198 UNICODE_STRING subkey
;
2200 TRACE("(%p,%s)\n",hkey
, debugstr_w(lpSubKey
));
2202 ret
= RegOpenKeyW(hkey
,lpSubKey
,&shkey
);
2204 return ERROR_INVALID_PARAMETER
;
2206 RtlInitUnicodeString(&subkey
, lpSubKey
);
2207 InitializeObjectAttributes(&attr
, &subkey
, OBJ_CASE_INSENSITIVE
, shkey
, NULL
);
2208 ret
= RtlNtStatusToDosError(NtUnloadKey(&attr
));
2216 /******************************************************************************
2217 * RegUnLoadKeyA [ADVAPI32.@]
2219 * See RegUnLoadKeyW.
2221 LSTATUS WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
2223 UNICODE_STRING lpSubKeyW
;
2226 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2227 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
.Buffer
);
2228 RtlFreeUnicodeString( &lpSubKeyW
);
2233 /******************************************************************************
2234 * RegReplaceKeyW [ADVAPI32.@]
2236 * Replace the file backing a registry key and all its subkeys with another file.
2239 * hkey [I] Handle of open key
2240 * lpSubKey [I] Address of name of subkey
2241 * lpNewFile [I] Address of filename for file with new data
2242 * lpOldFile [I] Address of filename for backup file
2245 * Success: ERROR_SUCCESS
2246 * Failure: nonzero error code from Winerror.h
2248 LSTATUS WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
2251 FIXME("(%p,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
2252 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
2253 return ERROR_SUCCESS
;
2257 /******************************************************************************
2258 * RegReplaceKeyA [ADVAPI32.@]
2260 * See RegReplaceKeyW.
2262 LSTATUS WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
2265 UNICODE_STRING lpSubKeyW
;
2266 UNICODE_STRING lpNewFileW
;
2267 UNICODE_STRING lpOldFileW
;
2270 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2271 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW
, lpOldFile
);
2272 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW
, lpNewFile
);
2273 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
.Buffer
, lpNewFileW
.Buffer
, lpOldFileW
.Buffer
);
2274 RtlFreeUnicodeString( &lpOldFileW
);
2275 RtlFreeUnicodeString( &lpNewFileW
);
2276 RtlFreeUnicodeString( &lpSubKeyW
);
2281 /******************************************************************************
2282 * RegSetKeySecurity [ADVAPI32.@]
2284 * Set the security of an open registry key.
2287 * hkey [I] Open handle of key to set
2288 * SecurityInfo [I] Descriptor contents
2289 * pSecurityDesc [I] Address of descriptor for key
2292 * Success: ERROR_SUCCESS
2293 * Failure: nonzero error code from Winerror.h
2295 LSTATUS WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
2296 PSECURITY_DESCRIPTOR pSecurityDesc
)
2298 TRACE("(%p,%d,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
2300 /* It seems to perform this check before the hkey check */
2301 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
2302 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
2303 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
2304 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
2307 return ERROR_INVALID_PARAMETER
;
2310 return ERROR_INVALID_PARAMETER
;
2312 FIXME(":(%p,%d,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
2314 return ERROR_SUCCESS
;
2318 /******************************************************************************
2319 * RegGetKeySecurity [ADVAPI32.@]
2321 * Get a copy of the security descriptor for a given registry key.
2324 * hkey [I] Open handle of key to set
2325 * SecurityInformation [I] Descriptor contents
2326 * pSecurityDescriptor [O] Address of descriptor for key
2327 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2330 * Success: ERROR_SUCCESS
2331 * Failure: Error code
2333 LSTATUS WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
2334 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2335 LPDWORD lpcbSecurityDescriptor
)
2337 TRACE("(%p,%d,%p,%d)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
2338 *lpcbSecurityDescriptor
);
2340 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
2342 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey
,
2343 SecurityInformation
, pSecurityDescriptor
,
2344 *lpcbSecurityDescriptor
, lpcbSecurityDescriptor
) );
2348 /******************************************************************************
2349 * RegFlushKey [ADVAPI32.@]
2351 * Immediately write a registry key to registry.
2354 * hkey [I] Handle of key to write
2357 * Success: ERROR_SUCCESS
2358 * Failure: Error code
2360 LSTATUS WINAPI
RegFlushKey( HKEY hkey
)
2362 hkey
= get_special_root_hkey( hkey
);
2363 if (!hkey
) return ERROR_INVALID_HANDLE
;
2365 return RtlNtStatusToDosError( NtFlushKey( hkey
) );
2369 /******************************************************************************
2370 * RegConnectRegistryW [ADVAPI32.@]
2372 * Establish a connection to a predefined registry key on another computer.
2375 * lpMachineName [I] Address of name of remote computer
2376 * hHey [I] Predefined registry handle
2377 * phkResult [I] Address of buffer for remote registry handle
2380 * Success: ERROR_SUCCESS
2381 * Failure: nonzero error code from Winerror.h
2383 LSTATUS WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
2388 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
2390 if (!lpMachineName
|| !*lpMachineName
) {
2391 /* Use the local machine name */
2392 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
2395 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
2396 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
2398 /* MSDN says lpMachineName must start with \\ : not so */
2399 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
2401 if (GetComputerNameW(compName
, &len
))
2403 if (!strcmpiW(lpMachineName
, compName
))
2404 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
2407 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
2408 ret
= ERROR_BAD_NETPATH
;
2412 ret
= GetLastError();
2418 /******************************************************************************
2419 * RegConnectRegistryA [ADVAPI32.@]
2421 * See RegConnectRegistryW.
2423 LSTATUS WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, PHKEY reskey
)
2425 UNICODE_STRING machineW
;
2428 RtlCreateUnicodeStringFromAsciiz( &machineW
, machine
);
2429 ret
= RegConnectRegistryW( machineW
.Buffer
, hkey
, reskey
);
2430 RtlFreeUnicodeString( &machineW
);
2435 /******************************************************************************
2436 * RegNotifyChangeKeyValue [ADVAPI32.@]
2438 * Notify the caller about changes to the attributes or contents of a registry key.
2441 * hkey [I] Handle of key to watch
2442 * fWatchSubTree [I] Flag for subkey notification
2443 * fdwNotifyFilter [I] Changes to be reported
2444 * hEvent [I] Handle of signaled event
2445 * fAsync [I] Flag for asynchronous reporting
2448 * Success: ERROR_SUCCESS
2449 * Failure: nonzero error code from Winerror.h
2451 LSTATUS WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
2452 DWORD fdwNotifyFilter
, HANDLE hEvent
,
2456 IO_STATUS_BLOCK iosb
;
2458 hkey
= get_special_root_hkey( hkey
);
2459 if (!hkey
) return ERROR_INVALID_HANDLE
;
2461 TRACE("(%p,%i,%d,%p,%i)\n", hkey
, fWatchSubTree
, fdwNotifyFilter
,
2464 status
= NtNotifyChangeKey( hkey
, hEvent
, NULL
, NULL
, &iosb
,
2465 fdwNotifyFilter
, fAsync
, NULL
, 0,
2468 if (status
&& status
!= STATUS_TIMEOUT
)
2469 return RtlNtStatusToDosError( status
);
2471 return ERROR_SUCCESS
;
2474 /******************************************************************************
2475 * RegOpenUserClassesRoot [ADVAPI32.@]
2477 * Open the HKEY_CLASSES_ROOT key for a user.
2480 * hToken [I] Handle of token representing the user
2481 * dwOptions [I] Reserved, must be 0
2482 * samDesired [I] Desired access rights
2483 * phkResult [O] Destination for the resulting key handle
2486 * Success: ERROR_SUCCESS
2487 * Failure: nonzero error code from Winerror.h
2490 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2491 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2492 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2494 LSTATUS WINAPI
RegOpenUserClassesRoot(
2501 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken
, dwOptions
, samDesired
, phkResult
);
2503 *phkResult
= HKEY_CLASSES_ROOT
;
2504 return ERROR_SUCCESS
;
2507 /******************************************************************************
2508 * load_string [Internal]
2510 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2511 * avoid importing user32, which is higher level than advapi32. Helper for
2514 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
2521 /* Negative values have to be inverted. */
2522 if (HIWORD(resId
) == 0xffff)
2523 resId
= (UINT
)(-((INT
)resId
));
2525 /* Load the resource into memory and get a pointer to it. */
2526 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
2527 if (!hResource
) return 0;
2528 hMemory
= LoadResource(hModule
, hResource
);
2529 if (!hMemory
) return 0;
2530 pString
= LockResource(hMemory
);
2532 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2533 idxString
= resId
& 0xf;
2534 while (idxString
--) pString
+= *pString
+ 1;
2536 /* If no buffer is given, return length of the string. */
2537 if (!pwszBuffer
) return *pString
;
2539 /* Else copy over the string, respecting the buffer size. */
2540 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
2541 if (cMaxChars
>= 0) {
2542 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
2543 pwszBuffer
[cMaxChars
] = '\0';
2549 /******************************************************************************
2550 * RegLoadMUIStringW [ADVAPI32.@]
2552 * Load the localized version of a string resource from some PE, respective
2553 * id and path of which are given in the registry value in the format
2554 * @[path]\dllname,-resourceId
2557 * hKey [I] Key, of which to load the string value from.
2558 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2559 * pszBuffer [O] Buffer to store the localized string in.
2560 * cbBuffer [I] Size of the destination buffer in bytes.
2561 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2562 * dwFlags [I] None supported yet.
2563 * pszBaseDir [I] Not supported yet.
2566 * Success: ERROR_SUCCESS,
2567 * Failure: nonzero error code from winerror.h
2570 * This is an API of Windows Vista, which wasn't available at the time this code
2571 * was written. We have to check for the correct behaviour once it's available.
2573 LSTATUS WINAPI
RegLoadMUIStringW(HKEY hKey
, LPCWSTR pwszValue
, LPWSTR pwszBuffer
, DWORD cbBuffer
,
2574 LPDWORD pcbData
, DWORD dwFlags
, LPCWSTR pwszBaseDir
)
2576 DWORD dwValueType
, cbData
;
2577 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
2580 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2581 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey
, debugstr_w(pwszValue
), pwszBuffer
,
2582 cbBuffer
, pcbData
, dwFlags
, debugstr_w(pwszBaseDir
));
2584 /* Parameter sanity checks. */
2585 if (!hKey
|| !pwszBuffer
)
2586 return ERROR_INVALID_PARAMETER
;
2588 if (pwszBaseDir
&& *pwszBaseDir
) {
2589 FIXME("BaseDir parameter not yet supported!\n");
2590 return ERROR_INVALID_PARAMETER
;
2593 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2594 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
2595 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2596 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
) {
2597 result
= ERROR_FILE_NOT_FOUND
;
2600 pwszTempBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2601 if (!pwszTempBuffer
) {
2602 result
= ERROR_NOT_ENOUGH_MEMORY
;
2605 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
2606 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2608 /* Expand environment variables, if appropriate, or copy the original string over. */
2609 if (dwValueType
== REG_EXPAND_SZ
) {
2610 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
2611 if (!cbData
) goto cleanup
;
2612 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2613 if (!pwszExpandedBuffer
) {
2614 result
= ERROR_NOT_ENOUGH_MEMORY
;
2617 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
2619 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2620 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
2623 /* If the value references a resource based string, parse the value and load the string.
2624 * Else just copy over the original value. */
2625 result
= ERROR_SUCCESS
;
2626 if (*pwszExpandedBuffer
!= '@') { /* '@' is the prefix for resource based string entries. */
2627 lstrcpynW(pwszBuffer
, pwszExpandedBuffer
, cbBuffer
/ sizeof(WCHAR
));
2629 WCHAR
*pComma
= strrchrW(pwszExpandedBuffer
, ',');
2633 /* Format of the expanded value is 'path_to_dll,-resId' */
2634 if (!pComma
|| pComma
[1] != '-') {
2635 result
= ERROR_BADKEY
;
2639 uiStringId
= atoiW(pComma
+2);
2642 hModule
= LoadLibraryW(pwszExpandedBuffer
+ 1);
2643 if (!hModule
|| !load_string(hModule
, uiStringId
, pwszBuffer
, cbBuffer
/sizeof(WCHAR
)))
2644 result
= ERROR_BADKEY
;
2645 FreeLibrary(hModule
);
2649 HeapFree(GetProcessHeap(), 0, pwszTempBuffer
);
2650 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer
);
2654 /******************************************************************************
2655 * RegLoadMUIStringA [ADVAPI32.@]
2657 * See RegLoadMUIStringW
2659 LSTATUS WINAPI
RegLoadMUIStringA(HKEY hKey
, LPCSTR pszValue
, LPSTR pszBuffer
, DWORD cbBuffer
,
2660 LPDWORD pcbData
, DWORD dwFlags
, LPCSTR pszBaseDir
)
2662 UNICODE_STRING valueW
, baseDirW
;
2664 DWORD cbData
= cbBuffer
* sizeof(WCHAR
);
2667 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
2668 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
2669 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszBaseDir
) ||
2670 !(pwszBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
)))
2672 result
= ERROR_NOT_ENOUGH_MEMORY
;
2676 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, dwFlags
,
2679 if (result
== ERROR_SUCCESS
) {
2680 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszBuffer
, cbBuffer
, NULL
, NULL
);
2686 HeapFree(GetProcessHeap(), 0, pwszBuffer
);
2687 RtlFreeUnicodeString(&baseDirW
);
2688 RtlFreeUnicodeString(&valueW
);
2693 /******************************************************************************
2694 * RegDisablePredefinedCache [ADVAPI32.@]
2696 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2702 * Success: ERROR_SUCCESS
2703 * Failure: nonzero error code from Winerror.h
2706 * This is useful for services that use impersonation.
2708 LSTATUS WINAPI
RegDisablePredefinedCache(void)
2710 HKEY hkey_current_user
;
2711 int idx
= (UINT_PTR
)HKEY_CURRENT_USER
- (UINT_PTR
)HKEY_SPECIAL_ROOT_FIRST
;
2713 /* prevent caching of future requests */
2714 hkcu_cache_disabled
= TRUE
;
2716 hkey_current_user
= InterlockedExchangePointer( (void **)&special_root_keys
[idx
], NULL
);
2718 if (hkey_current_user
)
2719 NtClose( hkey_current_user
);
2721 return ERROR_SUCCESS
;
2724 /******************************************************************************
2725 * RegDeleteTreeW [ADVAPI32.@]
2728 LSTATUS WINAPI
RegDeleteTreeW(HKEY hKey
, LPCWSTR lpszSubKey
)
2731 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
2732 DWORD dwMaxLen
, dwSize
;
2733 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
2734 HKEY hSubKey
= hKey
;
2736 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
2740 ret
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
2741 if (ret
) return ret
;
2744 /* Get highest length for keys, values */
2745 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
2746 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
2747 if (ret
) goto cleanup
;
2751 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
2752 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
2754 /* Name too big: alloc a buffer for it */
2755 if (!(lpszName
= HeapAlloc( GetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
2757 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2763 /* Recursively delete all the subkeys */
2767 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
2768 NULL
, NULL
, NULL
)) break;
2770 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
2771 if (ret
) goto cleanup
;
2775 ret
= RegDeleteKeyW(hKey
, lpszSubKey
);
2780 if (RegEnumValueW(hKey
, 0, lpszName
, &dwSize
,
2781 NULL
, NULL
, NULL
, NULL
)) break;
2783 ret
= RegDeleteValueW(hKey
, lpszName
);
2784 if (ret
) goto cleanup
;
2788 /* Free buffer if allocated */
2789 if (lpszName
!= szNameBuf
)
2790 HeapFree( GetProcessHeap(), 0, lpszName
);
2792 RegCloseKey(hSubKey
);
2796 /******************************************************************************
2797 * RegDeleteTreeA [ADVAPI32.@]
2800 LSTATUS WINAPI
RegDeleteTreeA(HKEY hKey
, LPCSTR lpszSubKey
)
2803 UNICODE_STRING lpszSubKeyW
;
2805 if (lpszSubKey
) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW
, lpszSubKey
);
2806 else lpszSubKeyW
.Buffer
= NULL
;
2807 ret
= RegDeleteTreeW( hKey
, lpszSubKeyW
.Buffer
);
2808 RtlFreeUnicodeString( &lpszSubKeyW
);