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
33 #define WIN32_NO_STATUS
40 #include "advapi32_misc.h"
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
47 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
48 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
50 static const WCHAR name_CLASSES_ROOT
[] =
51 {'\\','R','e','g','i','s','t','r','y','\\',
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 {'\\','R','e','g','i','s','t','r','y','\\',
57 'M','a','c','h','i','n','e',0};
58 static const WCHAR name_USERS
[] =
59 {'\\','R','e','g','i','s','t','r','y','\\',
61 static const WCHAR name_PERFORMANCE_DATA
[] =
62 {'\\','R','e','g','i','s','t','r','y','\\',
63 'P','e','r','f','D','a','t','a',0};
64 static const WCHAR name_CURRENT_CONFIG
[] =
65 {'\\','R','e','g','i','s','t','r','y','\\',
66 'M','a','c','h','i','n','e','\\',
67 'S','y','s','t','e','m','\\',
68 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
69 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
70 'C','u','r','r','e','n','t',0};
71 static const WCHAR name_DYN_DATA
[] =
72 {'\\','R','e','g','i','s','t','r','y','\\',
73 'D','y','n','D','a','t','a',0};
75 static const WCHAR
* const root_key_names
[] =
78 NULL
, /* HKEY_CURRENT_USER is determined dynamically */
81 name_PERFORMANCE_DATA
,
86 #define NB_SPECIAL_ROOT_KEYS (sizeof(root_key_names)/sizeof(root_key_names[0]))
88 static HKEY special_root_keys
[NB_SPECIAL_ROOT_KEYS
];
89 static BOOL hkcu_cache_disabled
;
91 static const BOOL is_win64
= (sizeof(void *) > sizeof(int));
93 /* check if value type needs string conversion (Ansi<->Unicode) */
94 static inline BOOL
is_string( DWORD type
)
96 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
99 /* check if current version is NT or Win95 */
100 static inline BOOL
is_version_nt(void)
102 return !(GetVersion() & 0x80000000);
105 static BOOL
is_wow6432node( const UNICODE_STRING
*name
)
107 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e'};
109 return (name
->Length
== sizeof(wow6432nodeW
) &&
110 !memicmpW( name
->Buffer
, wow6432nodeW
, sizeof(wow6432nodeW
)/sizeof(WCHAR
) ));
113 /* open the Wow6432Node subkey of the specified key */
114 static HANDLE
open_wow6432node( HANDLE key
)
116 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
117 OBJECT_ATTRIBUTES attr
;
118 UNICODE_STRING nameW
;
121 attr
.Length
= sizeof(attr
);
122 attr
.RootDirectory
= key
;
123 attr
.ObjectName
= &nameW
;
125 attr
.SecurityDescriptor
= NULL
;
126 attr
.SecurityQualityOfService
= NULL
;
127 RtlInitUnicodeString( &nameW
, wow6432nodeW
);
128 if (NtOpenKey( &ret
, MAXIMUM_ALLOWED
, &attr
)) ret
= 0;
132 /* wrapper for NtCreateKey that creates the key recursively if necessary */
133 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
134 const UNICODE_STRING
*class, ULONG options
, PULONG dispos
)
136 BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
137 NTSTATUS status
= STATUS_OBJECT_NAME_NOT_FOUND
;
138 HANDLE subkey
, root
= attr
->RootDirectory
;
140 if (!force_wow32
) status
= NtCreateKey( &subkey
, access
, attr
, 0, class, options
, dispos
);
142 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
144 static const WCHAR registry_root
[] = {'\\','R','e','g','i','s','t','r','y','\\'};
145 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
146 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
149 /* don't try to create registry root */
150 if (!attr
->RootDirectory
&& len
> sizeof(registry_root
)/sizeof(WCHAR
) &&
151 !memicmpW( buffer
, registry_root
, sizeof(registry_root
)/sizeof(WCHAR
)))
152 i
+= sizeof(registry_root
)/sizeof(WCHAR
);
154 while (i
< len
&& buffer
[i
] != '\\') i
++;
155 if (i
== len
&& !force_wow32
) return status
;
157 attrs
= attr
->Attributes
;
158 attr
->ObjectName
= &str
;
162 str
.Buffer
= buffer
+ pos
;
163 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
164 if (force_wow32
&& pos
)
166 if (is_wow6432node( &str
)) force_wow32
= FALSE
;
167 else if ((subkey
= open_wow6432node( attr
->RootDirectory
)))
169 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
170 attr
->RootDirectory
= subkey
;
176 attr
->Attributes
= attrs
;
177 status
= NtCreateKey( &subkey
, access
, attr
, 0, class, options
, dispos
);
181 attr
->Attributes
= attrs
& ~OBJ_OPENLINK
;
182 status
= NtCreateKey( &subkey
, access
, attr
, 0, class,
183 options
& ~REG_OPTION_CREATE_LINK
, dispos
);
185 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
186 if (status
) return status
;
188 attr
->RootDirectory
= subkey
;
189 while (i
< len
&& buffer
[i
] == '\\') i
++;
191 while (i
< len
&& buffer
[i
] != '\\') i
++;
194 attr
->RootDirectory
= subkey
;
195 if (force_wow32
&& (subkey
= open_wow6432node( attr
->RootDirectory
)))
197 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
198 attr
->RootDirectory
= subkey
;
200 *retkey
= attr
->RootDirectory
;
204 /* wrapper for NtOpenKey to handle Wow6432 nodes */
205 static NTSTATUS
open_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
208 BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
209 HANDLE subkey
, root
= attr
->RootDirectory
;
210 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
211 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
214 if (!force_wow32
) return NtOpenKey( (HANDLE
*)retkey
, access
, attr
);
216 if (len
&& buffer
[0] == '\\') return STATUS_OBJECT_PATH_INVALID
;
217 while (i
< len
&& buffer
[i
] != '\\') i
++;
218 attrs
= attr
->Attributes
;
219 attr
->ObjectName
= &str
;
223 str
.Buffer
= buffer
+ pos
;
224 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
225 if (force_wow32
&& pos
)
227 if (is_wow6432node( &str
)) force_wow32
= FALSE
;
228 else if ((subkey
= open_wow6432node( attr
->RootDirectory
)))
230 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
231 attr
->RootDirectory
= subkey
;
237 attr
->Attributes
= attrs
;
238 status
= NtOpenKey( &subkey
, access
, attr
);
242 attr
->Attributes
= attrs
& ~OBJ_OPENLINK
;
243 status
= NtOpenKey( &subkey
, access
, attr
);
245 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
246 if (status
) return status
;
247 attr
->RootDirectory
= subkey
;
249 while (i
< len
&& buffer
[i
] == '\\') i
++;
251 while (i
< len
&& buffer
[i
] != '\\') i
++;
253 if (force_wow32
&& (subkey
= open_wow6432node( attr
->RootDirectory
)))
255 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
256 attr
->RootDirectory
= subkey
;
258 *retkey
= attr
->RootDirectory
;
262 /* create one of the HKEY_* special root keys */
263 static HKEY
create_special_root_hkey( HKEY hkey
, DWORD access
)
266 int idx
= HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
268 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CURRENT_USER
))
270 if (RtlOpenCurrentUser( access
, (HANDLE
*)&hkey
)) return 0;
271 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey
);
273 /* don't cache the key in the table if caching is disabled */
274 if (hkcu_cache_disabled
)
279 OBJECT_ATTRIBUTES attr
;
282 attr
.Length
= sizeof(attr
);
283 attr
.RootDirectory
= 0;
284 attr
.ObjectName
= &name
;
286 attr
.SecurityDescriptor
= NULL
;
287 attr
.SecurityQualityOfService
= NULL
;
288 RtlInitUnicodeString( &name
, root_key_names
[idx
] );
289 if (create_key( &hkey
, access
, &attr
, NULL
, 0, NULL
)) return 0;
290 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
293 if (!(access
& (KEY_WOW64_64KEY
| KEY_WOW64_32KEY
)))
295 if (!(ret
= InterlockedCompareExchangePointer( (void **)&special_root_keys
[idx
], hkey
, 0 )))
298 NtClose( hkey
); /* somebody beat us to it */
305 /* map the hkey from special root to normal key if necessary */
306 static inline HKEY
get_special_root_hkey( HKEY hkey
, REGSAM access
)
310 if ((HandleToUlong(hkey
) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
))
311 && (HandleToUlong(hkey
) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
315 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
))
316 mask
= KEY_WOW64_32KEY
| KEY_WOW64_64KEY
;
318 if ((access
& mask
) ||
319 !(ret
= special_root_keys
[HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
)]))
320 ret
= create_special_root_hkey( hkey
, MAXIMUM_ALLOWED
| (access
& mask
) );
326 /******************************************************************************
327 * RegOverridePredefKey [ADVAPI32.@]
329 LSTATUS WINAPI
RegOverridePredefKey( HKEY hkey
, HKEY override
)
334 TRACE("(%p %p)\n", hkey
, override
);
336 if ((HandleToUlong(hkey
) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
))
337 || (HandleToUlong(hkey
) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
338 return ERROR_INVALID_PARAMETER
;
339 idx
= HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
343 NTSTATUS status
= NtDuplicateObject( GetCurrentProcess(), override
,
344 GetCurrentProcess(), (HANDLE
*)&override
,
345 0, 0, DUPLICATE_SAME_ACCESS
);
346 if (status
) return RtlNtStatusToDosError( status
);
349 old_key
= InterlockedExchangePointer( (void **)&special_root_keys
[idx
], override
);
350 if (old_key
) NtClose( old_key
);
351 return ERROR_SUCCESS
;
355 /******************************************************************************
356 * RegCreateKeyExW [ADVAPI32.@]
358 * See RegCreateKeyExA.
360 LSTATUS WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
361 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
362 PHKEY retkey
, LPDWORD dispos
)
364 OBJECT_ATTRIBUTES attr
;
365 UNICODE_STRING nameW
, classW
;
367 if (reserved
) return ERROR_INVALID_PARAMETER
;
368 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
370 attr
.Length
= sizeof(attr
);
371 attr
.RootDirectory
= hkey
;
372 attr
.ObjectName
= &nameW
;
374 attr
.SecurityDescriptor
= NULL
;
375 attr
.SecurityQualityOfService
= NULL
;
376 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
377 RtlInitUnicodeString( &nameW
, name
);
378 RtlInitUnicodeString( &classW
, class );
380 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
, &classW
, options
, dispos
) );
384 /******************************************************************************
385 * RegCreateKeyExA [ADVAPI32.@]
387 * Open a registry key, creating it if it doesn't exist.
390 * hkey [I] Handle of the parent registry key
391 * name [I] Name of the new key to open or create
392 * reserved [I] Reserved, pass 0
393 * class [I] The object type of the new key
394 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
395 * access [I] Access level desired
396 * sa [I] Security attributes for the key
397 * retkey [O] Destination for the resulting handle
398 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
401 * Success: ERROR_SUCCESS.
402 * Failure: A standard Win32 error code. retkey remains untouched.
405 * MAXIMUM_ALLOWED in access mask not supported by server
407 LSTATUS WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
408 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
409 PHKEY retkey
, LPDWORD dispos
)
411 OBJECT_ATTRIBUTES attr
;
412 UNICODE_STRING classW
;
413 ANSI_STRING nameA
, classA
;
416 if (reserved
) return ERROR_INVALID_PARAMETER
;
417 if (!is_version_nt())
419 access
= MAXIMUM_ALLOWED
; /* Win95 ignores the access mask */
420 if (name
&& *name
== '\\') name
++; /* win9x,ME ignores one (and only one) beginning backslash */
422 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
424 attr
.Length
= sizeof(attr
);
425 attr
.RootDirectory
= hkey
;
426 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
428 attr
.SecurityDescriptor
= NULL
;
429 attr
.SecurityQualityOfService
= NULL
;
430 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
431 RtlInitAnsiString( &nameA
, name
);
432 RtlInitAnsiString( &classA
, class );
434 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
437 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
439 status
= create_key( retkey
, access
, &attr
, &classW
, options
, dispos
);
440 RtlFreeUnicodeString( &classW
);
443 return RtlNtStatusToDosError( status
);
447 /******************************************************************************
448 * RegCreateKeyW [ADVAPI32.@]
450 * Creates the specified reg key.
453 * hKey [I] Handle to an open key.
454 * lpSubKey [I] Name of a key that will be opened or created.
455 * phkResult [O] Receives a handle to the opened or created key.
458 * Success: ERROR_SUCCESS
459 * Failure: nonzero error code defined in Winerror.h
461 LSTATUS WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpSubKey
, PHKEY phkResult
)
463 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
464 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
465 return RegCreateKeyExW( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
466 MAXIMUM_ALLOWED
, NULL
, phkResult
, NULL
);
470 /******************************************************************************
471 * RegCreateKeyA [ADVAPI32.@]
475 LSTATUS WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpSubKey
, PHKEY phkResult
)
477 return RegCreateKeyExA( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
478 MAXIMUM_ALLOWED
, NULL
, phkResult
, NULL
);
483 /******************************************************************************
484 * RegOpenKeyExW [ADVAPI32.@]
488 LSTATUS WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD options
, REGSAM access
, PHKEY retkey
)
490 OBJECT_ATTRIBUTES attr
;
491 UNICODE_STRING nameW
;
493 if (retkey
&& (!name
|| !name
[0]) &&
494 (HandleToUlong(hkey
) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
)) &&
495 (HandleToUlong(hkey
) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
498 return ERROR_SUCCESS
;
501 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
502 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
) && name
&& *name
== '\\') name
++;
504 if (!retkey
) return ERROR_INVALID_PARAMETER
;
505 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
507 attr
.Length
= sizeof(attr
);
508 attr
.RootDirectory
= hkey
;
509 attr
.ObjectName
= &nameW
;
511 attr
.SecurityDescriptor
= NULL
;
512 attr
.SecurityQualityOfService
= NULL
;
513 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
514 RtlInitUnicodeString( &nameW
, name
);
515 return RtlNtStatusToDosError( open_key( retkey
, access
, &attr
) );
519 /******************************************************************************
520 * RegOpenKeyExA [ADVAPI32.@]
522 * Open a registry key.
525 * hkey [I] Handle of open key
526 * name [I] Name of subkey to open
527 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
528 * access [I] Security access mask
529 * retkey [O] Handle to open key
532 * Success: ERROR_SUCCESS
533 * Failure: A standard Win32 error code. retkey is set to 0.
536 * Unlike RegCreateKeyExA(), this function will not create the key if it
539 LSTATUS WINAPI DECLSPEC_HOTPATCH
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD options
, REGSAM access
, PHKEY retkey
)
541 OBJECT_ATTRIBUTES attr
;
545 if (retkey
&& (!name
|| !name
[0]) &&
546 (HandleToUlong(hkey
) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
)) &&
547 (HandleToUlong(hkey
) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
550 return ERROR_SUCCESS
;
553 if (!is_version_nt()) access
= MAXIMUM_ALLOWED
; /* Win95 ignores the access mask */
556 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
557 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
) && name
&& *name
== '\\') name
++;
560 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
562 attr
.Length
= sizeof(attr
);
563 attr
.RootDirectory
= hkey
;
564 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
566 attr
.SecurityDescriptor
= NULL
;
567 attr
.SecurityQualityOfService
= NULL
;
568 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
570 RtlInitAnsiString( &nameA
, name
);
571 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
574 status
= open_key( retkey
, access
, &attr
);
576 return RtlNtStatusToDosError( status
);
580 /******************************************************************************
581 * RegOpenKeyW [ADVAPI32.@]
585 LSTATUS WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, PHKEY retkey
)
588 return ERROR_INVALID_PARAMETER
;
593 return ERROR_SUCCESS
;
595 return RegOpenKeyExW( hkey
, name
, 0, MAXIMUM_ALLOWED
, retkey
);
599 /******************************************************************************
600 * RegOpenKeyA [ADVAPI32.@]
602 * Open a registry key.
605 * hkey [I] Handle of parent key to open the new key under
606 * name [I] Name of the key under hkey to open
607 * retkey [O] Destination for the resulting Handle
610 * Success: ERROR_SUCCESS
611 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
613 LSTATUS WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, PHKEY retkey
)
616 return ERROR_INVALID_PARAMETER
;
621 return ERROR_SUCCESS
;
623 return RegOpenKeyExA( hkey
, name
, 0, MAXIMUM_ALLOWED
, retkey
);
627 /******************************************************************************
628 * RegOpenCurrentUser [ADVAPI32.@]
630 * Get a handle to the HKEY_CURRENT_USER key for the user
631 * the current thread is impersonating.
634 * access [I] Desired access rights to the key
635 * retkey [O] Handle to the opened key
638 * Success: ERROR_SUCCESS
639 * Failure: nonzero error code from Winerror.h
642 * This function is supposed to retrieve a handle to the
643 * HKEY_CURRENT_USER for the user the current thread is impersonating.
644 * Since Wine does not currently allow threads to impersonate other users,
645 * this stub should work fine.
647 LSTATUS WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
649 return RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
654 /******************************************************************************
655 * RegEnumKeyExW [ADVAPI32.@]
657 * Enumerate subkeys of the specified open registry key.
660 * hkey [I] Handle to key to enumerate
661 * index [I] Index of subkey to enumerate
662 * name [O] Buffer for subkey name
663 * name_len [O] Size of subkey buffer
664 * reserved [I] Reserved
665 * class [O] Buffer for class string
666 * class_len [O] Size of class buffer
667 * ft [O] Time key last written to
670 * Success: ERROR_SUCCESS
671 * Failure: System error code. If there are no more subkeys available, the
672 * function returns ERROR_NO_MORE_ITEMS.
674 LSTATUS WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
675 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
678 char buffer
[256], *buf_ptr
= buffer
;
679 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
682 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
683 name_len
? *name_len
: 0, reserved
, class, class_len
, ft
);
685 if (reserved
) return ERROR_INVALID_PARAMETER
;
686 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
688 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
689 buffer
, sizeof(buffer
), &total_size
);
691 while (status
== STATUS_BUFFER_OVERFLOW
)
693 /* retry with a dynamically allocated buffer */
694 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
695 if (!(buf_ptr
= heap_alloc( total_size
)))
696 return ERROR_NOT_ENOUGH_MEMORY
;
697 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
698 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
699 buf_ptr
, total_size
, &total_size
);
704 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
705 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
707 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
709 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
710 status
= STATUS_BUFFER_OVERFLOW
;
714 memcpy( name
, info
->Name
, info
->NameLength
);
718 *class_len
= cls_len
;
721 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
728 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
729 return RtlNtStatusToDosError( status
);
733 /******************************************************************************
734 * RegEnumKeyExA [ADVAPI32.@]
738 LSTATUS WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
739 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
742 char buffer
[256], *buf_ptr
= buffer
;
743 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
746 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
747 name_len
? *name_len
: 0, reserved
, class, class_len
, ft
);
749 if (reserved
) return ERROR_INVALID_PARAMETER
;
750 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
752 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
753 buffer
, sizeof(buffer
), &total_size
);
755 while (status
== STATUS_BUFFER_OVERFLOW
)
757 /* retry with a dynamically allocated buffer */
758 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
759 if (!(buf_ptr
= heap_alloc( total_size
)))
760 return ERROR_NOT_ENOUGH_MEMORY
;
761 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
762 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
763 buf_ptr
, total_size
, &total_size
);
770 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
771 RtlUnicodeToMultiByteSize( &cls_len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
773 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
775 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
776 status
= STATUS_BUFFER_OVERFLOW
;
780 RtlUnicodeToMultiByteN( name
, len
, NULL
, info
->Name
, info
->NameLength
);
784 *class_len
= cls_len
;
787 RtlUnicodeToMultiByteN( class, cls_len
, NULL
,
788 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
796 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
797 return RtlNtStatusToDosError( status
);
801 /******************************************************************************
802 * RegEnumKeyW [ADVAPI32.@]
804 * Enumerates subkeys of the specified open reg key.
807 * hKey [I] Handle to an open key.
808 * dwIndex [I] Index of the subkey of hKey to retrieve.
809 * lpName [O] Name of the subkey.
810 * cchName [I] Size of lpName in TCHARS.
813 * Success: ERROR_SUCCESS
814 * Failure: system error code. If there are no more subkeys available, the
815 * function returns ERROR_NO_MORE_ITEMS.
817 LSTATUS WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
819 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
823 /******************************************************************************
824 * RegEnumKeyA [ADVAPI32.@]
828 LSTATUS WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
830 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
834 /******************************************************************************
835 * RegQueryInfoKeyW [ADVAPI32.@]
837 * Retrieves information about the specified registry key.
840 * hkey [I] Handle to key to query
841 * class [O] Buffer for class string
842 * class_len [O] Size of class string buffer
843 * reserved [I] Reserved
844 * subkeys [O] Buffer for number of subkeys
845 * max_subkey [O] Buffer for longest subkey name length
846 * max_class [O] Buffer for longest class string length
847 * values [O] Buffer for number of value entries
848 * max_value [O] Buffer for longest value name length
849 * max_data [O] Buffer for longest value data length
850 * security [O] Buffer for security descriptor length
851 * modif [O] Modification time
854 * Success: ERROR_SUCCESS
855 * Failure: system error code.
858 * - win95 allows class to be valid and class_len to be NULL
859 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
860 * - both allow class to be NULL and class_len to be NULL
861 * (it's hard to test validity, so test !NULL instead)
863 LSTATUS WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
864 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
865 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
866 LPDWORD security
, FILETIME
*modif
)
869 char buffer
[256], *buf_ptr
= buffer
;
870 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
873 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
874 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
876 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
877 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
879 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
880 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
882 if (class && class_len
&& *class_len
)
884 /* retry with a dynamically allocated buffer */
885 while (status
== STATUS_BUFFER_OVERFLOW
)
887 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
888 if (!(buf_ptr
= heap_alloc( total_size
)))
889 return ERROR_NOT_ENOUGH_MEMORY
;
890 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
891 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
894 if (status
) goto done
;
896 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
898 status
= STATUS_BUFFER_TOO_SMALL
;
902 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
903 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
906 else status
= STATUS_SUCCESS
;
908 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
909 if (subkeys
) *subkeys
= info
->SubKeys
;
910 if (max_subkey
) *max_subkey
= info
->MaxNameLen
/ sizeof(WCHAR
);
911 if (max_class
) *max_class
= info
->MaxClassLen
/ sizeof(WCHAR
);
912 if (values
) *values
= info
->Values
;
913 if (max_value
) *max_value
= info
->MaxValueNameLen
/ sizeof(WCHAR
);
914 if (max_data
) *max_data
= info
->MaxValueDataLen
;
915 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
919 FIXME( "security argument not supported.\n");
924 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
925 return RtlNtStatusToDosError( status
);
929 /******************************************************************************
930 * RegQueryMultipleValuesA [ADVAPI32.@]
932 * Retrieves the type and data for a list of value names associated with a key.
935 * hKey [I] Handle to an open key.
936 * val_list [O] Array of VALENT structures that describes the entries.
937 * num_vals [I] Number of elements in val_list.
938 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
939 * ldwTotsize [I/O] Size of lpValueBuf.
942 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
943 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
946 LSTATUS WINAPI
RegQueryMultipleValuesA( HKEY hkey
, PVALENTA val_list
, DWORD num_vals
,
947 LPSTR lpValueBuf
, LPDWORD ldwTotsize
)
950 DWORD maxBytes
= *ldwTotsize
;
952 LPSTR bufptr
= lpValueBuf
;
955 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
957 for(i
=0; i
< num_vals
; ++i
)
960 val_list
[i
].ve_valuelen
=0;
961 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
962 if(status
!= ERROR_SUCCESS
)
967 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
969 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
970 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
971 if(status
!= ERROR_SUCCESS
)
976 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
978 bufptr
+= val_list
[i
].ve_valuelen
;
981 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
983 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
987 /******************************************************************************
988 * RegQueryMultipleValuesW [ADVAPI32.@]
990 * See RegQueryMultipleValuesA.
992 LSTATUS WINAPI
RegQueryMultipleValuesW( HKEY hkey
, PVALENTW val_list
, DWORD num_vals
,
993 LPWSTR lpValueBuf
, LPDWORD ldwTotsize
)
996 DWORD maxBytes
= *ldwTotsize
;
998 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
1001 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
1003 for(i
=0; i
< num_vals
; ++i
)
1005 val_list
[i
].ve_valuelen
=0;
1006 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
1007 if(status
!= ERROR_SUCCESS
)
1012 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
1014 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
1015 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
1016 if(status
!= ERROR_SUCCESS
)
1021 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
1023 bufptr
+= val_list
[i
].ve_valuelen
;
1026 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
1028 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
1031 /******************************************************************************
1032 * RegQueryInfoKeyA [ADVAPI32.@]
1034 * Retrieves information about a registry key.
1037 * hKey [I] Handle to an open key.
1038 * lpClass [O] Class string of the key.
1039 * lpcClass [I/O] size of lpClass.
1040 * lpReserved [I] Reserved; must be NULL.
1041 * lpcSubKeys [O] Number of subkeys contained by the key.
1042 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
1043 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
1045 * lpcValues [O] Number of values associated with the key.
1046 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
1047 * lpcMaxValueLen [O] Longest data component among the key's values
1048 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
1049 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
1052 * Success: ERROR_SUCCESS
1053 * Failure: nonzero error code from Winerror.h
1055 LSTATUS WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
1056 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
1057 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
1058 LPDWORD security
, FILETIME
*modif
)
1061 char buffer
[256], *buf_ptr
= buffer
;
1062 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
1063 DWORD total_size
, len
;
1065 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
1066 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
1068 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
1069 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1071 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
1072 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1074 if (class || class_len
)
1076 /* retry with a dynamically allocated buffer */
1077 while (status
== STATUS_BUFFER_OVERFLOW
)
1079 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1080 if (!(buf_ptr
= heap_alloc( total_size
)))
1081 return ERROR_NOT_ENOUGH_MEMORY
;
1082 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
1083 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
1086 if (status
) goto done
;
1089 if (class && class_len
) len
= *class_len
;
1090 RtlUnicodeToMultiByteN( class, len
, class_len
,
1091 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
), info
->ClassLength
);
1095 if (*class_len
+ 1 > len
)
1097 status
= STATUS_BUFFER_OVERFLOW
;
1102 else status
= STATUS_SUCCESS
;
1104 if (subkeys
) *subkeys
= info
->SubKeys
;
1105 if (max_subkey
) *max_subkey
= info
->MaxNameLen
/ sizeof(WCHAR
);
1106 if (max_class
) *max_class
= info
->MaxClassLen
/ sizeof(WCHAR
);
1107 if (values
) *values
= info
->Values
;
1108 if (max_value
) *max_value
= info
->MaxValueNameLen
/ sizeof(WCHAR
);
1109 if (max_data
) *max_data
= info
->MaxValueDataLen
;
1110 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
1114 FIXME( "security argument not supported.\n");
1119 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1120 return RtlNtStatusToDosError( status
);
1124 /******************************************************************************
1125 * RegCloseKey [ADVAPI32.@]
1127 * Close an open registry key.
1130 * hkey [I] Handle of key to close
1133 * Success: ERROR_SUCCESS
1134 * Failure: Error code
1136 LSTATUS WINAPI DECLSPEC_HOTPATCH
RegCloseKey( HKEY hkey
)
1138 if (!hkey
) return ERROR_INVALID_HANDLE
;
1139 if (hkey
>= (HKEY
)0x80000000) return ERROR_SUCCESS
;
1140 return RtlNtStatusToDosError( NtClose( hkey
) );
1144 /******************************************************************************
1145 * RegDeleteKeyExW [ADVAPI32.@]
1147 LSTATUS WINAPI
RegDeleteKeyExW( HKEY hkey
, LPCWSTR name
, REGSAM access
, DWORD reserved
)
1152 if (!name
) return ERROR_INVALID_PARAMETER
;
1154 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
1156 access
&= KEY_WOW64_64KEY
| KEY_WOW64_32KEY
;
1157 if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, access
| DELETE
, &tmp
)))
1159 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
1162 TRACE("%s ret=%08x\n", debugstr_w(name
), ret
);
1167 /******************************************************************************
1168 * RegDeleteKeyW [ADVAPI32.@]
1170 * See RegDeleteKeyA.
1172 LSTATUS WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
1174 return RegDeleteKeyExW( hkey
, name
, 0, 0 );
1178 /******************************************************************************
1179 * RegDeleteKeyExA [ADVAPI32.@]
1181 LSTATUS WINAPI
RegDeleteKeyExA( HKEY hkey
, LPCSTR name
, REGSAM access
, DWORD reserved
)
1186 if (!name
) return ERROR_INVALID_PARAMETER
;
1188 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
1190 access
&= KEY_WOW64_64KEY
| KEY_WOW64_32KEY
;
1191 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, access
| DELETE
, &tmp
)))
1193 if (!is_version_nt()) /* win95 does recursive key deletes */
1197 while(!RegEnumKeyA(tmp
, 0, sub
, sizeof(sub
)))
1199 if(RegDeleteKeyExA(tmp
, sub
, access
, reserved
)) /* recurse */
1203 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
1206 TRACE("%s ret=%08x\n", debugstr_a(name
), ret
);
1211 /******************************************************************************
1212 * RegDeleteKeyA [ADVAPI32.@]
1214 * Delete a registry key.
1217 * hkey [I] Handle to parent key containing the key to delete
1218 * name [I] Name of the key user hkey to delete
1222 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1223 * right. In reality, it opens a new handle with DELETE access.
1226 * Success: ERROR_SUCCESS
1227 * Failure: Error code
1229 LSTATUS WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
1231 return RegDeleteKeyExA( hkey
, name
, 0, 0 );
1236 /******************************************************************************
1237 * RegSetValueExW [ADVAPI32.@]
1239 * Set the data and contents of a registry value.
1242 * hkey [I] Handle of key to set value for
1243 * name [I] Name of value to set
1244 * reserved [I] Reserved, must be zero
1245 * type [I] Type of the value being set
1246 * data [I] The new contents of the value to set
1247 * count [I] Size of data
1250 * Success: ERROR_SUCCESS
1251 * Failure: Error code
1253 LSTATUS WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
1254 DWORD type
, const BYTE
*data
, DWORD count
)
1256 UNICODE_STRING nameW
;
1258 /* no need for version check, not implemented on win9x anyway */
1260 if ((data
&& ((ULONG_PTR
)data
>> 16) == 0) || (!data
&& count
)) return ERROR_NOACCESS
;
1262 if (count
&& is_string(type
))
1264 LPCWSTR str
= (LPCWSTR
)data
;
1265 /* if user forgot to count terminating null, add it (yes NT does this) */
1266 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
1267 count
+= sizeof(WCHAR
);
1269 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1271 RtlInitUnicodeString( &nameW
, name
);
1272 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
1276 /******************************************************************************
1277 * RegSetValueExA [ADVAPI32.@]
1279 * See RegSetValueExW.
1282 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1283 * NT does definitely care (aj)
1285 LSTATUS WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1286 const BYTE
*data
, DWORD count
)
1289 UNICODE_STRING nameW
;
1290 WCHAR
*dataW
= NULL
;
1293 if (!is_version_nt()) /* win95 */
1297 if (!data
) return ERROR_INVALID_PARAMETER
;
1298 count
= strlen((const char *)data
) + 1;
1301 else if (count
&& is_string(type
))
1303 /* if user forgot to count terminating null, add it (yes NT does this) */
1304 if (data
[count
-1] && !data
[count
]) count
++;
1307 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1309 if (is_string( type
)) /* need to convert to Unicode */
1312 RtlMultiByteToUnicodeSize( &lenW
, (const char *)data
, count
);
1313 if (!(dataW
= heap_alloc( lenW
))) return ERROR_OUTOFMEMORY
;
1314 RtlMultiByteToUnicodeN( dataW
, lenW
, NULL
, (const char *)data
, count
);
1316 data
= (BYTE
*)dataW
;
1319 RtlInitAnsiString( &nameA
, name
);
1320 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1322 status
= NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
);
1323 RtlFreeUnicodeString( &nameW
);
1326 return RtlNtStatusToDosError( status
);
1330 /******************************************************************************
1331 * RegSetValueW [ADVAPI32.@]
1333 * Sets the data for the default or unnamed value of a reg key.
1336 * hkey [I] Handle to an open key.
1337 * subkey [I] Name of a subkey of hKey.
1338 * type [I] Type of information to store.
1339 * data [I] String that contains the data to set for the default value.
1340 * count [I] Ignored.
1343 * Success: ERROR_SUCCESS
1344 * Failure: nonzero error code from Winerror.h
1346 LSTATUS WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR subkey
, DWORD type
, LPCWSTR data
, DWORD count
)
1348 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_w(subkey
), type
, debugstr_w(data
), count
);
1350 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1352 return RegSetKeyValueW( hkey
, subkey
, NULL
, type
, data
, (strlenW(data
) + 1)*sizeof(WCHAR
) );
1355 /******************************************************************************
1356 * RegSetValueA [ADVAPI32.@]
1360 LSTATUS WINAPI
RegSetValueA( HKEY hkey
, LPCSTR subkey
, DWORD type
, LPCSTR data
, DWORD count
)
1362 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_a(subkey
), type
, debugstr_a(data
), count
);
1364 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1366 return RegSetKeyValueA( hkey
, subkey
, NULL
, type
, data
, strlen(data
) + 1 );
1369 /******************************************************************************
1370 * RegSetKeyValueW [ADVAPI32.@]
1372 LONG WINAPI
RegSetKeyValueW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR name
, DWORD type
, const void *data
, DWORD len
)
1374 HKEY hsubkey
= NULL
;
1377 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey
, debugstr_w(subkey
), debugstr_w(name
), type
, data
, len
);
1379 if (subkey
&& subkey
[0]) /* need to create the subkey */
1381 if ((ret
= RegCreateKeyW( hkey
, subkey
, &hsubkey
)) != ERROR_SUCCESS
) return ret
;
1385 ret
= RegSetValueExW( hkey
, name
, 0, type
, (const BYTE
*)data
, len
);
1386 if (hsubkey
) RegCloseKey( hsubkey
);
1390 /******************************************************************************
1391 * RegSetKeyValueA [ADVAPI32.@]
1393 LONG WINAPI
RegSetKeyValueA( HKEY hkey
, LPCSTR subkey
, LPCSTR name
, DWORD type
, const void *data
, DWORD len
)
1395 HKEY hsubkey
= NULL
;
1398 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey
, debugstr_a(subkey
), debugstr_a(name
), type
, data
, len
);
1400 if (subkey
&& subkey
[0]) /* need to create the subkey */
1402 if ((ret
= RegCreateKeyA( hkey
, subkey
, &hsubkey
)) != ERROR_SUCCESS
) return ret
;
1406 ret
= RegSetValueExA( hkey
, name
, 0, type
, (const BYTE
*)data
, len
);
1407 if (hsubkey
) RegCloseKey( hsubkey
);
1411 /******************************************************************************
1412 * RegQueryValueExW [ADVAPI32.@]
1414 * See RegQueryValueExA.
1416 LSTATUS WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
1417 LPBYTE data
, LPDWORD count
)
1420 UNICODE_STRING name_str
;
1422 char buffer
[256], *buf_ptr
= buffer
;
1423 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1424 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1426 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1427 hkey
, debugstr_w(name
), reserved
, type
, data
, count
,
1428 (count
&& data
) ? *count
: 0 );
1430 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1431 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1433 RtlInitUnicodeString( &name_str
, name
);
1435 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
1438 total_size
= info_size
;
1439 if (count
) *count
= 0;
1442 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1443 buffer
, total_size
, &total_size
);
1444 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1448 /* retry with a dynamically allocated buffer */
1449 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
1451 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1452 if (!(buf_ptr
= heap_alloc( total_size
)))
1453 return ERROR_NOT_ENOUGH_MEMORY
;
1454 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1455 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1456 buf_ptr
, total_size
, &total_size
);
1461 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1462 /* if the type is REG_SZ and data is not 0-terminated
1463 * and there is enough space in the buffer NT appends a \0 */
1464 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1466 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
1467 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1470 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1472 else status
= STATUS_SUCCESS
;
1474 if (type
) *type
= info
->Type
;
1475 if (count
) *count
= total_size
- info_size
;
1478 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1479 return RtlNtStatusToDosError(status
);
1483 /******************************************************************************
1484 * RegQueryValueExA [ADVAPI32.@]
1486 * Get the type and contents of a specified value under with a key.
1489 * hkey [I] Handle of the key to query
1490 * name [I] Name of value under hkey to query
1491 * reserved [I] Reserved - must be NULL
1492 * type [O] Destination for the value type, or NULL if not required
1493 * data [O] Destination for the values contents, or NULL if not required
1494 * count [I/O] Size of data, updated with the number of bytes returned
1497 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1498 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1499 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1500 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1503 * MSDN states that if data is too small it is partially filled. In reality
1504 * it remains untouched.
1506 LSTATUS WINAPI DECLSPEC_HOTPATCH
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
,
1507 LPDWORD type
, LPBYTE data
, LPDWORD count
)
1511 UNICODE_STRING nameW
;
1512 DWORD total_size
, datalen
= 0;
1513 char buffer
[256], *buf_ptr
= buffer
;
1514 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1515 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1517 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1518 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
1520 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1521 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1523 if (count
) datalen
= *count
;
1524 if (!data
&& count
) *count
= 0;
1526 /* this matches Win9x behaviour - NT sets *type to a random value */
1527 if (type
) *type
= REG_NONE
;
1529 RtlInitAnsiString( &nameA
, name
);
1530 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1531 return RtlNtStatusToDosError(status
);
1533 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1534 buffer
, sizeof(buffer
), &total_size
);
1535 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1537 /* we need to fetch the contents for a string type even if not requested,
1538 * because we need to compute the length of the ASCII string. */
1539 if (data
|| is_string(info
->Type
))
1541 /* retry with a dynamically allocated buffer */
1542 while (status
== STATUS_BUFFER_OVERFLOW
)
1544 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1545 if (!(buf_ptr
= heap_alloc( total_size
)))
1547 status
= STATUS_NO_MEMORY
;
1550 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1551 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1552 buf_ptr
, total_size
, &total_size
);
1555 if (status
) goto done
;
1557 if (is_string(info
->Type
))
1561 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
1562 total_size
- info_size
);
1565 if (len
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1568 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
1569 total_size
- info_size
);
1570 /* if the type is REG_SZ and data is not 0-terminated
1571 * and there is enough space in the buffer NT appends a \0 */
1572 if (len
< datalen
&& data
[len
-1]) data
[len
] = 0;
1575 total_size
= len
+ info_size
;
1579 if (total_size
- info_size
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1580 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1583 else status
= STATUS_SUCCESS
;
1585 if (type
) *type
= info
->Type
;
1586 if (count
) *count
= total_size
- info_size
;
1589 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1590 RtlFreeUnicodeString( &nameW
);
1591 return RtlNtStatusToDosError(status
);
1595 /******************************************************************************
1596 * RegQueryValueW [ADVAPI32.@]
1598 * Retrieves the data associated with the default or unnamed value of a key.
1601 * hkey [I] Handle to an open key.
1602 * name [I] Name of the subkey of hKey.
1603 * data [O] Receives the string associated with the default value
1605 * count [I/O] Size of lpValue in bytes.
1608 * Success: ERROR_SUCCESS
1609 * Failure: nonzero error code from Winerror.h
1611 LSTATUS WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
1616 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
1618 if (name
&& name
[0])
1620 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1622 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1623 if (subkey
!= hkey
) RegCloseKey( subkey
);
1624 if (ret
== ERROR_FILE_NOT_FOUND
)
1626 /* return empty string if default value not found */
1627 if (data
) *data
= 0;
1628 if (count
) *count
= sizeof(WCHAR
);
1629 ret
= ERROR_SUCCESS
;
1635 /******************************************************************************
1636 * RegQueryValueA [ADVAPI32.@]
1638 * See RegQueryValueW.
1640 LSTATUS WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
1645 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
1647 if (name
&& name
[0])
1649 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1651 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1652 if (subkey
!= hkey
) RegCloseKey( subkey
);
1653 if (ret
== ERROR_FILE_NOT_FOUND
)
1655 /* return empty string if default value not found */
1656 if (data
) *data
= 0;
1657 if (count
) *count
= 1;
1658 ret
= ERROR_SUCCESS
;
1664 /******************************************************************************
1665 * ADVAPI_ApplyRestrictions [internal]
1667 * Helper function for RegGetValueA/W.
1669 static VOID
ADVAPI_ApplyRestrictions( DWORD dwFlags
, DWORD dwType
,
1670 DWORD cbData
, PLONG ret
)
1672 /* Check if the type is restricted by the passed flags */
1673 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1679 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1680 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1681 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1682 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1683 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1684 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1685 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1688 if (dwFlags
& dwMask
)
1690 /* Type is not restricted, check for size mismatch */
1691 if (dwType
== REG_BINARY
)
1695 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
1697 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
1700 if (cbExpect
&& cbData
!= cbExpect
)
1701 *ret
= ERROR_DATATYPE_MISMATCH
;
1704 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1709 /******************************************************************************
1710 * RegGetValueW [ADVAPI32.@]
1712 * Retrieves the type and data for a value name associated with a key,
1713 * optionally expanding its content and restricting its type.
1716 * hKey [I] Handle to an open key.
1717 * pszSubKey [I] Name of the subkey of hKey.
1718 * pszValue [I] Name of value under hKey/szSubKey to query.
1719 * dwFlags [I] Flags restricting the value type to retrieve.
1720 * pdwType [O] Destination for the values type, may be NULL.
1721 * pvData [O] Destination for the values content, may be NULL.
1722 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1723 * retrieve the whole content, including the trailing '\0'
1727 * Success: ERROR_SUCCESS
1728 * Failure: nonzero error code from Winerror.h
1731 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1732 * expanded and pdwType is set to REG_SZ instead.
1733 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1734 * without RRF_NOEXPAND is thus not allowed.
1735 * An exception is the case where RRF_RT_ANY is specified, because then
1736 * RRF_NOEXPAND is allowed.
1738 LSTATUS WINAPI
RegGetValueW( HKEY hKey
, LPCWSTR pszSubKey
, LPCWSTR pszValue
,
1739 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1742 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1746 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1747 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1748 pvData
, pcbData
, cbData
);
1750 if (pvData
&& !pcbData
)
1751 return ERROR_INVALID_PARAMETER
;
1752 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1753 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1754 return ERROR_INVALID_PARAMETER
;
1756 if (pszSubKey
&& pszSubKey
[0])
1758 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1759 if (ret
!= ERROR_SUCCESS
) return ret
;
1762 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1764 /* If we are going to expand we need to read in the whole the value even
1765 * if the passed buffer was too small as the expanded string might be
1766 * smaller than the unexpanded one and could fit into cbData bytes. */
1767 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1768 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1773 pvBuf
= heap_alloc(cbData
);
1776 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1780 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1781 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
1782 &dwType
, pvBuf
, &cbData
);
1785 /* Even if cbData was large enough we have to copy the
1786 * string since ExpandEnvironmentStrings can't handle
1787 * overlapping buffers. */
1788 CopyMemory(pvBuf
, pvData
, cbData
);
1791 /* Both the type or the value itself could have been modified in
1792 * between so we have to keep retrying until the buffer is large
1793 * enough or we no longer have to expand the value. */
1794 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1796 if (ret
== ERROR_SUCCESS
)
1798 /* Recheck dwType in case it changed since the first call */
1799 if (dwType
== REG_EXPAND_SZ
)
1801 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
1802 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
1804 if(pvData
&& pcbData
&& cbData
> *pcbData
)
1805 ret
= ERROR_MORE_DATA
;
1808 CopyMemory(pvData
, pvBuf
, *pcbData
);
1814 if (pszSubKey
&& pszSubKey
[0])
1817 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1819 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1820 ZeroMemory(pvData
, *pcbData
);
1822 if (pdwType
) *pdwType
= dwType
;
1823 if (pcbData
) *pcbData
= cbData
;
1829 /******************************************************************************
1830 * RegGetValueA [ADVAPI32.@]
1834 LSTATUS WINAPI
RegGetValueA( HKEY hKey
, LPCSTR pszSubKey
, LPCSTR pszValue
,
1835 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1838 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1842 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1843 hKey
, debugstr_a(pszSubKey
), debugstr_a(pszValue
), dwFlags
,
1844 pdwType
, pvData
, pcbData
, cbData
);
1846 if (pvData
&& !pcbData
)
1847 return ERROR_INVALID_PARAMETER
;
1848 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1849 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1850 return ERROR_INVALID_PARAMETER
;
1852 if (pszSubKey
&& pszSubKey
[0])
1854 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1855 if (ret
!= ERROR_SUCCESS
) return ret
;
1858 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1860 /* If we are going to expand we need to read in the whole the value even
1861 * if the passed buffer was too small as the expanded string might be
1862 * smaller than the unexpanded one and could fit into cbData bytes. */
1863 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1864 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1869 pvBuf
= heap_alloc(cbData
);
1872 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1876 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1877 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
1878 &dwType
, pvBuf
, &cbData
);
1881 /* Even if cbData was large enough we have to copy the
1882 * string since ExpandEnvironmentStrings can't handle
1883 * overlapping buffers. */
1884 CopyMemory(pvBuf
, pvData
, cbData
);
1887 /* Both the type or the value itself could have been modified in
1888 * between so we have to keep retrying until the buffer is large
1889 * enough or we no longer have to expand the value. */
1890 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1892 if (ret
== ERROR_SUCCESS
)
1894 /* Recheck dwType in case it changed since the first call */
1895 if (dwType
== REG_EXPAND_SZ
)
1897 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
1898 pcbData
? *pcbData
: 0);
1900 if(pvData
&& pcbData
&& cbData
> *pcbData
)
1901 ret
= ERROR_MORE_DATA
;
1904 CopyMemory(pvData
, pvBuf
, *pcbData
);
1910 if (pszSubKey
&& pszSubKey
[0])
1913 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1915 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1916 ZeroMemory(pvData
, *pcbData
);
1918 if (pdwType
) *pdwType
= dwType
;
1919 if (pcbData
) *pcbData
= cbData
;
1925 /******************************************************************************
1926 * RegEnumValueW [ADVAPI32.@]
1928 * Enumerates the values for the specified open registry key.
1931 * hkey [I] Handle to key to query
1932 * index [I] Index of value to query
1933 * value [O] Value string
1934 * val_count [I/O] Size of value buffer (in wchars)
1935 * reserved [I] Reserved
1936 * type [O] Type code
1937 * data [O] Value data
1938 * count [I/O] Size of data buffer (in bytes)
1941 * Success: ERROR_SUCCESS
1942 * Failure: nonzero error code from Winerror.h
1945 LSTATUS WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
1946 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1950 char buffer
[256], *buf_ptr
= buffer
;
1951 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1952 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1954 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1955 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1957 if ((data
&& !count
) || reserved
|| !value
|| !val_count
)
1958 return ERROR_INVALID_PARAMETER
;
1959 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1961 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1962 if (data
) total_size
+= *count
;
1963 total_size
= min( sizeof(buffer
), total_size
);
1965 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1966 buffer
, total_size
, &total_size
);
1968 /* retry with a dynamically allocated buffer */
1969 while (status
== STATUS_BUFFER_OVERFLOW
)
1971 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1972 if (!(buf_ptr
= heap_alloc( total_size
)))
1973 return ERROR_NOT_ENOUGH_MEMORY
;
1974 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1975 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1976 buf_ptr
, total_size
, &total_size
);
1979 if (status
) goto done
;
1981 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
1983 status
= STATUS_BUFFER_OVERFLOW
;
1986 memcpy( value
, info
->Name
, info
->NameLength
);
1987 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
1988 value
[*val_count
] = 0;
1992 if (total_size
- info
->DataOffset
> *count
)
1994 status
= STATUS_BUFFER_OVERFLOW
;
1997 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1998 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
2000 /* if the type is REG_SZ and data is not 0-terminated
2001 * and there is enough space in the buffer NT appends a \0 */
2002 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
2003 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2008 if (type
) *type
= info
->Type
;
2009 if (count
) *count
= info
->DataLength
;
2012 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
2013 return RtlNtStatusToDosError(status
);
2017 /******************************************************************************
2018 * RegEnumValueA [ADVAPI32.@]
2020 * See RegEnumValueW.
2022 LSTATUS WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
2023 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
2027 char buffer
[256], *buf_ptr
= buffer
;
2028 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2029 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
2031 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
2032 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
2034 if ((data
&& !count
) || reserved
|| !value
|| !val_count
)
2035 return ERROR_INVALID_PARAMETER
;
2036 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2038 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2039 if (data
) total_size
+= *count
;
2040 total_size
= min( sizeof(buffer
), total_size
);
2042 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
2043 buffer
, total_size
, &total_size
);
2045 /* we need to fetch the contents for a string type even if not requested,
2046 * because we need to compute the length of the ASCII string. */
2048 /* retry with a dynamically allocated buffer */
2049 while (status
== STATUS_BUFFER_OVERFLOW
)
2051 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
2052 if (!(buf_ptr
= heap_alloc( total_size
)))
2053 return ERROR_NOT_ENOUGH_MEMORY
;
2054 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2055 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
2056 buf_ptr
, total_size
, &total_size
);
2059 if (status
) goto done
;
2061 if (is_string(info
->Type
))
2064 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2065 total_size
- info
->DataOffset
);
2068 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2071 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2072 total_size
- info
->DataOffset
);
2073 /* if the type is REG_SZ and data is not 0-terminated
2074 * and there is enough space in the buffer NT appends a \0 */
2075 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2078 info
->DataLength
= len
;
2082 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2083 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2090 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2091 if (len
>= *val_count
)
2093 status
= STATUS_BUFFER_OVERFLOW
;
2096 len
= *val_count
- 1;
2097 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2103 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2109 if (type
) *type
= info
->Type
;
2110 if (count
) *count
= info
->DataLength
;
2113 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
2114 return RtlNtStatusToDosError(status
);
2117 /******************************************************************************
2118 * RegDeleteValueW [ADVAPI32.@]
2120 * See RegDeleteValueA.
2122 LSTATUS WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
2124 return RegDeleteKeyValueW( hkey
, NULL
, name
);
2127 /******************************************************************************
2128 * RegDeleteValueA [ADVAPI32.@]
2130 * Delete a value from the registry.
2133 * hkey [I] Registry handle of the key holding the value
2134 * name [I] Name of the value under hkey to delete
2137 * Success: ERROR_SUCCESS
2138 * Failure: nonzero error code from Winerror.h
2140 LSTATUS WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
2142 return RegDeleteKeyValueA( hkey
, NULL
, name
);
2145 /******************************************************************************
2146 * RegDeleteKeyValueW [ADVAPI32.@]
2148 LONG WINAPI
RegDeleteKeyValueW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR name
)
2150 UNICODE_STRING nameW
;
2154 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2158 if ((ret
= RegOpenKeyExW( hkey
, subkey
, 0, KEY_SET_VALUE
, &hsubkey
)))
2163 RtlInitUnicodeString( &nameW
, name
);
2164 ret
= RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
2165 if (hsubkey
) RegCloseKey( hsubkey
);
2169 /******************************************************************************
2170 * RegDeleteKeyValueA [ADVAPI32.@]
2172 LONG WINAPI
RegDeleteKeyValueA( HKEY hkey
, LPCSTR subkey
, LPCSTR name
)
2174 UNICODE_STRING nameW
;
2179 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2183 LONG ret
= RegOpenKeyExA( hkey
, subkey
, 0, KEY_SET_VALUE
, &hsubkey
);
2189 RtlInitAnsiString( &nameA
, name
);
2190 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
2192 status
= NtDeleteValueKey( hkey
, &nameW
);
2193 RtlFreeUnicodeString( &nameW
);
2196 if (hsubkey
) RegCloseKey( hsubkey
);
2197 return RtlNtStatusToDosError( status
);
2200 /******************************************************************************
2201 * RegLoadKeyW [ADVAPI32.@]
2203 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2204 * registration information from a specified file into that subkey.
2207 * hkey [I] Handle of open key
2208 * subkey [I] Address of name of subkey
2209 * filename [I] Address of filename for registry information
2212 * Success: ERROR_SUCCESS
2213 * Failure: nonzero error code from Winerror.h
2215 LSTATUS WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
2217 OBJECT_ATTRIBUTES destkey
, file
;
2218 UNICODE_STRING subkeyW
, filenameW
;
2221 if (!(hkey
= get_special_root_hkey(hkey
, 0))) return ERROR_INVALID_HANDLE
;
2223 destkey
.Length
= sizeof(destkey
);
2224 destkey
.RootDirectory
= hkey
; /* root key: HKLM or HKU */
2225 destkey
.ObjectName
= &subkeyW
; /* name of the key */
2226 destkey
.Attributes
= 0;
2227 destkey
.SecurityDescriptor
= NULL
;
2228 destkey
.SecurityQualityOfService
= NULL
;
2229 RtlInitUnicodeString(&subkeyW
, subkey
);
2231 file
.Length
= sizeof(file
);
2232 file
.RootDirectory
= NULL
;
2233 file
.ObjectName
= &filenameW
; /* file containing the hive */
2234 file
.Attributes
= OBJ_CASE_INSENSITIVE
;
2235 file
.SecurityDescriptor
= NULL
;
2236 file
.SecurityQualityOfService
= NULL
;
2237 RtlDosPathNameToNtPathName_U(filename
, &filenameW
, NULL
, NULL
);
2239 status
= NtLoadKey(&destkey
, &file
);
2240 RtlFreeUnicodeString(&filenameW
);
2241 return RtlNtStatusToDosError( status
);
2245 /******************************************************************************
2246 * RegLoadKeyA [ADVAPI32.@]
2250 LSTATUS WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
2252 UNICODE_STRING subkeyW
, filenameW
;
2253 STRING subkeyA
, filenameA
;
2257 RtlInitAnsiString(&subkeyA
, subkey
);
2258 RtlInitAnsiString(&filenameA
, filename
);
2260 RtlInitUnicodeString(&subkeyW
, NULL
);
2261 RtlInitUnicodeString(&filenameW
, NULL
);
2262 if (!(status
= RtlAnsiStringToUnicodeString(&subkeyW
, &subkeyA
, TRUE
)) &&
2263 !(status
= RtlAnsiStringToUnicodeString(&filenameW
, &filenameA
, TRUE
)))
2265 ret
= RegLoadKeyW(hkey
, subkeyW
.Buffer
, filenameW
.Buffer
);
2267 else ret
= RtlNtStatusToDosError(status
);
2268 RtlFreeUnicodeString(&subkeyW
);
2269 RtlFreeUnicodeString(&filenameW
);
2274 /******************************************************************************
2275 * RegSaveKeyW [ADVAPI32.@]
2277 * Save a key and all of its subkeys and values to a new file in the standard format.
2280 * hkey [I] Handle of key where save begins
2281 * lpFile [I] Address of filename to save to
2282 * sa [I] Address of security structure
2285 * Success: ERROR_SUCCESS
2286 * Failure: nonzero error code from Winerror.h
2288 LSTATUS WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
2290 static const WCHAR format
[] =
2291 {'r','e','g','%','0','4','x','.','t','m','p',0};
2292 WCHAR buffer
[MAX_PATH
];
2298 TRACE( "(%p,%s,%p)\n", hkey
, debugstr_w(file
), sa
);
2300 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
2301 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2303 err
= GetLastError();
2304 GetFullPathNameW( file
, sizeof(buffer
)/sizeof(WCHAR
), buffer
, &nameW
);
2308 snprintfW( nameW
, 16, format
, count
++ );
2309 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
2310 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
2311 if (handle
!= INVALID_HANDLE_VALUE
) break;
2312 if ((ret
= GetLastError()) != ERROR_FILE_EXISTS
) goto done
;
2314 /* Something gone haywire ? Please report if this happens abnormally */
2316 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
);
2319 ret
= RtlNtStatusToDosError(NtSaveKey(hkey
, handle
));
2321 CloseHandle( handle
);
2324 if (!MoveFileExW( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
2326 ERR( "Failed to move %s to %s\n", debugstr_w(buffer
),
2328 ret
= GetLastError();
2331 if (ret
) DeleteFileW( buffer
);
2334 SetLastError( err
); /* restore last error code */
2339 /******************************************************************************
2340 * RegSaveKeyA [ADVAPI32.@]
2344 LSTATUS WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
2346 UNICODE_STRING
*fileW
= &NtCurrentTeb()->StaticUnicodeString
;
2350 RtlInitAnsiString(&fileA
, file
);
2351 if ((status
= RtlAnsiStringToUnicodeString(fileW
, &fileA
, FALSE
)))
2352 return RtlNtStatusToDosError( status
);
2353 return RegSaveKeyW(hkey
, fileW
->Buffer
, sa
);
2357 /******************************************************************************
2358 * RegRestoreKeyW [ADVAPI32.@]
2360 * Read the registry information from a file and copy it over a key.
2363 * hkey [I] Handle of key where restore begins
2364 * lpFile [I] Address of filename containing saved tree
2365 * dwFlags [I] Optional flags
2368 * Success: ERROR_SUCCESS
2369 * Failure: nonzero error code from Winerror.h
2371 LSTATUS WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
2373 TRACE("(%p,%s,%d)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2375 /* It seems to do this check before the hkey check */
2376 if (!lpFile
|| !*lpFile
)
2377 return ERROR_INVALID_PARAMETER
;
2379 FIXME("(%p,%s,%d): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2381 /* Check for file existence */
2383 return ERROR_SUCCESS
;
2387 /******************************************************************************
2388 * RegRestoreKeyA [ADVAPI32.@]
2390 * See RegRestoreKeyW.
2392 LSTATUS WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
2394 UNICODE_STRING lpFileW
;
2397 RtlCreateUnicodeStringFromAsciiz( &lpFileW
, lpFile
);
2398 ret
= RegRestoreKeyW( hkey
, lpFileW
.Buffer
, dwFlags
);
2399 RtlFreeUnicodeString( &lpFileW
);
2404 /******************************************************************************
2405 * RegUnLoadKeyW [ADVAPI32.@]
2407 * Unload a registry key and its subkeys from the registry.
2410 * hkey [I] Handle of open key
2411 * lpSubKey [I] Address of name of subkey to unload
2414 * Success: ERROR_SUCCESS
2415 * Failure: nonzero error code from Winerror.h
2417 LSTATUS WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
2421 OBJECT_ATTRIBUTES attr
;
2422 UNICODE_STRING subkey
;
2424 TRACE("(%p,%s)\n",hkey
, debugstr_w(lpSubKey
));
2426 ret
= RegOpenKeyW(hkey
,lpSubKey
,&shkey
);
2428 return ERROR_INVALID_PARAMETER
;
2430 RtlInitUnicodeString(&subkey
, lpSubKey
);
2431 InitializeObjectAttributes(&attr
, &subkey
, OBJ_CASE_INSENSITIVE
, shkey
, NULL
);
2432 ret
= RtlNtStatusToDosError(NtUnloadKey(&attr
));
2440 /******************************************************************************
2441 * RegUnLoadKeyA [ADVAPI32.@]
2443 * See RegUnLoadKeyW.
2445 LSTATUS WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
2447 UNICODE_STRING lpSubKeyW
;
2450 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2451 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
.Buffer
);
2452 RtlFreeUnicodeString( &lpSubKeyW
);
2457 /******************************************************************************
2458 * RegReplaceKeyW [ADVAPI32.@]
2460 * Replace the file backing a registry key and all its subkeys with another file.
2463 * hkey [I] Handle of open key
2464 * lpSubKey [I] Address of name of subkey
2465 * lpNewFile [I] Address of filename for file with new data
2466 * lpOldFile [I] Address of filename for backup file
2469 * Success: ERROR_SUCCESS
2470 * Failure: nonzero error code from Winerror.h
2472 LSTATUS WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
2475 FIXME("(%p,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
2476 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
2477 return ERROR_SUCCESS
;
2481 /******************************************************************************
2482 * RegReplaceKeyA [ADVAPI32.@]
2484 * See RegReplaceKeyW.
2486 LSTATUS WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
2489 UNICODE_STRING lpSubKeyW
;
2490 UNICODE_STRING lpNewFileW
;
2491 UNICODE_STRING lpOldFileW
;
2494 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2495 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW
, lpOldFile
);
2496 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW
, lpNewFile
);
2497 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
.Buffer
, lpNewFileW
.Buffer
, lpOldFileW
.Buffer
);
2498 RtlFreeUnicodeString( &lpOldFileW
);
2499 RtlFreeUnicodeString( &lpNewFileW
);
2500 RtlFreeUnicodeString( &lpSubKeyW
);
2505 /******************************************************************************
2506 * RegSetKeySecurity [ADVAPI32.@]
2508 * Set the security of an open registry key.
2511 * hkey [I] Open handle of key to set
2512 * SecurityInfo [I] Descriptor contents
2513 * pSecurityDesc [I] Address of descriptor for key
2516 * Success: ERROR_SUCCESS
2517 * Failure: nonzero error code from Winerror.h
2519 LSTATUS WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
2520 PSECURITY_DESCRIPTOR pSecurityDesc
)
2522 TRACE("(%p,%d,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
2524 /* It seems to perform this check before the hkey check */
2525 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
2526 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
2527 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
2528 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
2531 return ERROR_INVALID_PARAMETER
;
2534 return ERROR_INVALID_PARAMETER
;
2536 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2538 return RtlNtStatusToDosError( NtSetSecurityObject( hkey
, SecurityInfo
, pSecurityDesc
) );
2542 /******************************************************************************
2543 * RegGetKeySecurity [ADVAPI32.@]
2545 * Get a copy of the security descriptor for a given registry key.
2548 * hkey [I] Open handle of key to set
2549 * SecurityInformation [I] Descriptor contents
2550 * pSecurityDescriptor [O] Address of descriptor for key
2551 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2554 * Success: ERROR_SUCCESS
2555 * Failure: Error code
2557 LSTATUS WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
2558 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2559 LPDWORD lpcbSecurityDescriptor
)
2561 TRACE("(%p,%d,%p,%d)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
2562 *lpcbSecurityDescriptor
);
2564 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2566 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey
,
2567 SecurityInformation
, pSecurityDescriptor
,
2568 *lpcbSecurityDescriptor
, lpcbSecurityDescriptor
) );
2572 /******************************************************************************
2573 * RegFlushKey [ADVAPI32.@]
2575 * Immediately write a registry key to registry.
2578 * hkey [I] Handle of key to write
2581 * Success: ERROR_SUCCESS
2582 * Failure: Error code
2584 LSTATUS WINAPI
RegFlushKey( HKEY hkey
)
2586 hkey
= get_special_root_hkey( hkey
, 0 );
2587 if (!hkey
) return ERROR_INVALID_HANDLE
;
2589 return RtlNtStatusToDosError( NtFlushKey( hkey
) );
2593 /******************************************************************************
2594 * RegConnectRegistryW [ADVAPI32.@]
2596 * Establish a connection to a predefined registry key on another computer.
2599 * lpMachineName [I] Address of name of remote computer
2600 * hHey [I] Predefined registry handle
2601 * phkResult [I] Address of buffer for remote registry handle
2604 * Success: ERROR_SUCCESS
2605 * Failure: nonzero error code from Winerror.h
2607 LSTATUS WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
2612 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName
), hKey
, phkResult
);
2614 if (!lpMachineName
|| !*lpMachineName
) {
2615 /* Use the local machine name */
2616 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
2619 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
2620 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
2622 /* MSDN says lpMachineName must start with \\ : not so */
2623 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
2625 if (GetComputerNameW(compName
, &len
))
2627 if (!strcmpiW(lpMachineName
, compName
))
2628 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
2631 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
2632 ret
= ERROR_BAD_NETPATH
;
2636 ret
= GetLastError();
2642 /******************************************************************************
2643 * RegConnectRegistryA [ADVAPI32.@]
2645 * See RegConnectRegistryW.
2647 LSTATUS WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, PHKEY reskey
)
2649 UNICODE_STRING machineW
;
2652 RtlCreateUnicodeStringFromAsciiz( &machineW
, machine
);
2653 ret
= RegConnectRegistryW( machineW
.Buffer
, hkey
, reskey
);
2654 RtlFreeUnicodeString( &machineW
);
2659 /******************************************************************************
2660 * RegNotifyChangeKeyValue [ADVAPI32.@]
2662 * Notify the caller about changes to the attributes or contents of a registry key.
2665 * hkey [I] Handle of key to watch
2666 * fWatchSubTree [I] Flag for subkey notification
2667 * fdwNotifyFilter [I] Changes to be reported
2668 * hEvent [I] Handle of signaled event
2669 * fAsync [I] Flag for asynchronous reporting
2672 * Success: ERROR_SUCCESS
2673 * Failure: nonzero error code from Winerror.h
2675 LSTATUS WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
2676 DWORD fdwNotifyFilter
, HANDLE hEvent
,
2680 IO_STATUS_BLOCK iosb
;
2682 hkey
= get_special_root_hkey( hkey
, 0 );
2683 if (!hkey
) return ERROR_INVALID_HANDLE
;
2685 TRACE("(%p,%i,%d,%p,%i)\n", hkey
, fWatchSubTree
, fdwNotifyFilter
,
2688 status
= NtNotifyChangeKey( hkey
, hEvent
, NULL
, NULL
, &iosb
,
2689 fdwNotifyFilter
, fWatchSubTree
, NULL
, 0,
2692 if (status
&& status
!= STATUS_TIMEOUT
)
2693 return RtlNtStatusToDosError( status
);
2695 return ERROR_SUCCESS
;
2698 /******************************************************************************
2699 * RegOpenUserClassesRoot [ADVAPI32.@]
2701 * Open the HKEY_CLASSES_ROOT key for a user.
2704 * hToken [I] Handle of token representing the user
2705 * dwOptions [I] Reserved, must be 0
2706 * samDesired [I] Desired access rights
2707 * phkResult [O] Destination for the resulting key handle
2710 * Success: ERROR_SUCCESS
2711 * Failure: nonzero error code from Winerror.h
2714 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2715 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2716 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2718 LSTATUS WINAPI
RegOpenUserClassesRoot(
2725 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken
, dwOptions
, samDesired
, phkResult
);
2727 *phkResult
= HKEY_CLASSES_ROOT
;
2728 return ERROR_SUCCESS
;
2731 /******************************************************************************
2732 * load_string [Internal]
2734 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2735 * avoid importing user32, which is higher level than advapi32. Helper for
2738 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
2745 /* Negative values have to be inverted. */
2746 if (HIWORD(resId
) == 0xffff)
2747 resId
= (UINT
)(-((INT
)resId
));
2749 /* Load the resource into memory and get a pointer to it. */
2750 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
2751 if (!hResource
) return 0;
2752 hMemory
= LoadResource(hModule
, hResource
);
2753 if (!hMemory
) return 0;
2754 pString
= LockResource(hMemory
);
2756 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2757 idxString
= resId
& 0xf;
2758 while (idxString
--) pString
+= *pString
+ 1;
2760 /* If no buffer is given, return length of the string. */
2761 if (!pwszBuffer
) return *pString
;
2763 /* Else copy over the string, respecting the buffer size. */
2764 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
2765 if (cMaxChars
>= 0) {
2766 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
2767 pwszBuffer
[cMaxChars
] = '\0';
2773 /******************************************************************************
2774 * RegLoadMUIStringW [ADVAPI32.@]
2776 * Load the localized version of a string resource from some PE, respective
2777 * id and path of which are given in the registry value in the format
2778 * @[path]\dllname,-resourceId
2781 * hKey [I] Key, of which to load the string value from.
2782 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2783 * pszBuffer [O] Buffer to store the localized string in.
2784 * cbBuffer [I] Size of the destination buffer in bytes.
2785 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2786 * dwFlags [I] None supported yet.
2787 * pszBaseDir [I] Not supported yet.
2790 * Success: ERROR_SUCCESS,
2791 * Failure: nonzero error code from winerror.h
2794 * This is an API of Windows Vista, which wasn't available at the time this code
2795 * was written. We have to check for the correct behaviour once it's available.
2797 LSTATUS WINAPI
RegLoadMUIStringW(HKEY hKey
, LPCWSTR pwszValue
, LPWSTR pwszBuffer
, DWORD cbBuffer
,
2798 LPDWORD pcbData
, DWORD dwFlags
, LPCWSTR pwszBaseDir
)
2800 DWORD dwValueType
, cbData
;
2801 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
2804 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2805 "dwFlags = %d, pwszBaseDir = %s)\n", hKey
, debugstr_w(pwszValue
), pwszBuffer
,
2806 cbBuffer
, pcbData
, dwFlags
, debugstr_w(pwszBaseDir
));
2808 /* Parameter sanity checks. */
2809 if (!hKey
|| !pwszBuffer
)
2810 return ERROR_INVALID_PARAMETER
;
2812 if (pwszBaseDir
&& *pwszBaseDir
) {
2813 FIXME("BaseDir parameter not yet supported!\n");
2814 return ERROR_INVALID_PARAMETER
;
2817 /* Check for value existence and correctness of its type, allocate a buffer and load it. */
2818 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
2819 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2820 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
) {
2821 result
= ERROR_FILE_NOT_FOUND
;
2824 pwszTempBuffer
= heap_alloc(cbData
);
2825 if (!pwszTempBuffer
) {
2826 result
= ERROR_NOT_ENOUGH_MEMORY
;
2829 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
2830 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2832 /* Expand environment variables, if appropriate, or copy the original string over. */
2833 if (dwValueType
== REG_EXPAND_SZ
) {
2834 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
2835 if (!cbData
) goto cleanup
;
2836 pwszExpandedBuffer
= heap_alloc(cbData
);
2837 if (!pwszExpandedBuffer
) {
2838 result
= ERROR_NOT_ENOUGH_MEMORY
;
2841 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
2843 pwszExpandedBuffer
= heap_alloc(cbData
);
2844 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
2847 /* If the value references a resource based string, parse the value and load the string.
2848 * Else just copy over the original value. */
2849 result
= ERROR_SUCCESS
;
2850 if (*pwszExpandedBuffer
!= '@') { /* '@' is the prefix for resource based string entries. */
2851 lstrcpynW(pwszBuffer
, pwszExpandedBuffer
, cbBuffer
/ sizeof(WCHAR
));
2853 WCHAR
*pComma
= strrchrW(pwszExpandedBuffer
, ',');
2857 /* Format of the expanded value is 'path_to_dll,-resId' */
2858 if (!pComma
|| pComma
[1] != '-') {
2859 result
= ERROR_BADKEY
;
2863 uiStringId
= atoiW(pComma
+2);
2866 hModule
= LoadLibraryW(pwszExpandedBuffer
+ 1);
2867 if (!hModule
|| !load_string(hModule
, uiStringId
, pwszBuffer
, cbBuffer
/sizeof(WCHAR
)))
2868 result
= ERROR_BADKEY
;
2869 FreeLibrary(hModule
);
2873 heap_free(pwszTempBuffer
);
2874 heap_free(pwszExpandedBuffer
);
2878 /******************************************************************************
2879 * RegLoadMUIStringA [ADVAPI32.@]
2881 * See RegLoadMUIStringW
2883 LSTATUS WINAPI
RegLoadMUIStringA(HKEY hKey
, LPCSTR pszValue
, LPSTR pszBuffer
, DWORD cbBuffer
,
2884 LPDWORD pcbData
, DWORD dwFlags
, LPCSTR pszBaseDir
)
2886 UNICODE_STRING valueW
, baseDirW
;
2888 DWORD cbData
= cbBuffer
* sizeof(WCHAR
);
2891 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
2892 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
2893 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszBaseDir
) ||
2894 !(pwszBuffer
= heap_alloc(cbData
)))
2896 result
= ERROR_NOT_ENOUGH_MEMORY
;
2900 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, dwFlags
,
2903 if (result
== ERROR_SUCCESS
) {
2904 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszBuffer
, cbBuffer
, NULL
, NULL
);
2910 heap_free(pwszBuffer
);
2911 RtlFreeUnicodeString(&baseDirW
);
2912 RtlFreeUnicodeString(&valueW
);
2917 /******************************************************************************
2918 * RegDisablePredefinedCache [ADVAPI32.@]
2920 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2926 * Success: ERROR_SUCCESS
2927 * Failure: nonzero error code from Winerror.h
2930 * This is useful for services that use impersonation.
2932 LSTATUS WINAPI
RegDisablePredefinedCache(void)
2934 HKEY hkey_current_user
;
2935 int idx
= HandleToUlong(HKEY_CURRENT_USER
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
2937 /* prevent caching of future requests */
2938 hkcu_cache_disabled
= TRUE
;
2940 hkey_current_user
= InterlockedExchangePointer( (void **)&special_root_keys
[idx
], NULL
);
2942 if (hkey_current_user
)
2943 NtClose( hkey_current_user
);
2945 return ERROR_SUCCESS
;
2948 /******************************************************************************
2949 * RegDeleteTreeW [ADVAPI32.@]
2952 LSTATUS WINAPI
RegDeleteTreeW(HKEY hKey
, LPCWSTR lpszSubKey
)
2955 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
2956 DWORD dwMaxLen
, dwSize
;
2957 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
2958 HKEY hSubKey
= hKey
;
2960 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
2964 ret
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
2965 if (ret
) return ret
;
2968 /* Get highest length for keys, values */
2969 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
2970 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
2971 if (ret
) goto cleanup
;
2975 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
2976 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
2978 /* Name too big: alloc a buffer for it */
2979 if (!(lpszName
= heap_alloc( dwMaxLen
*sizeof(WCHAR
))))
2981 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2987 /* Recursively delete all the subkeys */
2991 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
2992 NULL
, NULL
, NULL
)) break;
2994 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
2995 if (ret
) goto cleanup
;
2999 ret
= RegDeleteKeyW(hKey
, lpszSubKey
);
3004 if (RegEnumValueW(hKey
, 0, lpszName
, &dwSize
,
3005 NULL
, NULL
, NULL
, NULL
)) break;
3007 ret
= RegDeleteValueW(hKey
, lpszName
);
3008 if (ret
) goto cleanup
;
3012 /* Free buffer if allocated */
3013 if (lpszName
!= szNameBuf
)
3014 heap_free( lpszName
);
3016 RegCloseKey(hSubKey
);
3020 /******************************************************************************
3021 * RegDeleteTreeA [ADVAPI32.@]
3024 LSTATUS WINAPI
RegDeleteTreeA(HKEY hKey
, LPCSTR lpszSubKey
)
3027 UNICODE_STRING lpszSubKeyW
;
3029 if (lpszSubKey
) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW
, lpszSubKey
);
3030 else lpszSubKeyW
.Buffer
= NULL
;
3031 ret
= RegDeleteTreeW( hKey
, lpszSubKeyW
.Buffer
);
3032 RtlFreeUnicodeString( &lpszSubKeyW
);
3036 /******************************************************************************
3037 * RegDisableReflectionKey [ADVAPI32.@]
3040 LONG WINAPI
RegDisableReflectionKey(HKEY base
)
3042 FIXME("%p: stub\n", base
);
3043 return ERROR_SUCCESS
;