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