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
,
81 static const int is_win64
= (sizeof(void *) > sizeof(int));
83 /* check if value type needs string conversion (Ansi<->Unicode) */
84 static inline int is_string( DWORD type
)
86 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
89 /* check if current version is NT or Win95 */
90 static inline int is_version_nt(void)
92 return !(GetVersion() & 0x80000000);
95 static BOOL
is_wow6432node( const UNICODE_STRING
*name
)
97 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e'};
99 return (name
->Length
== sizeof(wow6432nodeW
) &&
100 !memicmpW( name
->Buffer
, wow6432nodeW
, sizeof(wow6432nodeW
)/sizeof(WCHAR
) ));
103 /* open the Wow6432Node subkey of the specified key */
104 static HANDLE
open_wow6432node( HANDLE key
, const UNICODE_STRING
*name
)
106 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
107 OBJECT_ATTRIBUTES attr
;
108 UNICODE_STRING nameW
;
111 attr
.Length
= sizeof(attr
);
112 attr
.RootDirectory
= key
;
113 attr
.ObjectName
= &nameW
;
115 attr
.SecurityDescriptor
= NULL
;
116 attr
.SecurityQualityOfService
= NULL
;
117 RtlInitUnicodeString( &nameW
, wow6432nodeW
);
118 if (NtOpenKey( &ret
, MAXIMUM_ALLOWED
, &attr
)) ret
= 0;
122 /* wrapper for NtCreateKey that creates the key recursively if necessary */
123 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
124 const UNICODE_STRING
*class, ULONG options
, PULONG dispos
)
126 BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
127 NTSTATUS status
= STATUS_OBJECT_NAME_NOT_FOUND
;
129 if (!force_wow32
) status
= NtCreateKey( (HANDLE
*)retkey
, access
, attr
, 0, class, options
, dispos
);
131 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
133 HANDLE subkey
, root
= attr
->RootDirectory
;
134 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
135 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
138 while (i
< len
&& buffer
[i
] != '\\') i
++;
139 if (i
== len
&& !force_wow32
) return status
;
141 attrs
= attr
->Attributes
;
142 attr
->Attributes
&= ~OBJ_OPENLINK
;
143 attr
->ObjectName
= &str
;
147 str
.Buffer
= buffer
+ pos
;
148 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
149 if (force_wow32
&& pos
)
151 if (is_wow6432node( &str
)) force_wow32
= FALSE
;
152 else if ((subkey
= open_wow6432node( attr
->RootDirectory
, &str
)))
154 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
155 attr
->RootDirectory
= subkey
;
159 status
= NtCreateKey( &subkey
, access
, attr
, 0, class,
160 options
& ~REG_OPTION_CREATE_LINK
, dispos
);
161 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
162 if (status
) return status
;
163 attr
->RootDirectory
= subkey
;
164 while (i
< len
&& buffer
[i
] == '\\') i
++;
166 while (i
< len
&& buffer
[i
] != '\\') i
++;
168 str
.Buffer
= buffer
+ pos
;
169 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
170 attr
->Attributes
= attrs
;
171 status
= NtCreateKey( (PHANDLE
)retkey
, access
, attr
, 0, class, options
, dispos
);
172 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
177 /* create one of the HKEY_* special root keys */
178 static HKEY
create_special_root_hkey( HKEY hkey
, DWORD access
)
181 int idx
= (UINT_PTR
)hkey
- (UINT_PTR
)HKEY_SPECIAL_ROOT_FIRST
;
183 if (hkey
== HKEY_CURRENT_USER
)
185 if (RtlOpenCurrentUser( access
, (HANDLE
*)&hkey
)) return 0;
186 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey
);
188 /* don't cache the key in the table if caching is disabled */
189 if (hkcu_cache_disabled
)
194 OBJECT_ATTRIBUTES attr
;
197 attr
.Length
= sizeof(attr
);
198 attr
.RootDirectory
= 0;
199 attr
.ObjectName
= &name
;
201 attr
.SecurityDescriptor
= NULL
;
202 attr
.SecurityQualityOfService
= NULL
;
203 RtlInitUnicodeString( &name
, root_key_names
[idx
] );
204 if (create_key( &hkey
, access
, &attr
, NULL
, 0, NULL
)) return 0;
205 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
208 if (!(ret
= InterlockedCompareExchangePointer( (void **)&special_root_keys
[idx
], hkey
, 0 )))
211 NtClose( hkey
); /* somebody beat us to it */
215 /* map the hkey from special root to normal key if necessary */
216 static inline HKEY
get_special_root_hkey( HKEY hkey
)
220 if ((hkey
>= HKEY_SPECIAL_ROOT_FIRST
) && (hkey
<= HKEY_SPECIAL_ROOT_LAST
))
222 if (!(ret
= special_root_keys
[(UINT_PTR
)hkey
- (UINT_PTR
)HKEY_SPECIAL_ROOT_FIRST
]))
223 ret
= create_special_root_hkey( hkey
, MAXIMUM_ALLOWED
);
229 /******************************************************************************
230 * RegOverridePredefKey [ADVAPI32.@]
232 LSTATUS WINAPI
RegOverridePredefKey( HKEY hkey
, HKEY override
)
237 if ((hkey
< HKEY_SPECIAL_ROOT_FIRST
) || (hkey
> HKEY_SPECIAL_ROOT_LAST
))
238 return ERROR_INVALID_PARAMETER
;
239 idx
= (UINT_PTR
)hkey
- (UINT_PTR
)HKEY_SPECIAL_ROOT_FIRST
;
243 NTSTATUS status
= NtDuplicateObject( GetCurrentProcess(), override
,
244 GetCurrentProcess(), (HANDLE
*)&override
,
245 0, 0, DUPLICATE_SAME_ACCESS
);
246 if (status
) return RtlNtStatusToDosError( status
);
249 old_key
= InterlockedExchangePointer( (void **)&special_root_keys
[idx
], override
);
250 if (old_key
) NtClose( old_key
);
251 return ERROR_SUCCESS
;
255 /******************************************************************************
256 * RegCreateKeyExW [ADVAPI32.@]
258 * See RegCreateKeyExA.
260 LSTATUS WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
261 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
262 PHKEY retkey
, LPDWORD dispos
)
264 OBJECT_ATTRIBUTES attr
;
265 UNICODE_STRING nameW
, classW
;
267 if (reserved
) return ERROR_INVALID_PARAMETER
;
268 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
270 attr
.Length
= sizeof(attr
);
271 attr
.RootDirectory
= hkey
;
272 attr
.ObjectName
= &nameW
;
274 attr
.SecurityDescriptor
= NULL
;
275 attr
.SecurityQualityOfService
= NULL
;
276 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
277 RtlInitUnicodeString( &nameW
, name
);
278 RtlInitUnicodeString( &classW
, class );
280 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
, &classW
, options
, dispos
) );
284 /******************************************************************************
285 * RegCreateKeyExA [ADVAPI32.@]
287 * Open a registry key, creating it if it doesn't exist.
290 * hkey [I] Handle of the parent registry key
291 * name [I] Name of the new key to open or create
292 * reserved [I] Reserved, pass 0
293 * class [I] The object type of the new key
294 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
295 * access [I] Access level desired
296 * sa [I] Security attributes for the key
297 * retkey [O] Destination for the resulting handle
298 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
301 * Success: ERROR_SUCCESS.
302 * Failure: A standard Win32 error code. retkey remains untouched.
305 * MAXIMUM_ALLOWED in access mask not supported by server
307 LSTATUS WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
308 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
309 PHKEY retkey
, LPDWORD dispos
)
311 OBJECT_ATTRIBUTES attr
;
312 UNICODE_STRING classW
;
313 ANSI_STRING nameA
, classA
;
316 if (reserved
) return ERROR_INVALID_PARAMETER
;
317 if (!is_version_nt())
319 access
= MAXIMUM_ALLOWED
; /* Win95 ignores the access mask */
320 if (name
&& *name
== '\\') name
++; /* win9x,ME ignores one (and only one) beginning backslash */
322 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
324 attr
.Length
= sizeof(attr
);
325 attr
.RootDirectory
= hkey
;
326 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
328 attr
.SecurityDescriptor
= NULL
;
329 attr
.SecurityQualityOfService
= NULL
;
330 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
331 RtlInitAnsiString( &nameA
, name
);
332 RtlInitAnsiString( &classA
, class );
334 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
337 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
339 status
= create_key( retkey
, access
, &attr
, &classW
, options
, dispos
);
340 RtlFreeUnicodeString( &classW
);
343 return RtlNtStatusToDosError( status
);
347 /******************************************************************************
348 * RegCreateKeyW [ADVAPI32.@]
350 * Creates the specified reg key.
353 * hKey [I] Handle to an open key.
354 * lpSubKey [I] Name of a key that will be opened or created.
355 * phkResult [O] Receives a handle to the opened or created key.
358 * Success: ERROR_SUCCESS
359 * Failure: nonzero error code defined in Winerror.h
361 LSTATUS WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpSubKey
, PHKEY phkResult
)
363 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
364 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
365 return RegCreateKeyExW( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
366 MAXIMUM_ALLOWED
, NULL
, phkResult
, NULL
);
370 /******************************************************************************
371 * RegCreateKeyA [ADVAPI32.@]
375 LSTATUS WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpSubKey
, PHKEY phkResult
)
377 return RegCreateKeyExA( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
378 MAXIMUM_ALLOWED
, NULL
, phkResult
, NULL
);
383 /******************************************************************************
384 * RegOpenKeyExW [ADVAPI32.@]
388 LSTATUS WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD options
, REGSAM access
, PHKEY retkey
)
390 OBJECT_ATTRIBUTES attr
;
391 UNICODE_STRING nameW
;
393 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
394 if (hkey
== HKEY_CLASSES_ROOT
&& name
&& *name
== '\\') name
++;
396 if (!retkey
) return ERROR_INVALID_PARAMETER
;
397 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
399 attr
.Length
= sizeof(attr
);
400 attr
.RootDirectory
= hkey
;
401 attr
.ObjectName
= &nameW
;
403 attr
.SecurityDescriptor
= NULL
;
404 attr
.SecurityQualityOfService
= NULL
;
405 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
406 RtlInitUnicodeString( &nameW
, name
);
407 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE
)retkey
, access
, &attr
) );
411 /******************************************************************************
412 * RegOpenKeyExA [ADVAPI32.@]
414 * Open a registry key.
417 * hkey [I] Handle of open key
418 * name [I] Name of subkey to open
419 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
420 * access [I] Security access mask
421 * retkey [O] Handle to open key
424 * Success: ERROR_SUCCESS
425 * Failure: A standard Win32 error code. retkey is set to 0.
428 * Unlike RegCreateKeyExA(), this function will not create the key if it
431 LSTATUS WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD options
, REGSAM access
, PHKEY retkey
)
433 OBJECT_ATTRIBUTES attr
;
437 if (!is_version_nt()) access
= MAXIMUM_ALLOWED
; /* Win95 ignores the access mask */
440 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
441 if (hkey
== HKEY_CLASSES_ROOT
&& name
&& *name
== '\\') name
++;
444 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
446 attr
.Length
= sizeof(attr
);
447 attr
.RootDirectory
= hkey
;
448 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
450 attr
.SecurityDescriptor
= NULL
;
451 attr
.SecurityQualityOfService
= NULL
;
452 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
454 RtlInitAnsiString( &nameA
, name
);
455 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
458 status
= NtOpenKey( (PHANDLE
)retkey
, access
, &attr
);
460 return RtlNtStatusToDosError( status
);
464 /******************************************************************************
465 * RegOpenKeyW [ADVAPI32.@]
469 LSTATUS WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, PHKEY retkey
)
472 return ERROR_INVALID_PARAMETER
;
477 return ERROR_SUCCESS
;
479 return RegOpenKeyExW( hkey
, name
, 0, MAXIMUM_ALLOWED
, retkey
);
483 /******************************************************************************
484 * RegOpenKeyA [ADVAPI32.@]
486 * Open a registry key.
489 * hkey [I] Handle of parent key to open the new key under
490 * name [I] Name of the key under hkey to open
491 * retkey [O] Destination for the resulting Handle
494 * Success: ERROR_SUCCESS
495 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
497 LSTATUS WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, PHKEY retkey
)
500 return ERROR_INVALID_PARAMETER
;
505 return ERROR_SUCCESS
;
507 return RegOpenKeyExA( hkey
, name
, 0, MAXIMUM_ALLOWED
, retkey
);
511 /******************************************************************************
512 * RegOpenCurrentUser [ADVAPI32.@]
514 * Get a handle to the HKEY_CURRENT_USER key for the user
515 * the current thread is impersonating.
518 * access [I] Desired access rights to the key
519 * retkey [O] Handle to the opened key
522 * Success: ERROR_SUCCESS
523 * Failure: nonzero error code from Winerror.h
526 * This function is supposed to retrieve a handle to the
527 * HKEY_CURRENT_USER for the user the current thread is impersonating.
528 * Since Wine does not currently allow threads to impersonate other users,
529 * this stub should work fine.
531 LSTATUS WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
533 return RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
538 /******************************************************************************
539 * RegEnumKeyExW [ADVAPI32.@]
541 * Enumerate subkeys of the specified open registry key.
544 * hkey [I] Handle to key to enumerate
545 * index [I] Index of subkey to enumerate
546 * name [O] Buffer for subkey name
547 * name_len [O] Size of subkey buffer
548 * reserved [I] Reserved
549 * class [O] Buffer for class string
550 * class_len [O] Size of class buffer
551 * ft [O] Time key last written to
554 * Success: ERROR_SUCCESS
555 * Failure: System error code. If there are no more subkeys available, the
556 * function returns ERROR_NO_MORE_ITEMS.
558 LSTATUS WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
559 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
562 char buffer
[256], *buf_ptr
= buffer
;
563 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
566 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
567 name_len
? *name_len
: 0, reserved
, class, class_len
, ft
);
569 if (reserved
) return ERROR_INVALID_PARAMETER
;
570 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
572 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
573 buffer
, sizeof(buffer
), &total_size
);
575 while (status
== STATUS_BUFFER_OVERFLOW
)
577 /* retry with a dynamically allocated buffer */
578 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
579 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
580 return ERROR_NOT_ENOUGH_MEMORY
;
581 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
582 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
583 buf_ptr
, total_size
, &total_size
);
588 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
589 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
591 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
593 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
594 status
= STATUS_BUFFER_OVERFLOW
;
598 memcpy( name
, info
->Name
, info
->NameLength
);
602 *class_len
= cls_len
;
605 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
612 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
613 return RtlNtStatusToDosError( status
);
617 /******************************************************************************
618 * RegEnumKeyExA [ADVAPI32.@]
622 LSTATUS WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
623 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
626 char buffer
[256], *buf_ptr
= buffer
;
627 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
630 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
631 name_len
? *name_len
: 0, reserved
, class, class_len
, ft
);
633 if (reserved
) return ERROR_INVALID_PARAMETER
;
634 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
636 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
637 buffer
, sizeof(buffer
), &total_size
);
639 while (status
== STATUS_BUFFER_OVERFLOW
)
641 /* retry with a dynamically allocated buffer */
642 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
643 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
644 return ERROR_NOT_ENOUGH_MEMORY
;
645 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
646 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
647 buf_ptr
, total_size
, &total_size
);
654 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
655 RtlUnicodeToMultiByteSize( &cls_len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
657 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
659 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
660 status
= STATUS_BUFFER_OVERFLOW
;
664 RtlUnicodeToMultiByteN( name
, len
, NULL
, info
->Name
, info
->NameLength
);
668 *class_len
= cls_len
;
671 RtlUnicodeToMultiByteN( class, cls_len
, NULL
,
672 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
680 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
681 return RtlNtStatusToDosError( status
);
685 /******************************************************************************
686 * RegEnumKeyW [ADVAPI32.@]
688 * Enumerates subkeys of the specified open reg key.
691 * hKey [I] Handle to an open key.
692 * dwIndex [I] Index of the subkey of hKey to retrieve.
693 * lpName [O] Name of the subkey.
694 * cchName [I] Size of lpName in TCHARS.
697 * Success: ERROR_SUCCESS
698 * Failure: system error code. If there are no more subkeys available, the
699 * function returns ERROR_NO_MORE_ITEMS.
701 LSTATUS WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
703 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
707 /******************************************************************************
708 * RegEnumKeyA [ADVAPI32.@]
712 LSTATUS WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
714 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
718 /******************************************************************************
719 * RegQueryInfoKeyW [ADVAPI32.@]
721 * Retrieves information about the specified registry key.
724 * hkey [I] Handle to key to query
725 * class [O] Buffer for class string
726 * class_len [O] Size of class string buffer
727 * reserved [I] Reserved
728 * subkeys [O] Buffer for number of subkeys
729 * max_subkey [O] Buffer for longest subkey name length
730 * max_class [O] Buffer for longest class string length
731 * values [O] Buffer for number of value entries
732 * max_value [O] Buffer for longest value name length
733 * max_data [O] Buffer for longest value data length
734 * security [O] Buffer for security descriptor length
735 * modif [O] Modification time
738 * Success: ERROR_SUCCESS
739 * Failure: system error code.
742 * - win95 allows class to be valid and class_len to be NULL
743 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
744 * - both allow class to be NULL and class_len to be NULL
745 * (it's hard to test validity, so test !NULL instead)
747 LSTATUS WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
748 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
749 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
750 LPDWORD security
, FILETIME
*modif
)
753 char buffer
[256], *buf_ptr
= buffer
;
754 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
757 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
758 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
760 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
761 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
763 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
764 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
768 /* retry with a dynamically allocated buffer */
769 while (status
== STATUS_BUFFER_OVERFLOW
)
771 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
772 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
773 return ERROR_NOT_ENOUGH_MEMORY
;
774 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
775 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
778 if (status
) goto done
;
780 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
782 status
= STATUS_BUFFER_OVERFLOW
;
786 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
787 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
790 else status
= STATUS_SUCCESS
;
792 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
793 if (subkeys
) *subkeys
= info
->SubKeys
;
794 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
795 if (max_class
) *max_class
= info
->MaxClassLen
;
796 if (values
) *values
= info
->Values
;
797 if (max_value
) *max_value
= info
->MaxValueNameLen
;
798 if (max_data
) *max_data
= info
->MaxValueDataLen
;
799 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
802 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
803 return RtlNtStatusToDosError( status
);
807 /******************************************************************************
808 * RegQueryMultipleValuesA [ADVAPI32.@]
810 * Retrieves the type and data for a list of value names associated with a key.
813 * hKey [I] Handle to an open key.
814 * val_list [O] Array of VALENT structures that describes the entries.
815 * num_vals [I] Number of elements in val_list.
816 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
817 * ldwTotsize [I/O] Size of lpValueBuf.
820 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
821 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
824 LSTATUS WINAPI
RegQueryMultipleValuesA( HKEY hkey
, PVALENTA val_list
, DWORD num_vals
,
825 LPSTR lpValueBuf
, LPDWORD ldwTotsize
)
828 DWORD maxBytes
= *ldwTotsize
;
830 LPSTR bufptr
= lpValueBuf
;
833 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
835 for(i
=0; i
< num_vals
; ++i
)
838 val_list
[i
].ve_valuelen
=0;
839 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
840 if(status
!= ERROR_SUCCESS
)
845 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
847 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
848 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
849 if(status
!= ERROR_SUCCESS
)
854 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
856 bufptr
+= val_list
[i
].ve_valuelen
;
859 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
861 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
865 /******************************************************************************
866 * RegQueryMultipleValuesW [ADVAPI32.@]
868 * See RegQueryMultipleValuesA.
870 LSTATUS WINAPI
RegQueryMultipleValuesW( HKEY hkey
, PVALENTW val_list
, DWORD num_vals
,
871 LPWSTR lpValueBuf
, LPDWORD ldwTotsize
)
874 DWORD maxBytes
= *ldwTotsize
;
876 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
879 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
881 for(i
=0; i
< num_vals
; ++i
)
883 val_list
[i
].ve_valuelen
=0;
884 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
885 if(status
!= ERROR_SUCCESS
)
890 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
892 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
893 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
894 if(status
!= ERROR_SUCCESS
)
899 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
901 bufptr
+= val_list
[i
].ve_valuelen
;
904 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
906 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
909 /******************************************************************************
910 * RegQueryInfoKeyA [ADVAPI32.@]
912 * Retrieves information about a registry key.
915 * hKey [I] Handle to an open key.
916 * lpClass [O] Class string of the key.
917 * lpcClass [I/O] size of lpClass.
918 * lpReserved [I] Reserved; must be NULL.
919 * lpcSubKeys [O] Number of subkeys contained by the key.
920 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
921 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
923 * lpcValues [O] Number of values associated with the key.
924 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
925 * lpcMaxValueLen [O] Longest data component among the key's values
926 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
927 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
930 * Success: ERROR_SUCCESS
931 * Failure: nonzero error code from Winerror.h
933 LSTATUS WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
934 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
935 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
936 LPDWORD security
, FILETIME
*modif
)
939 char buffer
[256], *buf_ptr
= buffer
;
940 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
941 DWORD total_size
, len
;
943 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
944 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
946 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
947 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
949 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
950 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
952 if (class || class_len
)
954 /* retry with a dynamically allocated buffer */
955 while (status
== STATUS_BUFFER_OVERFLOW
)
957 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
958 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
959 return ERROR_NOT_ENOUGH_MEMORY
;
960 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
961 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
964 if (status
) goto done
;
966 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
), info
->ClassLength
);
969 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
972 if (class && !status
)
974 RtlUnicodeToMultiByteN( class, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
979 else status
= STATUS_SUCCESS
;
981 if (subkeys
) *subkeys
= info
->SubKeys
;
982 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
983 if (max_class
) *max_class
= info
->MaxClassLen
;
984 if (values
) *values
= info
->Values
;
985 if (max_value
) *max_value
= info
->MaxValueNameLen
;
986 if (max_data
) *max_data
= info
->MaxValueDataLen
;
987 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
990 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
991 return RtlNtStatusToDosError( status
);
995 /******************************************************************************
996 * RegCloseKey [ADVAPI32.@]
998 * Close an open registry key.
1001 * hkey [I] Handle of key to close
1004 * Success: ERROR_SUCCESS
1005 * Failure: Error code
1007 LSTATUS WINAPI
RegCloseKey( HKEY hkey
)
1009 if (!hkey
) return ERROR_INVALID_HANDLE
;
1010 if (hkey
>= (HKEY
)0x80000000) return ERROR_SUCCESS
;
1011 return RtlNtStatusToDosError( NtClose( hkey
) );
1015 /******************************************************************************
1016 * RegDeleteKeyExW [ADVAPI32.@]
1018 LSTATUS WINAPI
RegDeleteKeyExW( HKEY hkey
, LPCWSTR name
, REGSAM access
, DWORD reserved
)
1023 if (!name
) return ERROR_INVALID_PARAMETER
;
1025 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1027 access
&= KEY_WOW64_64KEY
| KEY_WOW64_32KEY
;
1028 if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, access
| DELETE
, &tmp
)))
1030 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
1033 TRACE("%s ret=%08x\n", debugstr_w(name
), ret
);
1038 /******************************************************************************
1039 * RegDeleteKeyW [ADVAPI32.@]
1041 * See RegDeleteKeyA.
1043 LSTATUS WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
1045 return RegDeleteKeyExW( hkey
, name
, 0, 0 );
1049 /******************************************************************************
1050 * RegDeleteKeyExA [ADVAPI32.@]
1052 LSTATUS WINAPI
RegDeleteKeyExA( HKEY hkey
, LPCSTR name
, REGSAM access
, DWORD reserved
)
1057 if (!name
) return ERROR_INVALID_PARAMETER
;
1059 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1061 access
&= KEY_WOW64_64KEY
| KEY_WOW64_32KEY
;
1062 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, access
| DELETE
, &tmp
)))
1064 if (!is_version_nt()) /* win95 does recursive key deletes */
1066 CHAR name
[MAX_PATH
];
1068 while(!RegEnumKeyA(tmp
, 0, name
, sizeof(name
)))
1070 if(RegDeleteKeyExA(tmp
, name
, access
, reserved
)) /* recurse */
1074 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
1077 TRACE("%s ret=%08x\n", debugstr_a(name
), ret
);
1082 /******************************************************************************
1083 * RegDeleteKeyA [ADVAPI32.@]
1085 * Delete a registry key.
1088 * hkey [I] Handle to parent key containing the key to delete
1089 * name [I] Name of the key user hkey to delete
1093 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1094 * right. In reality, it opens a new handle with DELETE access.
1097 * Success: ERROR_SUCCESS
1098 * Failure: Error code
1100 LSTATUS WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
1102 return RegDeleteKeyExA( hkey
, name
, 0, 0 );
1107 /******************************************************************************
1108 * RegSetValueExW [ADVAPI32.@]
1110 * Set the data and contents of a registry value.
1113 * hkey [I] Handle of key to set value for
1114 * name [I] Name of value to set
1115 * reserved [I] Reserved, must be zero
1116 * type [I] Type of the value being set
1117 * data [I] The new contents of the value to set
1118 * count [I] Size of data
1121 * Success: ERROR_SUCCESS
1122 * Failure: Error code
1124 LSTATUS WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
1125 DWORD type
, CONST BYTE
*data
, DWORD count
)
1127 UNICODE_STRING nameW
;
1129 /* no need for version check, not implemented on win9x anyway */
1130 if (count
&& is_string(type
))
1132 LPCWSTR str
= (LPCWSTR
)data
;
1133 /* if user forgot to count terminating null, add it (yes NT does this) */
1134 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
1135 count
+= sizeof(WCHAR
);
1137 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1139 RtlInitUnicodeString( &nameW
, name
);
1140 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
1144 /******************************************************************************
1145 * RegSetValueExA [ADVAPI32.@]
1147 * See RegSetValueExW.
1150 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1151 * NT does definitely care (aj)
1153 LSTATUS WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1154 CONST BYTE
*data
, DWORD count
)
1157 UNICODE_STRING nameW
;
1158 WCHAR
*dataW
= NULL
;
1161 if (!is_version_nt()) /* win95 */
1165 if (!data
) return ERROR_INVALID_PARAMETER
;
1166 count
= strlen((const char *)data
) + 1;
1169 else if (count
&& is_string(type
))
1171 /* if user forgot to count terminating null, add it (yes NT does this) */
1172 if (data
[count
-1] && !data
[count
]) count
++;
1175 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1177 if (is_string( type
)) /* need to convert to Unicode */
1180 RtlMultiByteToUnicodeSize( &lenW
, (const char *)data
, count
);
1181 if (!(dataW
= HeapAlloc( GetProcessHeap(), 0, lenW
))) return ERROR_OUTOFMEMORY
;
1182 RtlMultiByteToUnicodeN( dataW
, lenW
, NULL
, (const char *)data
, count
);
1184 data
= (BYTE
*)dataW
;
1187 RtlInitAnsiString( &nameA
, name
);
1188 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1190 status
= NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
);
1191 RtlFreeUnicodeString( &nameW
);
1193 HeapFree( GetProcessHeap(), 0, dataW
);
1194 return RtlNtStatusToDosError( status
);
1198 /******************************************************************************
1199 * RegSetValueW [ADVAPI32.@]
1201 * Sets the data for the default or unnamed value of a reg key.
1204 * hKey [I] Handle to an open key.
1205 * lpSubKey [I] Name of a subkey of hKey.
1206 * dwType [I] Type of information to store.
1207 * lpData [I] String that contains the data to set for the default value.
1208 * cbData [I] Ignored.
1211 * Success: ERROR_SUCCESS
1212 * Failure: nonzero error code from Winerror.h
1214 LSTATUS WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR name
, DWORD type
, LPCWSTR data
, DWORD count
)
1219 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_w(name
), type
, debugstr_w(data
), count
);
1221 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1223 if (name
&& name
[0]) /* need to create the subkey */
1225 if ((ret
= RegCreateKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1228 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)data
,
1229 (strlenW( data
) + 1) * sizeof(WCHAR
) );
1230 if (subkey
!= hkey
) RegCloseKey( subkey
);
1235 /******************************************************************************
1236 * RegSetValueA [ADVAPI32.@]
1240 LSTATUS WINAPI
RegSetValueA( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1245 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_a(name
), type
, debugstr_a(data
), count
);
1247 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1249 if (name
&& name
[0]) /* need to create the subkey */
1251 if ((ret
= RegCreateKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1253 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)data
, strlen(data
)+1 );
1254 if (subkey
!= hkey
) RegCloseKey( subkey
);
1260 /******************************************************************************
1261 * RegQueryValueExW [ADVAPI32.@]
1263 * See RegQueryValueExA.
1265 LSTATUS WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
1266 LPBYTE data
, LPDWORD count
)
1269 UNICODE_STRING name_str
;
1271 char buffer
[256], *buf_ptr
= buffer
;
1272 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1273 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1275 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1276 hkey
, debugstr_w(name
), reserved
, type
, data
, count
,
1277 (count
&& data
) ? *count
: 0 );
1279 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1280 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1282 RtlInitUnicodeString( &name_str
, name
);
1284 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
1287 total_size
= info_size
;
1288 if (count
) *count
= 0;
1291 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1292 buffer
, total_size
, &total_size
);
1293 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1297 /* retry with a dynamically allocated buffer */
1298 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
1300 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1301 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1302 return ERROR_NOT_ENOUGH_MEMORY
;
1303 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1304 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1305 buf_ptr
, total_size
, &total_size
);
1310 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1311 /* if the type is REG_SZ and data is not 0-terminated
1312 * and there is enough space in the buffer NT appends a \0 */
1313 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1315 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
1316 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1319 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1321 else status
= STATUS_SUCCESS
;
1323 if (type
) *type
= info
->Type
;
1324 if (count
) *count
= total_size
- info_size
;
1327 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1328 return RtlNtStatusToDosError(status
);
1332 /******************************************************************************
1333 * RegQueryValueExA [ADVAPI32.@]
1335 * Get the type and contents of a specified value under with a key.
1338 * hkey [I] Handle of the key to query
1339 * name [I] Name of value under hkey to query
1340 * reserved [I] Reserved - must be NULL
1341 * type [O] Destination for the value type, or NULL if not required
1342 * data [O] Destination for the values contents, or NULL if not required
1343 * count [I/O] Size of data, updated with the number of bytes returned
1346 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1347 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1348 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1349 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1352 * MSDN states that if data is too small it is partially filled. In reality
1353 * it remains untouched.
1355 LSTATUS WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1356 LPBYTE data
, LPDWORD count
)
1360 UNICODE_STRING nameW
;
1361 DWORD total_size
, datalen
= 0;
1362 char buffer
[256], *buf_ptr
= buffer
;
1363 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1364 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1366 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1367 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
1369 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1370 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1372 if (count
) datalen
= *count
;
1373 if (!data
&& count
) *count
= 0;
1375 /* this matches Win9x behaviour - NT sets *type to a random value */
1376 if (type
) *type
= REG_NONE
;
1378 RtlInitAnsiString( &nameA
, name
);
1379 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1380 return RtlNtStatusToDosError(status
);
1382 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1383 buffer
, sizeof(buffer
), &total_size
);
1384 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1386 /* we need to fetch the contents for a string type even if not requested,
1387 * because we need to compute the length of the ASCII string. */
1388 if (data
|| is_string(info
->Type
))
1390 /* retry with a dynamically allocated buffer */
1391 while (status
== STATUS_BUFFER_OVERFLOW
)
1393 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1394 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1396 status
= STATUS_NO_MEMORY
;
1399 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1400 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1401 buf_ptr
, total_size
, &total_size
);
1404 if (status
) goto done
;
1406 if (is_string(info
->Type
))
1410 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
1411 total_size
- info_size
);
1414 if (len
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1417 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
1418 total_size
- info_size
);
1419 /* if the type is REG_SZ and data is not 0-terminated
1420 * and there is enough space in the buffer NT appends a \0 */
1421 if (len
< datalen
&& data
[len
-1]) data
[len
] = 0;
1424 total_size
= len
+ info_size
;
1428 if (total_size
- info_size
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1429 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1432 else status
= STATUS_SUCCESS
;
1434 if (type
) *type
= info
->Type
;
1435 if (count
) *count
= total_size
- info_size
;
1438 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1439 RtlFreeUnicodeString( &nameW
);
1440 return RtlNtStatusToDosError(status
);
1444 /******************************************************************************
1445 * RegQueryValueW [ADVAPI32.@]
1447 * Retrieves the data associated with the default or unnamed value of a key.
1450 * hkey [I] Handle to an open key.
1451 * name [I] Name of the subkey of hKey.
1452 * data [O] Receives the string associated with the default value
1454 * count [I/O] Size of lpValue in bytes.
1457 * Success: ERROR_SUCCESS
1458 * Failure: nonzero error code from Winerror.h
1460 LSTATUS WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
1465 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
1467 if (name
&& name
[0])
1469 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1471 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1472 if (subkey
!= hkey
) RegCloseKey( subkey
);
1473 if (ret
== ERROR_FILE_NOT_FOUND
)
1475 /* return empty string if default value not found */
1476 if (data
) *data
= 0;
1477 if (count
) *count
= sizeof(WCHAR
);
1478 ret
= ERROR_SUCCESS
;
1484 /******************************************************************************
1485 * RegQueryValueA [ADVAPI32.@]
1487 * See RegQueryValueW.
1489 LSTATUS WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
1494 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
1496 if (name
&& name
[0])
1498 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1500 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1501 if (subkey
!= hkey
) RegCloseKey( subkey
);
1502 if (ret
== ERROR_FILE_NOT_FOUND
)
1504 /* return empty string if default value not found */
1505 if (data
) *data
= 0;
1506 if (count
) *count
= 1;
1507 ret
= ERROR_SUCCESS
;
1513 /******************************************************************************
1514 * ADVAPI_ApplyRestrictions [internal]
1516 * Helper function for RegGetValueA/W.
1518 static VOID
ADVAPI_ApplyRestrictions( DWORD dwFlags
, DWORD dwType
,
1519 DWORD cbData
, PLONG ret
)
1521 /* Check if the type is restricted by the passed flags */
1522 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1528 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1529 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1530 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1531 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1532 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1533 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1534 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1537 if (dwFlags
& dwMask
)
1539 /* Type is not restricted, check for size mismatch */
1540 if (dwType
== REG_BINARY
)
1544 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
1546 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
1549 if (cbExpect
&& cbData
!= cbExpect
)
1550 *ret
= ERROR_DATATYPE_MISMATCH
;
1553 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1558 /******************************************************************************
1559 * RegGetValueW [ADVAPI32.@]
1561 * Retrieves the type and data for a value name associated with a key,
1562 * optionally expanding its content and restricting its type.
1565 * hKey [I] Handle to an open key.
1566 * pszSubKey [I] Name of the subkey of hKey.
1567 * pszValue [I] Name of value under hKey/szSubKey to query.
1568 * dwFlags [I] Flags restricting the value type to retrieve.
1569 * pdwType [O] Destination for the values type, may be NULL.
1570 * pvData [O] Destination for the values content, may be NULL.
1571 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1572 * retrieve the whole content, including the trailing '\0'
1576 * Success: ERROR_SUCCESS
1577 * Failure: nonzero error code from Winerror.h
1580 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1581 * expanded and pdwType is set to REG_SZ instead.
1582 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1583 * without RRF_NOEXPAND is thus not allowed.
1584 * An exception is the case where RRF_RT_ANY is specified, because then
1585 * RRF_NOEXPAND is allowed.
1587 LSTATUS WINAPI
RegGetValueW( HKEY hKey
, LPCWSTR pszSubKey
, LPCWSTR pszValue
,
1588 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1591 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1595 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1596 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1597 pvData
, pcbData
, cbData
);
1599 if (pvData
&& !pcbData
)
1600 return ERROR_INVALID_PARAMETER
;
1601 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1602 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1603 return ERROR_INVALID_PARAMETER
;
1605 if (pszSubKey
&& pszSubKey
[0])
1607 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1608 if (ret
!= ERROR_SUCCESS
) return ret
;
1611 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1613 /* If we are going to expand we need to read in the whole the value even
1614 * if the passed buffer was too small as the expanded string might be
1615 * smaller than the unexpanded one and could fit into cbData bytes. */
1616 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1617 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1620 HeapFree(GetProcessHeap(), 0, pvBuf
);
1622 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1625 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1629 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1630 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
1631 &dwType
, pvBuf
, &cbData
);
1634 /* Even if cbData was large enough we have to copy the
1635 * string since ExpandEnvironmentStrings can't handle
1636 * overlapping buffers. */
1637 CopyMemory(pvBuf
, pvData
, cbData
);
1640 /* Both the type or the value itself could have been modified in
1641 * between so we have to keep retrying until the buffer is large
1642 * enough or we no longer have to expand the value. */
1643 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1645 if (ret
== ERROR_SUCCESS
)
1647 /* Recheck dwType in case it changed since the first call */
1648 if (dwType
== REG_EXPAND_SZ
)
1650 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
1651 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
1653 if(pvData
&& pcbData
&& cbData
> *pcbData
)
1654 ret
= ERROR_MORE_DATA
;
1657 CopyMemory(pvData
, pvBuf
, *pcbData
);
1660 HeapFree(GetProcessHeap(), 0, pvBuf
);
1663 if (pszSubKey
&& pszSubKey
[0])
1666 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1668 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1669 ZeroMemory(pvData
, *pcbData
);
1671 if (pdwType
) *pdwType
= dwType
;
1672 if (pcbData
) *pcbData
= cbData
;
1678 /******************************************************************************
1679 * RegGetValueA [ADVAPI32.@]
1683 LSTATUS WINAPI
RegGetValueA( HKEY hKey
, LPCSTR pszSubKey
, LPCSTR pszValue
,
1684 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1687 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1691 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1692 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
1695 if (pvData
&& !pcbData
)
1696 return ERROR_INVALID_PARAMETER
;
1697 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1698 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1699 return ERROR_INVALID_PARAMETER
;
1701 if (pszSubKey
&& pszSubKey
[0])
1703 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1704 if (ret
!= ERROR_SUCCESS
) return ret
;
1707 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1709 /* If we are going to expand we need to read in the whole the value even
1710 * if the passed buffer was too small as the expanded string might be
1711 * smaller than the unexpanded one and could fit into cbData bytes. */
1712 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1713 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1716 HeapFree(GetProcessHeap(), 0, pvBuf
);
1718 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1721 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1725 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1726 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
1727 &dwType
, pvBuf
, &cbData
);
1730 /* Even if cbData was large enough we have to copy the
1731 * string since ExpandEnvironmentStrings can't handle
1732 * overlapping buffers. */
1733 CopyMemory(pvBuf
, pvData
, cbData
);
1736 /* Both the type or the value itself could have been modified in
1737 * between so we have to keep retrying until the buffer is large
1738 * enough or we no longer have to expand the value. */
1739 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1741 if (ret
== ERROR_SUCCESS
)
1743 /* Recheck dwType in case it changed since the first call */
1744 if (dwType
== REG_EXPAND_SZ
)
1746 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
1747 pcbData
? *pcbData
: 0);
1749 if(pvData
&& pcbData
&& cbData
> *pcbData
)
1750 ret
= ERROR_MORE_DATA
;
1753 CopyMemory(pvData
, pvBuf
, *pcbData
);
1756 HeapFree(GetProcessHeap(), 0, pvBuf
);
1759 if (pszSubKey
&& pszSubKey
[0])
1762 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1764 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1765 ZeroMemory(pvData
, *pcbData
);
1767 if (pdwType
) *pdwType
= dwType
;
1768 if (pcbData
) *pcbData
= cbData
;
1774 /******************************************************************************
1775 * RegEnumValueW [ADVAPI32.@]
1777 * Enumerates the values for the specified open registry key.
1780 * hkey [I] Handle to key to query
1781 * index [I] Index of value to query
1782 * value [O] Value string
1783 * val_count [I/O] Size of value buffer (in wchars)
1784 * reserved [I] Reserved
1785 * type [O] Type code
1786 * data [O] Value data
1787 * count [I/O] Size of data buffer (in bytes)
1790 * Success: ERROR_SUCCESS
1791 * Failure: nonzero error code from Winerror.h
1794 LSTATUS WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
1795 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1799 char buffer
[256], *buf_ptr
= buffer
;
1800 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1801 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1803 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1804 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1806 /* NT only checks count, not val_count */
1807 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1808 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1810 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1811 if (data
) total_size
+= *count
;
1812 total_size
= min( sizeof(buffer
), total_size
);
1814 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1815 buffer
, total_size
, &total_size
);
1816 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1820 /* retry with a dynamically allocated buffer */
1821 while (status
== STATUS_BUFFER_OVERFLOW
)
1823 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1824 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1825 return ERROR_NOT_ENOUGH_MEMORY
;
1826 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1827 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1828 buf_ptr
, total_size
, &total_size
);
1831 if (status
) goto done
;
1835 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
1837 status
= STATUS_BUFFER_OVERFLOW
;
1840 memcpy( value
, info
->Name
, info
->NameLength
);
1841 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
1842 value
[*val_count
] = 0;
1847 if (total_size
- info
->DataOffset
> *count
)
1849 status
= STATUS_BUFFER_OVERFLOW
;
1852 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1853 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1855 /* if the type is REG_SZ and data is not 0-terminated
1856 * and there is enough space in the buffer NT appends a \0 */
1857 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
1858 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1862 else status
= STATUS_SUCCESS
;
1865 if (type
) *type
= info
->Type
;
1866 if (count
) *count
= info
->DataLength
;
1869 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1870 return RtlNtStatusToDosError(status
);
1874 /******************************************************************************
1875 * RegEnumValueA [ADVAPI32.@]
1877 * See RegEnumValueW.
1879 LSTATUS WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1880 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1884 char buffer
[256], *buf_ptr
= buffer
;
1885 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1886 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1888 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1889 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1891 /* NT only checks count, not val_count */
1892 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1893 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1895 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1896 if (data
) total_size
+= *count
;
1897 total_size
= min( sizeof(buffer
), total_size
);
1899 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1900 buffer
, total_size
, &total_size
);
1901 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1903 /* we need to fetch the contents for a string type even if not requested,
1904 * because we need to compute the length of the ASCII string. */
1905 if (value
|| data
|| is_string(info
->Type
))
1907 /* retry with a dynamically allocated buffer */
1908 while (status
== STATUS_BUFFER_OVERFLOW
)
1910 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1911 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1912 return ERROR_NOT_ENOUGH_MEMORY
;
1913 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1914 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1915 buf_ptr
, total_size
, &total_size
);
1918 if (status
) goto done
;
1920 if (is_string(info
->Type
))
1923 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1924 total_size
- info
->DataOffset
);
1927 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1930 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1931 total_size
- info
->DataOffset
);
1932 /* if the type is REG_SZ and data is not 0-terminated
1933 * and there is enough space in the buffer NT appends a \0 */
1934 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1937 info
->DataLength
= len
;
1941 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1942 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1945 if (value
&& !status
)
1949 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
1950 if (len
>= *val_count
)
1952 status
= STATUS_BUFFER_OVERFLOW
;
1955 len
= *val_count
- 1;
1956 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1962 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1968 else status
= STATUS_SUCCESS
;
1970 if (type
) *type
= info
->Type
;
1971 if (count
) *count
= info
->DataLength
;
1974 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1975 return RtlNtStatusToDosError(status
);
1980 /******************************************************************************
1981 * RegDeleteValueW [ADVAPI32.@]
1983 * See RegDeleteValueA.
1985 LSTATUS WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
1987 UNICODE_STRING nameW
;
1989 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1991 RtlInitUnicodeString( &nameW
, name
);
1992 return RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
1996 /******************************************************************************
1997 * RegDeleteValueA [ADVAPI32.@]
1999 * Delete a value from the registry.
2002 * hkey [I] Registry handle of the key holding the value
2003 * name [I] Name of the value under hkey to delete
2006 * Success: ERROR_SUCCESS
2007 * Failure: nonzero error code from Winerror.h
2009 LSTATUS WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
2012 UNICODE_STRING nameW
;
2015 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
2017 RtlInitAnsiString( &nameA
, name
);
2018 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
2020 status
= NtDeleteValueKey( hkey
, &nameW
);
2021 RtlFreeUnicodeString( &nameW
);
2023 return RtlNtStatusToDosError( status
);
2027 /******************************************************************************
2028 * RegLoadKeyW [ADVAPI32.@]
2030 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2031 * registration information from a specified file into that subkey.
2034 * hkey [I] Handle of open key
2035 * subkey [I] Address of name of subkey
2036 * filename [I] Address of filename for registry information
2039 * Success: ERROR_SUCCESS
2040 * Failure: nonzero error code from Winerror.h
2042 LSTATUS WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
2044 OBJECT_ATTRIBUTES destkey
, file
;
2045 UNICODE_STRING subkeyW
, filenameW
;
2048 if (!(hkey
= get_special_root_hkey(hkey
))) return ERROR_INVALID_HANDLE
;
2050 destkey
.Length
= sizeof(destkey
);
2051 destkey
.RootDirectory
= hkey
; /* root key: HKLM or HKU */
2052 destkey
.ObjectName
= &subkeyW
; /* name of the key */
2053 destkey
.Attributes
= 0;
2054 destkey
.SecurityDescriptor
= NULL
;
2055 destkey
.SecurityQualityOfService
= NULL
;
2056 RtlInitUnicodeString(&subkeyW
, subkey
);
2058 file
.Length
= sizeof(file
);
2059 file
.RootDirectory
= NULL
;
2060 file
.ObjectName
= &filenameW
; /* file containing the hive */
2061 file
.Attributes
= OBJ_CASE_INSENSITIVE
;
2062 file
.SecurityDescriptor
= NULL
;
2063 file
.SecurityQualityOfService
= NULL
;
2064 RtlDosPathNameToNtPathName_U(filename
, &filenameW
, NULL
, NULL
);
2066 status
= NtLoadKey(&destkey
, &file
);
2067 RtlFreeUnicodeString(&filenameW
);
2068 return RtlNtStatusToDosError( status
);
2072 /******************************************************************************
2073 * RegLoadKeyA [ADVAPI32.@]
2077 LSTATUS WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
2079 UNICODE_STRING subkeyW
, filenameW
;
2080 STRING subkeyA
, filenameA
;
2084 RtlInitAnsiString(&subkeyA
, subkey
);
2085 RtlInitAnsiString(&filenameA
, filename
);
2087 RtlInitUnicodeString(&subkeyW
, NULL
);
2088 RtlInitUnicodeString(&filenameW
, NULL
);
2089 if (!(status
= RtlAnsiStringToUnicodeString(&subkeyW
, &subkeyA
, TRUE
)) &&
2090 !(status
= RtlAnsiStringToUnicodeString(&filenameW
, &filenameA
, TRUE
)))
2092 ret
= RegLoadKeyW(hkey
, subkeyW
.Buffer
, filenameW
.Buffer
);
2094 else ret
= RtlNtStatusToDosError(status
);
2095 RtlFreeUnicodeString(&subkeyW
);
2096 RtlFreeUnicodeString(&filenameW
);
2101 /******************************************************************************
2102 * RegSaveKeyW [ADVAPI32.@]
2104 * Save a key and all of its subkeys and values to a new file in the standard format.
2107 * hkey [I] Handle of key where save begins
2108 * lpFile [I] Address of filename to save to
2109 * sa [I] Address of security structure
2112 * Success: ERROR_SUCCESS
2113 * Failure: nonzero error code from Winerror.h
2115 LSTATUS WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
2117 static const WCHAR format
[] =
2118 {'r','e','g','%','0','4','x','.','t','m','p',0};
2119 WCHAR buffer
[MAX_PATH
];
2125 TRACE( "(%p,%s,%p)\n", hkey
, debugstr_w(file
), sa
);
2127 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
2128 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
2130 err
= GetLastError();
2131 GetFullPathNameW( file
, sizeof(buffer
)/sizeof(WCHAR
), buffer
, &nameW
);
2135 snprintfW( nameW
, 16, format
, count
++ );
2136 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
2137 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
2138 if (handle
!= INVALID_HANDLE_VALUE
) break;
2139 if ((ret
= GetLastError()) != ERROR_FILE_EXISTS
) goto done
;
2141 /* Something gone haywire ? Please report if this happens abnormally */
2143 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
);
2146 ret
= RtlNtStatusToDosError(NtSaveKey(hkey
, handle
));
2148 CloseHandle( handle
);
2151 if (!MoveFileExW( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
2153 ERR( "Failed to move %s to %s\n", debugstr_w(buffer
),
2155 ret
= GetLastError();
2158 if (ret
) DeleteFileW( buffer
);
2161 SetLastError( err
); /* restore last error code */
2166 /******************************************************************************
2167 * RegSaveKeyA [ADVAPI32.@]
2171 LSTATUS WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
2173 UNICODE_STRING
*fileW
= &NtCurrentTeb()->StaticUnicodeString
;
2177 RtlInitAnsiString(&fileA
, file
);
2178 if ((status
= RtlAnsiStringToUnicodeString(fileW
, &fileA
, FALSE
)))
2179 return RtlNtStatusToDosError( status
);
2180 return RegSaveKeyW(hkey
, fileW
->Buffer
, sa
);
2184 /******************************************************************************
2185 * RegRestoreKeyW [ADVAPI32.@]
2187 * Read the registry information from a file and copy it over a key.
2190 * hkey [I] Handle of key where restore begins
2191 * lpFile [I] Address of filename containing saved tree
2192 * dwFlags [I] Optional flags
2195 * Success: ERROR_SUCCESS
2196 * Failure: nonzero error code from Winerror.h
2198 LSTATUS WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
2200 TRACE("(%p,%s,%d)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2202 /* It seems to do this check before the hkey check */
2203 if (!lpFile
|| !*lpFile
)
2204 return ERROR_INVALID_PARAMETER
;
2206 FIXME("(%p,%s,%d): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2208 /* Check for file existence */
2210 return ERROR_SUCCESS
;
2214 /******************************************************************************
2215 * RegRestoreKeyA [ADVAPI32.@]
2217 * See RegRestoreKeyW.
2219 LSTATUS WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
2221 UNICODE_STRING lpFileW
;
2224 RtlCreateUnicodeStringFromAsciiz( &lpFileW
, lpFile
);
2225 ret
= RegRestoreKeyW( hkey
, lpFileW
.Buffer
, dwFlags
);
2226 RtlFreeUnicodeString( &lpFileW
);
2231 /******************************************************************************
2232 * RegUnLoadKeyW [ADVAPI32.@]
2234 * Unload a registry key and its subkeys from the registry.
2237 * hkey [I] Handle of open key
2238 * lpSubKey [I] Address of name of subkey to unload
2241 * Success: ERROR_SUCCESS
2242 * Failure: nonzero error code from Winerror.h
2244 LSTATUS WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
2248 OBJECT_ATTRIBUTES attr
;
2249 UNICODE_STRING subkey
;
2251 TRACE("(%p,%s)\n",hkey
, debugstr_w(lpSubKey
));
2253 ret
= RegOpenKeyW(hkey
,lpSubKey
,&shkey
);
2255 return ERROR_INVALID_PARAMETER
;
2257 RtlInitUnicodeString(&subkey
, lpSubKey
);
2258 InitializeObjectAttributes(&attr
, &subkey
, OBJ_CASE_INSENSITIVE
, shkey
, NULL
);
2259 ret
= RtlNtStatusToDosError(NtUnloadKey(&attr
));
2267 /******************************************************************************
2268 * RegUnLoadKeyA [ADVAPI32.@]
2270 * See RegUnLoadKeyW.
2272 LSTATUS WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
2274 UNICODE_STRING lpSubKeyW
;
2277 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2278 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
.Buffer
);
2279 RtlFreeUnicodeString( &lpSubKeyW
);
2284 /******************************************************************************
2285 * RegReplaceKeyW [ADVAPI32.@]
2287 * Replace the file backing a registry key and all its subkeys with another file.
2290 * hkey [I] Handle of open key
2291 * lpSubKey [I] Address of name of subkey
2292 * lpNewFile [I] Address of filename for file with new data
2293 * lpOldFile [I] Address of filename for backup file
2296 * Success: ERROR_SUCCESS
2297 * Failure: nonzero error code from Winerror.h
2299 LSTATUS WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
2302 FIXME("(%p,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
2303 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
2304 return ERROR_SUCCESS
;
2308 /******************************************************************************
2309 * RegReplaceKeyA [ADVAPI32.@]
2311 * See RegReplaceKeyW.
2313 LSTATUS WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
2316 UNICODE_STRING lpSubKeyW
;
2317 UNICODE_STRING lpNewFileW
;
2318 UNICODE_STRING lpOldFileW
;
2321 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2322 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW
, lpOldFile
);
2323 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW
, lpNewFile
);
2324 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
.Buffer
, lpNewFileW
.Buffer
, lpOldFileW
.Buffer
);
2325 RtlFreeUnicodeString( &lpOldFileW
);
2326 RtlFreeUnicodeString( &lpNewFileW
);
2327 RtlFreeUnicodeString( &lpSubKeyW
);
2332 /******************************************************************************
2333 * RegSetKeySecurity [ADVAPI32.@]
2335 * Set the security of an open registry key.
2338 * hkey [I] Open handle of key to set
2339 * SecurityInfo [I] Descriptor contents
2340 * pSecurityDesc [I] Address of descriptor for key
2343 * Success: ERROR_SUCCESS
2344 * Failure: nonzero error code from Winerror.h
2346 LSTATUS WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
2347 PSECURITY_DESCRIPTOR pSecurityDesc
)
2349 TRACE("(%p,%d,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
2351 /* It seems to perform this check before the hkey check */
2352 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
2353 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
2354 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
2355 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
2358 return ERROR_INVALID_PARAMETER
;
2361 return ERROR_INVALID_PARAMETER
;
2363 FIXME(":(%p,%d,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
2365 return ERROR_SUCCESS
;
2369 /******************************************************************************
2370 * RegGetKeySecurity [ADVAPI32.@]
2372 * Get a copy of the security descriptor for a given registry key.
2375 * hkey [I] Open handle of key to set
2376 * SecurityInformation [I] Descriptor contents
2377 * pSecurityDescriptor [O] Address of descriptor for key
2378 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2381 * Success: ERROR_SUCCESS
2382 * Failure: Error code
2384 LSTATUS WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
2385 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2386 LPDWORD lpcbSecurityDescriptor
)
2388 TRACE("(%p,%d,%p,%d)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
2389 *lpcbSecurityDescriptor
);
2391 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
2393 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey
,
2394 SecurityInformation
, pSecurityDescriptor
,
2395 *lpcbSecurityDescriptor
, lpcbSecurityDescriptor
) );
2399 /******************************************************************************
2400 * RegFlushKey [ADVAPI32.@]
2402 * Immediately write a registry key to registry.
2405 * hkey [I] Handle of key to write
2408 * Success: ERROR_SUCCESS
2409 * Failure: Error code
2411 LSTATUS WINAPI
RegFlushKey( HKEY hkey
)
2413 hkey
= get_special_root_hkey( hkey
);
2414 if (!hkey
) return ERROR_INVALID_HANDLE
;
2416 return RtlNtStatusToDosError( NtFlushKey( hkey
) );
2420 /******************************************************************************
2421 * RegConnectRegistryW [ADVAPI32.@]
2423 * Establish a connection to a predefined registry key on another computer.
2426 * lpMachineName [I] Address of name of remote computer
2427 * hHey [I] Predefined registry handle
2428 * phkResult [I] Address of buffer for remote registry handle
2431 * Success: ERROR_SUCCESS
2432 * Failure: nonzero error code from Winerror.h
2434 LSTATUS WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
2439 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
2441 if (!lpMachineName
|| !*lpMachineName
) {
2442 /* Use the local machine name */
2443 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
2446 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
2447 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
2449 /* MSDN says lpMachineName must start with \\ : not so */
2450 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
2452 if (GetComputerNameW(compName
, &len
))
2454 if (!strcmpiW(lpMachineName
, compName
))
2455 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
2458 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
2459 ret
= ERROR_BAD_NETPATH
;
2463 ret
= GetLastError();
2469 /******************************************************************************
2470 * RegConnectRegistryA [ADVAPI32.@]
2472 * See RegConnectRegistryW.
2474 LSTATUS WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, PHKEY reskey
)
2476 UNICODE_STRING machineW
;
2479 RtlCreateUnicodeStringFromAsciiz( &machineW
, machine
);
2480 ret
= RegConnectRegistryW( machineW
.Buffer
, hkey
, reskey
);
2481 RtlFreeUnicodeString( &machineW
);
2486 /******************************************************************************
2487 * RegNotifyChangeKeyValue [ADVAPI32.@]
2489 * Notify the caller about changes to the attributes or contents of a registry key.
2492 * hkey [I] Handle of key to watch
2493 * fWatchSubTree [I] Flag for subkey notification
2494 * fdwNotifyFilter [I] Changes to be reported
2495 * hEvent [I] Handle of signaled event
2496 * fAsync [I] Flag for asynchronous reporting
2499 * Success: ERROR_SUCCESS
2500 * Failure: nonzero error code from Winerror.h
2502 LSTATUS WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
2503 DWORD fdwNotifyFilter
, HANDLE hEvent
,
2507 IO_STATUS_BLOCK iosb
;
2509 hkey
= get_special_root_hkey( hkey
);
2510 if (!hkey
) return ERROR_INVALID_HANDLE
;
2512 TRACE("(%p,%i,%d,%p,%i)\n", hkey
, fWatchSubTree
, fdwNotifyFilter
,
2515 status
= NtNotifyChangeKey( hkey
, hEvent
, NULL
, NULL
, &iosb
,
2516 fdwNotifyFilter
, fAsync
, NULL
, 0,
2519 if (status
&& status
!= STATUS_TIMEOUT
)
2520 return RtlNtStatusToDosError( status
);
2522 return ERROR_SUCCESS
;
2525 /******************************************************************************
2526 * RegOpenUserClassesRoot [ADVAPI32.@]
2528 * Open the HKEY_CLASSES_ROOT key for a user.
2531 * hToken [I] Handle of token representing the user
2532 * dwOptions [I] Reserved, must be 0
2533 * samDesired [I] Desired access rights
2534 * phkResult [O] Destination for the resulting key handle
2537 * Success: ERROR_SUCCESS
2538 * Failure: nonzero error code from Winerror.h
2541 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2542 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2543 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2545 LSTATUS WINAPI
RegOpenUserClassesRoot(
2552 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken
, dwOptions
, samDesired
, phkResult
);
2554 *phkResult
= HKEY_CLASSES_ROOT
;
2555 return ERROR_SUCCESS
;
2558 /******************************************************************************
2559 * load_string [Internal]
2561 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2562 * avoid importing user32, which is higher level than advapi32. Helper for
2565 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
2572 /* Negative values have to be inverted. */
2573 if (HIWORD(resId
) == 0xffff)
2574 resId
= (UINT
)(-((INT
)resId
));
2576 /* Load the resource into memory and get a pointer to it. */
2577 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
2578 if (!hResource
) return 0;
2579 hMemory
= LoadResource(hModule
, hResource
);
2580 if (!hMemory
) return 0;
2581 pString
= LockResource(hMemory
);
2583 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2584 idxString
= resId
& 0xf;
2585 while (idxString
--) pString
+= *pString
+ 1;
2587 /* If no buffer is given, return length of the string. */
2588 if (!pwszBuffer
) return *pString
;
2590 /* Else copy over the string, respecting the buffer size. */
2591 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
2592 if (cMaxChars
>= 0) {
2593 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
2594 pwszBuffer
[cMaxChars
] = '\0';
2600 /******************************************************************************
2601 * RegLoadMUIStringW [ADVAPI32.@]
2603 * Load the localized version of a string resource from some PE, respective
2604 * id and path of which are given in the registry value in the format
2605 * @[path]\dllname,-resourceId
2608 * hKey [I] Key, of which to load the string value from.
2609 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2610 * pszBuffer [O] Buffer to store the localized string in.
2611 * cbBuffer [I] Size of the destination buffer in bytes.
2612 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2613 * dwFlags [I] None supported yet.
2614 * pszBaseDir [I] Not supported yet.
2617 * Success: ERROR_SUCCESS,
2618 * Failure: nonzero error code from winerror.h
2621 * This is an API of Windows Vista, which wasn't available at the time this code
2622 * was written. We have to check for the correct behaviour once it's available.
2624 LSTATUS WINAPI
RegLoadMUIStringW(HKEY hKey
, LPCWSTR pwszValue
, LPWSTR pwszBuffer
, DWORD cbBuffer
,
2625 LPDWORD pcbData
, DWORD dwFlags
, LPCWSTR pwszBaseDir
)
2627 DWORD dwValueType
, cbData
;
2628 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
2631 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2632 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey
, debugstr_w(pwszValue
), pwszBuffer
,
2633 cbBuffer
, pcbData
, dwFlags
, debugstr_w(pwszBaseDir
));
2635 /* Parameter sanity checks. */
2636 if (!hKey
|| !pwszBuffer
)
2637 return ERROR_INVALID_PARAMETER
;
2639 if (pwszBaseDir
&& *pwszBaseDir
) {
2640 FIXME("BaseDir parameter not yet supported!\n");
2641 return ERROR_INVALID_PARAMETER
;
2644 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2645 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
2646 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2647 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
) {
2648 result
= ERROR_FILE_NOT_FOUND
;
2651 pwszTempBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2652 if (!pwszTempBuffer
) {
2653 result
= ERROR_NOT_ENOUGH_MEMORY
;
2656 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
2657 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2659 /* Expand environment variables, if appropriate, or copy the original string over. */
2660 if (dwValueType
== REG_EXPAND_SZ
) {
2661 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
2662 if (!cbData
) goto cleanup
;
2663 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2664 if (!pwszExpandedBuffer
) {
2665 result
= ERROR_NOT_ENOUGH_MEMORY
;
2668 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
2670 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2671 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
2674 /* If the value references a resource based string, parse the value and load the string.
2675 * Else just copy over the original value. */
2676 result
= ERROR_SUCCESS
;
2677 if (*pwszExpandedBuffer
!= '@') { /* '@' is the prefix for resource based string entries. */
2678 lstrcpynW(pwszBuffer
, pwszExpandedBuffer
, cbBuffer
/ sizeof(WCHAR
));
2680 WCHAR
*pComma
= strrchrW(pwszExpandedBuffer
, ',');
2684 /* Format of the expanded value is 'path_to_dll,-resId' */
2685 if (!pComma
|| pComma
[1] != '-') {
2686 result
= ERROR_BADKEY
;
2690 uiStringId
= atoiW(pComma
+2);
2693 hModule
= LoadLibraryW(pwszExpandedBuffer
+ 1);
2694 if (!hModule
|| !load_string(hModule
, uiStringId
, pwszBuffer
, cbBuffer
/sizeof(WCHAR
)))
2695 result
= ERROR_BADKEY
;
2696 FreeLibrary(hModule
);
2700 HeapFree(GetProcessHeap(), 0, pwszTempBuffer
);
2701 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer
);
2705 /******************************************************************************
2706 * RegLoadMUIStringA [ADVAPI32.@]
2708 * See RegLoadMUIStringW
2710 LSTATUS WINAPI
RegLoadMUIStringA(HKEY hKey
, LPCSTR pszValue
, LPSTR pszBuffer
, DWORD cbBuffer
,
2711 LPDWORD pcbData
, DWORD dwFlags
, LPCSTR pszBaseDir
)
2713 UNICODE_STRING valueW
, baseDirW
;
2715 DWORD cbData
= cbBuffer
* sizeof(WCHAR
);
2718 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
2719 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
2720 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszBaseDir
) ||
2721 !(pwszBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
)))
2723 result
= ERROR_NOT_ENOUGH_MEMORY
;
2727 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, dwFlags
,
2730 if (result
== ERROR_SUCCESS
) {
2731 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszBuffer
, cbBuffer
, NULL
, NULL
);
2737 HeapFree(GetProcessHeap(), 0, pwszBuffer
);
2738 RtlFreeUnicodeString(&baseDirW
);
2739 RtlFreeUnicodeString(&valueW
);
2744 /******************************************************************************
2745 * RegDisablePredefinedCache [ADVAPI32.@]
2747 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2753 * Success: ERROR_SUCCESS
2754 * Failure: nonzero error code from Winerror.h
2757 * This is useful for services that use impersonation.
2759 LSTATUS WINAPI
RegDisablePredefinedCache(void)
2761 HKEY hkey_current_user
;
2762 int idx
= (UINT_PTR
)HKEY_CURRENT_USER
- (UINT_PTR
)HKEY_SPECIAL_ROOT_FIRST
;
2764 /* prevent caching of future requests */
2765 hkcu_cache_disabled
= TRUE
;
2767 hkey_current_user
= InterlockedExchangePointer( (void **)&special_root_keys
[idx
], NULL
);
2769 if (hkey_current_user
)
2770 NtClose( hkey_current_user
);
2772 return ERROR_SUCCESS
;
2775 /******************************************************************************
2776 * RegDeleteTreeW [ADVAPI32.@]
2779 LSTATUS WINAPI
RegDeleteTreeW(HKEY hKey
, LPCWSTR lpszSubKey
)
2782 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
2783 DWORD dwMaxLen
, dwSize
;
2784 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
2785 HKEY hSubKey
= hKey
;
2787 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
2791 ret
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
2792 if (ret
) return ret
;
2795 /* Get highest length for keys, values */
2796 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
2797 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
2798 if (ret
) goto cleanup
;
2802 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
2803 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
2805 /* Name too big: alloc a buffer for it */
2806 if (!(lpszName
= HeapAlloc( GetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
2808 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2814 /* Recursively delete all the subkeys */
2818 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
2819 NULL
, NULL
, NULL
)) break;
2821 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
2822 if (ret
) goto cleanup
;
2826 ret
= RegDeleteKeyW(hKey
, lpszSubKey
);
2831 if (RegEnumValueW(hKey
, 0, lpszName
, &dwSize
,
2832 NULL
, NULL
, NULL
, NULL
)) break;
2834 ret
= RegDeleteValueW(hKey
, lpszName
);
2835 if (ret
) goto cleanup
;
2839 /* Free buffer if allocated */
2840 if (lpszName
!= szNameBuf
)
2841 HeapFree( GetProcessHeap(), 0, lpszName
);
2843 RegCloseKey(hSubKey
);
2847 /******************************************************************************
2848 * RegDeleteTreeA [ADVAPI32.@]
2851 LSTATUS WINAPI
RegDeleteTreeA(HKEY hKey
, LPCSTR lpszSubKey
)
2854 UNICODE_STRING lpszSubKeyW
;
2856 if (lpszSubKey
) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW
, lpszSubKey
);
2857 else lpszSubKeyW
.Buffer
= NULL
;
2858 ret
= RegDeleteTreeW( hKey
, lpszSubKeyW
.Buffer
);
2859 RtlFreeUnicodeString( &lpszSubKeyW
);