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
41 #include "advapi32_misc.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
48 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
49 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
51 static const WCHAR name_CLASSES_ROOT
[] =
52 {'\\','R','e','g','i','s','t','r','y','\\',
53 'M','a','c','h','i','n','e','\\',
54 'S','o','f','t','w','a','r','e','\\',
55 'C','l','a','s','s','e','s',0};
56 static const WCHAR name_LOCAL_MACHINE
[] =
57 {'\\','R','e','g','i','s','t','r','y','\\',
58 'M','a','c','h','i','n','e',0};
59 static const WCHAR name_USERS
[] =
60 {'\\','R','e','g','i','s','t','r','y','\\',
62 static const WCHAR name_PERFORMANCE_DATA
[] =
63 {'\\','R','e','g','i','s','t','r','y','\\',
64 'P','e','r','f','D','a','t','a',0};
65 static const WCHAR name_CURRENT_CONFIG
[] =
66 {'\\','R','e','g','i','s','t','r','y','\\',
67 'M','a','c','h','i','n','e','\\',
68 'S','y','s','t','e','m','\\',
69 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
70 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
71 'C','u','r','r','e','n','t',0};
72 static const WCHAR name_DYN_DATA
[] =
73 {'\\','R','e','g','i','s','t','r','y','\\',
74 'D','y','n','D','a','t','a',0};
76 static const WCHAR
* const root_key_names
[] =
79 NULL
, /* HKEY_CURRENT_USER is determined dynamically */
82 name_PERFORMANCE_DATA
,
87 #define NB_SPECIAL_ROOT_KEYS (sizeof(root_key_names)/sizeof(root_key_names[0]))
89 static HKEY special_root_keys
[NB_SPECIAL_ROOT_KEYS
];
90 static BOOL hkcu_cache_disabled
;
92 static const BOOL is_win64
= (sizeof(void *) > sizeof(int));
94 /* check if value type needs string conversion (Ansi<->Unicode) */
95 static inline BOOL
is_string( DWORD type
)
97 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
100 /* check if current version is NT or Win95 */
101 static inline BOOL
is_version_nt(void)
103 return !(GetVersion() & 0x80000000);
106 static BOOL
is_wow6432node( const UNICODE_STRING
*name
)
108 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e'};
110 return (name
->Length
== sizeof(wow6432nodeW
) &&
111 !memicmpW( name
->Buffer
, wow6432nodeW
, sizeof(wow6432nodeW
)/sizeof(WCHAR
) ));
114 /* open the Wow6432Node subkey of the specified key */
115 static HANDLE
open_wow6432node( HANDLE key
)
117 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
118 OBJECT_ATTRIBUTES attr
;
119 UNICODE_STRING nameW
;
122 attr
.Length
= sizeof(attr
);
123 attr
.RootDirectory
= key
;
124 attr
.ObjectName
= &nameW
;
126 attr
.SecurityDescriptor
= NULL
;
127 attr
.SecurityQualityOfService
= NULL
;
128 RtlInitUnicodeString( &nameW
, wow6432nodeW
);
129 if (NtOpenKey( &ret
, MAXIMUM_ALLOWED
, &attr
)) ret
= 0;
133 /* wrapper for NtCreateKey that creates the key recursively if necessary */
134 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
135 const UNICODE_STRING
*class, ULONG options
, PULONG dispos
)
137 BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
138 NTSTATUS status
= STATUS_OBJECT_NAME_NOT_FOUND
;
139 HANDLE subkey
, root
= attr
->RootDirectory
;
141 if (!force_wow32
) status
= NtCreateKey( &subkey
, access
, attr
, 0, class, options
, dispos
);
143 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
145 static const WCHAR registry_root
[] = {'\\','R','e','g','i','s','t','r','y','\\'};
146 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
147 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
150 /* don't try to create registry root */
151 if (!attr
->RootDirectory
&& len
> sizeof(registry_root
)/sizeof(WCHAR
) &&
152 !memicmpW( buffer
, registry_root
, sizeof(registry_root
)/sizeof(WCHAR
)))
153 i
+= sizeof(registry_root
)/sizeof(WCHAR
);
155 while (i
< len
&& buffer
[i
] != '\\') i
++;
156 if (i
== len
&& !force_wow32
) return status
;
158 attrs
= attr
->Attributes
;
159 attr
->ObjectName
= &str
;
163 str
.Buffer
= buffer
+ pos
;
164 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
165 if (force_wow32
&& pos
)
167 if (is_wow6432node( &str
)) force_wow32
= FALSE
;
168 else if ((subkey
= open_wow6432node( attr
->RootDirectory
)))
170 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
171 attr
->RootDirectory
= subkey
;
177 attr
->Attributes
= attrs
;
178 status
= NtCreateKey( &subkey
, access
, attr
, 0, class, options
, dispos
);
182 attr
->Attributes
= attrs
& ~OBJ_OPENLINK
;
183 status
= NtCreateKey( &subkey
, access
, attr
, 0, class,
184 options
& ~REG_OPTION_CREATE_LINK
, dispos
);
186 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
187 if (status
) return status
;
189 attr
->RootDirectory
= subkey
;
190 while (i
< len
&& buffer
[i
] == '\\') i
++;
192 while (i
< len
&& buffer
[i
] != '\\') i
++;
195 attr
->RootDirectory
= subkey
;
196 if (force_wow32
&& (subkey
= open_wow6432node( attr
->RootDirectory
)))
198 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
199 attr
->RootDirectory
= subkey
;
201 *retkey
= attr
->RootDirectory
;
205 /* wrapper for NtOpenKey to handle Wow6432 nodes */
206 static NTSTATUS
open_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
209 BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
210 HANDLE subkey
, root
= attr
->RootDirectory
;
211 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
212 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
215 if (!force_wow32
) return NtOpenKey( (HANDLE
*)retkey
, access
, attr
);
217 if (len
&& buffer
[0] == '\\') return STATUS_OBJECT_PATH_INVALID
;
218 while (i
< len
&& buffer
[i
] != '\\') i
++;
219 attrs
= attr
->Attributes
;
220 attr
->ObjectName
= &str
;
224 str
.Buffer
= buffer
+ pos
;
225 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
226 if (force_wow32
&& pos
)
228 if (is_wow6432node( &str
)) force_wow32
= FALSE
;
229 else if ((subkey
= open_wow6432node( attr
->RootDirectory
)))
231 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
232 attr
->RootDirectory
= subkey
;
238 attr
->Attributes
= attrs
;
239 status
= NtOpenKey( &subkey
, access
, attr
);
243 attr
->Attributes
= attrs
& ~OBJ_OPENLINK
;
244 status
= NtOpenKey( &subkey
, access
, attr
);
246 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
247 if (status
) return status
;
248 attr
->RootDirectory
= subkey
;
250 while (i
< len
&& buffer
[i
] == '\\') i
++;
252 while (i
< len
&& buffer
[i
] != '\\') i
++;
254 if (force_wow32
&& (subkey
= open_wow6432node( attr
->RootDirectory
)))
256 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
257 attr
->RootDirectory
= subkey
;
259 *retkey
= attr
->RootDirectory
;
263 /* create one of the HKEY_* special root keys */
264 static HKEY
create_special_root_hkey( HKEY hkey
, DWORD access
)
267 int idx
= HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
269 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CURRENT_USER
))
271 if (RtlOpenCurrentUser( access
, (HANDLE
*)&hkey
)) return 0;
272 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey
);
274 /* don't cache the key in the table if caching is disabled */
275 if (hkcu_cache_disabled
)
280 OBJECT_ATTRIBUTES attr
;
283 attr
.Length
= sizeof(attr
);
284 attr
.RootDirectory
= 0;
285 attr
.ObjectName
= &name
;
287 attr
.SecurityDescriptor
= NULL
;
288 attr
.SecurityQualityOfService
= NULL
;
289 RtlInitUnicodeString( &name
, root_key_names
[idx
] );
290 if (create_key( &hkey
, access
, &attr
, NULL
, 0, NULL
)) return 0;
291 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
294 if (!(access
& (KEY_WOW64_64KEY
| KEY_WOW64_32KEY
)))
296 if (!(ret
= InterlockedCompareExchangePointer( (void **)&special_root_keys
[idx
], hkey
, 0 )))
299 NtClose( hkey
); /* somebody beat us to it */
306 /* map the hkey from special root to normal key if necessary */
307 static inline HKEY
get_special_root_hkey( HKEY hkey
, REGSAM access
)
311 if ((HandleToUlong(hkey
) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
))
312 && (HandleToUlong(hkey
) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
316 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
))
317 mask
= KEY_WOW64_32KEY
| KEY_WOW64_64KEY
;
319 if ((access
& mask
) ||
320 !(ret
= special_root_keys
[HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
)]))
321 ret
= create_special_root_hkey( hkey
, MAXIMUM_ALLOWED
| (access
& mask
) );
327 /******************************************************************************
328 * RegOverridePredefKey [ADVAPI32.@]
330 LSTATUS WINAPI
RegOverridePredefKey( HKEY hkey
, HKEY override
)
335 TRACE("(%p %p)\n", hkey
, override
);
337 if ((HandleToUlong(hkey
) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
))
338 || (HandleToUlong(hkey
) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
339 return ERROR_INVALID_PARAMETER
;
340 idx
= HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
344 NTSTATUS status
= NtDuplicateObject( GetCurrentProcess(), override
,
345 GetCurrentProcess(), (HANDLE
*)&override
,
346 0, 0, DUPLICATE_SAME_ACCESS
);
347 if (status
) return RtlNtStatusToDosError( status
);
350 old_key
= InterlockedExchangePointer( (void **)&special_root_keys
[idx
], override
);
351 if (old_key
) NtClose( old_key
);
352 return ERROR_SUCCESS
;
356 /******************************************************************************
357 * RegCreateKeyExW [ADVAPI32.@]
359 * See RegCreateKeyExA.
361 LSTATUS WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
362 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
363 PHKEY retkey
, LPDWORD dispos
)
365 OBJECT_ATTRIBUTES attr
;
366 UNICODE_STRING nameW
, classW
;
368 if (reserved
) return ERROR_INVALID_PARAMETER
;
369 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
371 attr
.Length
= sizeof(attr
);
372 attr
.RootDirectory
= hkey
;
373 attr
.ObjectName
= &nameW
;
375 attr
.SecurityDescriptor
= NULL
;
376 attr
.SecurityQualityOfService
= NULL
;
377 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
378 RtlInitUnicodeString( &nameW
, name
);
379 RtlInitUnicodeString( &classW
, class );
381 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
, &classW
, options
, dispos
) );
385 /******************************************************************************
386 * RegCreateKeyExA [ADVAPI32.@]
388 * Open a registry key, creating it if it doesn't exist.
391 * hkey [I] Handle of the parent registry key
392 * name [I] Name of the new key to open or create
393 * reserved [I] Reserved, pass 0
394 * class [I] The object type of the new key
395 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
396 * access [I] Access level desired
397 * sa [I] Security attributes for the key
398 * retkey [O] Destination for the resulting handle
399 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
402 * Success: ERROR_SUCCESS.
403 * Failure: A standard Win32 error code. retkey remains untouched.
406 * MAXIMUM_ALLOWED in access mask not supported by server
408 LSTATUS WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
409 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
410 PHKEY retkey
, LPDWORD dispos
)
412 OBJECT_ATTRIBUTES attr
;
413 UNICODE_STRING classW
;
414 ANSI_STRING nameA
, classA
;
417 if (reserved
) return ERROR_INVALID_PARAMETER
;
418 if (!is_version_nt())
420 access
= MAXIMUM_ALLOWED
; /* Win95 ignores the access mask */
421 if (name
&& *name
== '\\') name
++; /* win9x,ME ignores one (and only one) beginning backslash */
423 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
425 attr
.Length
= sizeof(attr
);
426 attr
.RootDirectory
= hkey
;
427 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
429 attr
.SecurityDescriptor
= NULL
;
430 attr
.SecurityQualityOfService
= NULL
;
431 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
432 RtlInitAnsiString( &nameA
, name
);
433 RtlInitAnsiString( &classA
, class );
435 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
438 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
440 status
= create_key( retkey
, access
, &attr
, &classW
, options
, dispos
);
441 RtlFreeUnicodeString( &classW
);
444 return RtlNtStatusToDosError( status
);
448 /******************************************************************************
449 * RegCreateKeyW [ADVAPI32.@]
451 * Creates the specified reg key.
454 * hKey [I] Handle to an open key.
455 * lpSubKey [I] Name of a key that will be opened or created.
456 * phkResult [O] Receives a handle to the opened or created key.
459 * Success: ERROR_SUCCESS
460 * Failure: nonzero error code defined in Winerror.h
462 LSTATUS WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpSubKey
, PHKEY phkResult
)
464 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
465 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
466 return RegCreateKeyExW( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
467 MAXIMUM_ALLOWED
, NULL
, phkResult
, NULL
);
471 /******************************************************************************
472 * RegCreateKeyA [ADVAPI32.@]
476 LSTATUS WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpSubKey
, PHKEY phkResult
)
478 return RegCreateKeyExA( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
479 MAXIMUM_ALLOWED
, NULL
, phkResult
, NULL
);
483 /******************************************************************************
484 * RegCreateKeyTransactedW [ADVAPI32.@]
486 LSTATUS WINAPI
RegCreateKeyTransactedW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
487 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
488 PHKEY retkey
, LPDWORD dispos
, HANDLE transaction
, PVOID reserved2
)
490 FIXME( "(%p,%s,%u,%s,%u,%u,%p,%p,%p,%p,%p): stub\n", hkey
, debugstr_w(name
), reserved
,
491 debugstr_w(class), options
, access
, sa
, retkey
, dispos
, transaction
, reserved2
);
492 return ERROR_CALL_NOT_IMPLEMENTED
;
496 /******************************************************************************
497 * RegCreateKeyTransactedA [ADVAPI32.@]
499 LSTATUS WINAPI
RegCreateKeyTransactedA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
500 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
501 PHKEY retkey
, LPDWORD dispos
, HANDLE transaction
, PVOID reserved2
)
503 FIXME( "(%p,%s,%u,%s,%u,%u,%p,%p,%p,%p,%p): stub\n", hkey
, debugstr_a(name
), reserved
,
504 debugstr_a(class), options
, access
, sa
, retkey
, dispos
, transaction
, reserved2
);
505 return ERROR_CALL_NOT_IMPLEMENTED
;
509 /******************************************************************************
510 * RegOpenKeyExW [ADVAPI32.@]
514 LSTATUS WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD options
, REGSAM access
, PHKEY retkey
)
516 OBJECT_ATTRIBUTES attr
;
517 UNICODE_STRING nameW
;
519 if (retkey
&& (!name
|| !name
[0]) &&
520 (HandleToUlong(hkey
) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
)) &&
521 (HandleToUlong(hkey
) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
524 return ERROR_SUCCESS
;
527 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
528 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
) && name
&& *name
== '\\') name
++;
530 if (!retkey
) return ERROR_INVALID_PARAMETER
;
531 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
533 attr
.Length
= sizeof(attr
);
534 attr
.RootDirectory
= hkey
;
535 attr
.ObjectName
= &nameW
;
537 attr
.SecurityDescriptor
= NULL
;
538 attr
.SecurityQualityOfService
= NULL
;
539 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
540 RtlInitUnicodeString( &nameW
, name
);
541 return RtlNtStatusToDosError( open_key( retkey
, access
, &attr
) );
545 /******************************************************************************
546 * RegOpenKeyExA [ADVAPI32.@]
548 * Open a registry key.
551 * hkey [I] Handle of open key
552 * name [I] Name of subkey to open
553 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
554 * access [I] Security access mask
555 * retkey [O] Handle to open key
558 * Success: ERROR_SUCCESS
559 * Failure: A standard Win32 error code. retkey is set to 0.
562 * Unlike RegCreateKeyExA(), this function will not create the key if it
565 LSTATUS WINAPI DECLSPEC_HOTPATCH
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD options
, REGSAM access
, PHKEY retkey
)
567 OBJECT_ATTRIBUTES attr
;
571 if (retkey
&& (!name
|| !name
[0]) &&
572 (HandleToUlong(hkey
) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
)) &&
573 (HandleToUlong(hkey
) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
576 return ERROR_SUCCESS
;
579 if (!is_version_nt()) access
= MAXIMUM_ALLOWED
; /* Win95 ignores the access mask */
582 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
583 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
) && name
&& *name
== '\\') name
++;
586 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
588 attr
.Length
= sizeof(attr
);
589 attr
.RootDirectory
= hkey
;
590 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
592 attr
.SecurityDescriptor
= NULL
;
593 attr
.SecurityQualityOfService
= NULL
;
594 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
596 RtlInitAnsiString( &nameA
, name
);
597 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
600 status
= open_key( retkey
, access
, &attr
);
602 return RtlNtStatusToDosError( status
);
606 /******************************************************************************
607 * RegOpenKeyW [ADVAPI32.@]
611 LSTATUS WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, PHKEY retkey
)
614 return ERROR_INVALID_PARAMETER
;
619 return ERROR_SUCCESS
;
621 return RegOpenKeyExW( hkey
, name
, 0, MAXIMUM_ALLOWED
, retkey
);
625 /******************************************************************************
626 * RegOpenKeyA [ADVAPI32.@]
628 * Open a registry key.
631 * hkey [I] Handle of parent key to open the new key under
632 * name [I] Name of the key under hkey to open
633 * retkey [O] Destination for the resulting Handle
636 * Success: ERROR_SUCCESS
637 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
639 LSTATUS WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, PHKEY retkey
)
642 return ERROR_INVALID_PARAMETER
;
647 return ERROR_SUCCESS
;
649 return RegOpenKeyExA( hkey
, name
, 0, MAXIMUM_ALLOWED
, retkey
);
652 static WCHAR
*get_thread_token_user_sid(HANDLE token
)
654 WCHAR
*sidstring
= NULL
;
658 GetTokenInformation(token
, TokenUser
, NULL
, 0, &len
);
660 info
= heap_alloc(len
);
661 if (GetTokenInformation(token
, TokenUser
, info
, len
, &len
))
662 ConvertSidToStringSidW(info
->User
.Sid
, &sidstring
);
668 /******************************************************************************
669 * RegOpenCurrentUser [ADVAPI32.@]
671 * Get a handle to the HKEY_CURRENT_USER key for the user
672 * the current thread is impersonating.
675 * access [I] Desired access rights to the key
676 * retkey [O] Handle to the opened key
679 * Success: ERROR_SUCCESS
680 * Failure: nonzero error code from Winerror.h
683 * This function is supposed to retrieve a handle to the
684 * HKEY_CURRENT_USER for the user the current thread is impersonating.
685 * Since Wine does not currently allow threads to impersonate other users,
686 * this stub should work fine.
688 LSTATUS WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
690 WCHAR
*sidstring
= NULL
;
694 /* get current user SID */
695 if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY
, FALSE
, &threadtoken
))
697 sidstring
= get_thread_token_user_sid(threadtoken
);
698 CloseHandle(threadtoken
);
703 ImpersonateSelf(SecurityIdentification
);
704 if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY
, FALSE
, &threadtoken
))
706 sidstring
= get_thread_token_user_sid(threadtoken
);
707 CloseHandle(threadtoken
);
714 ret
= RegOpenKeyExW( HKEY_USERS
, sidstring
, 0, access
, retkey
);
715 LocalFree(sidstring
);
718 ret
= RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
725 /******************************************************************************
726 * RegEnumKeyExW [ADVAPI32.@]
728 * Enumerate subkeys of the specified open registry key.
731 * hkey [I] Handle to key to enumerate
732 * index [I] Index of subkey to enumerate
733 * name [O] Buffer for subkey name
734 * name_len [O] Size of subkey buffer
735 * reserved [I] Reserved
736 * class [O] Buffer for class string
737 * class_len [O] Size of class buffer
738 * ft [O] Time key last written to
741 * Success: ERROR_SUCCESS
742 * Failure: System error code. If there are no more subkeys available, the
743 * function returns ERROR_NO_MORE_ITEMS.
745 LSTATUS WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
746 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
749 char buffer
[256], *buf_ptr
= buffer
;
750 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
753 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
754 name_len
? *name_len
: 0, reserved
, class, class_len
, ft
);
756 if (reserved
) return ERROR_INVALID_PARAMETER
;
757 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
759 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
760 buffer
, sizeof(buffer
), &total_size
);
762 while (status
== STATUS_BUFFER_OVERFLOW
)
764 /* retry with a dynamically allocated buffer */
765 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
766 if (!(buf_ptr
= heap_alloc( total_size
)))
767 return ERROR_NOT_ENOUGH_MEMORY
;
768 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
769 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
770 buf_ptr
, total_size
, &total_size
);
775 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
776 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
778 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
780 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
781 status
= STATUS_BUFFER_OVERFLOW
;
785 memcpy( name
, info
->Name
, info
->NameLength
);
789 *class_len
= cls_len
;
792 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
799 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
800 return RtlNtStatusToDosError( status
);
804 /******************************************************************************
805 * RegEnumKeyExA [ADVAPI32.@]
809 LSTATUS WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
810 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
813 char buffer
[256], *buf_ptr
= buffer
;
814 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
817 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
818 name_len
? *name_len
: 0, reserved
, class, class_len
, ft
);
820 if (reserved
) return ERROR_INVALID_PARAMETER
;
821 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
823 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
824 buffer
, sizeof(buffer
), &total_size
);
826 while (status
== STATUS_BUFFER_OVERFLOW
)
828 /* retry with a dynamically allocated buffer */
829 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
830 if (!(buf_ptr
= heap_alloc( total_size
)))
831 return ERROR_NOT_ENOUGH_MEMORY
;
832 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
833 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
834 buf_ptr
, total_size
, &total_size
);
841 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
842 RtlUnicodeToMultiByteSize( &cls_len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
844 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
846 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
847 status
= STATUS_BUFFER_OVERFLOW
;
851 RtlUnicodeToMultiByteN( name
, len
, NULL
, info
->Name
, info
->NameLength
);
855 *class_len
= cls_len
;
858 RtlUnicodeToMultiByteN( class, cls_len
, NULL
,
859 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
867 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
868 return RtlNtStatusToDosError( status
);
872 /******************************************************************************
873 * RegEnumKeyW [ADVAPI32.@]
875 * Enumerates subkeys of the specified open reg key.
878 * hKey [I] Handle to an open key.
879 * dwIndex [I] Index of the subkey of hKey to retrieve.
880 * lpName [O] Name of the subkey.
881 * cchName [I] Size of lpName in TCHARS.
884 * Success: ERROR_SUCCESS
885 * Failure: system error code. If there are no more subkeys available, the
886 * function returns ERROR_NO_MORE_ITEMS.
888 LSTATUS WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
890 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
894 /******************************************************************************
895 * RegEnumKeyA [ADVAPI32.@]
899 LSTATUS WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
901 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
905 /******************************************************************************
906 * RegQueryInfoKeyW [ADVAPI32.@]
908 * Retrieves information about the specified registry key.
911 * hkey [I] Handle to key to query
912 * class [O] Buffer for class string
913 * class_len [O] Size of class string buffer
914 * reserved [I] Reserved
915 * subkeys [O] Buffer for number of subkeys
916 * max_subkey [O] Buffer for longest subkey name length
917 * max_class [O] Buffer for longest class string length
918 * values [O] Buffer for number of value entries
919 * max_value [O] Buffer for longest value name length
920 * max_data [O] Buffer for longest value data length
921 * security [O] Buffer for security descriptor length
922 * modif [O] Modification time
925 * Success: ERROR_SUCCESS
926 * Failure: system error code.
929 * - win95 allows class to be valid and class_len to be NULL
930 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
931 * - both allow class to be NULL and class_len to be NULL
932 * (it's hard to test validity, so test !NULL instead)
934 LSTATUS WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
935 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
936 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
937 LPDWORD security
, FILETIME
*modif
)
940 char buffer
[256], *buf_ptr
= buffer
;
941 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
944 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
945 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
947 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
948 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
950 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
951 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
953 if (class && class_len
&& *class_len
)
955 /* retry with a dynamically allocated buffer */
956 while (status
== STATUS_BUFFER_OVERFLOW
)
958 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
959 if (!(buf_ptr
= heap_alloc( total_size
)))
960 return ERROR_NOT_ENOUGH_MEMORY
;
961 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
962 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
965 if (status
) goto done
;
967 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
969 status
= STATUS_BUFFER_TOO_SMALL
;
973 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
974 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
977 else status
= STATUS_SUCCESS
;
979 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
980 if (subkeys
) *subkeys
= info
->SubKeys
;
981 if (max_subkey
) *max_subkey
= info
->MaxNameLen
/ sizeof(WCHAR
);
982 if (max_class
) *max_class
= info
->MaxClassLen
/ sizeof(WCHAR
);
983 if (values
) *values
= info
->Values
;
984 if (max_value
) *max_value
= info
->MaxValueNameLen
/ sizeof(WCHAR
);
985 if (max_data
) *max_data
= info
->MaxValueDataLen
;
986 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
990 FIXME( "security argument not supported.\n");
995 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
996 return RtlNtStatusToDosError( status
);
1000 /******************************************************************************
1001 * RegQueryMultipleValuesA [ADVAPI32.@]
1003 * Retrieves the type and data for a list of value names associated with a key.
1006 * hKey [I] Handle to an open key.
1007 * val_list [O] Array of VALENT structures that describes the entries.
1008 * num_vals [I] Number of elements in val_list.
1009 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
1010 * ldwTotsize [I/O] Size of lpValueBuf.
1013 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
1014 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
1017 LSTATUS WINAPI
RegQueryMultipleValuesA( HKEY hkey
, PVALENTA val_list
, DWORD num_vals
,
1018 LPSTR lpValueBuf
, LPDWORD ldwTotsize
)
1021 DWORD maxBytes
= *ldwTotsize
;
1023 LPSTR bufptr
= lpValueBuf
;
1026 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
1028 for(i
=0; i
< num_vals
; ++i
)
1031 val_list
[i
].ve_valuelen
=0;
1032 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
1033 if(status
!= ERROR_SUCCESS
)
1038 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
1040 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
1041 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
1042 if(status
!= ERROR_SUCCESS
)
1047 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
1049 bufptr
+= val_list
[i
].ve_valuelen
;
1052 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
1054 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
1058 /******************************************************************************
1059 * RegQueryMultipleValuesW [ADVAPI32.@]
1061 * See RegQueryMultipleValuesA.
1063 LSTATUS WINAPI
RegQueryMultipleValuesW( HKEY hkey
, PVALENTW val_list
, DWORD num_vals
,
1064 LPWSTR lpValueBuf
, LPDWORD ldwTotsize
)
1067 DWORD maxBytes
= *ldwTotsize
;
1069 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
1072 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
1074 for(i
=0; i
< num_vals
; ++i
)
1076 val_list
[i
].ve_valuelen
=0;
1077 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
1078 if(status
!= ERROR_SUCCESS
)
1083 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
1085 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
1086 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
1087 if(status
!= ERROR_SUCCESS
)
1092 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
1094 bufptr
+= val_list
[i
].ve_valuelen
;
1097 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
1099 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
1102 /******************************************************************************
1103 * RegQueryInfoKeyA [ADVAPI32.@]
1105 * Retrieves information about a registry key.
1108 * hKey [I] Handle to an open key.
1109 * lpClass [O] Class string of the key.
1110 * lpcClass [I/O] size of lpClass.
1111 * lpReserved [I] Reserved; must be NULL.
1112 * lpcSubKeys [O] Number of subkeys contained by the key.
1113 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
1114 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
1116 * lpcValues [O] Number of values associated with the key.
1117 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
1118 * lpcMaxValueLen [O] Longest data component among the key's values
1119 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
1120 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
1123 * Success: ERROR_SUCCESS
1124 * Failure: nonzero error code from Winerror.h
1126 LSTATUS WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
1127 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
1128 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
1129 LPDWORD security
, FILETIME
*modif
)
1132 char buffer
[256], *buf_ptr
= buffer
;
1133 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
1134 DWORD total_size
, len
;
1136 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
1137 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
1139 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
1140 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1142 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
1143 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1145 if (class || class_len
)
1147 /* retry with a dynamically allocated buffer */
1148 while (status
== STATUS_BUFFER_OVERFLOW
)
1150 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1151 if (!(buf_ptr
= heap_alloc( total_size
)))
1152 return ERROR_NOT_ENOUGH_MEMORY
;
1153 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
1154 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
1157 if (status
) goto done
;
1160 if (class && class_len
) len
= *class_len
;
1161 RtlUnicodeToMultiByteN( class, len
, class_len
,
1162 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
), info
->ClassLength
);
1165 if (*class_len
+ 1 > len
)
1167 status
= STATUS_BUFFER_OVERFLOW
;
1170 class[*class_len
] = 0;
1173 else status
= STATUS_SUCCESS
;
1175 if (subkeys
) *subkeys
= info
->SubKeys
;
1176 if (max_subkey
) *max_subkey
= info
->MaxNameLen
/ sizeof(WCHAR
);
1177 if (max_class
) *max_class
= info
->MaxClassLen
/ sizeof(WCHAR
);
1178 if (values
) *values
= info
->Values
;
1179 if (max_value
) *max_value
= info
->MaxValueNameLen
/ sizeof(WCHAR
);
1180 if (max_data
) *max_data
= info
->MaxValueDataLen
;
1181 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
1185 FIXME( "security argument not supported.\n");
1190 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1191 return RtlNtStatusToDosError( status
);
1195 /******************************************************************************
1196 * RegCloseKey [ADVAPI32.@]
1198 * Close an open registry key.
1201 * hkey [I] Handle of key to close
1204 * Success: ERROR_SUCCESS
1205 * Failure: Error code
1207 LSTATUS WINAPI DECLSPEC_HOTPATCH
RegCloseKey( HKEY hkey
)
1209 if (!hkey
) return ERROR_INVALID_HANDLE
;
1210 if (hkey
>= (HKEY
)0x80000000) return ERROR_SUCCESS
;
1211 return RtlNtStatusToDosError( NtClose( hkey
) );
1215 /******************************************************************************
1216 * RegDeleteKeyExW [ADVAPI32.@]
1218 LSTATUS WINAPI
RegDeleteKeyExW( HKEY hkey
, LPCWSTR name
, REGSAM access
, DWORD reserved
)
1223 if (!name
) return ERROR_INVALID_PARAMETER
;
1225 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
1227 access
&= KEY_WOW64_64KEY
| KEY_WOW64_32KEY
;
1228 if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, access
| DELETE
, &tmp
)))
1230 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
1233 TRACE("%s ret=%08x\n", debugstr_w(name
), ret
);
1238 /******************************************************************************
1239 * RegDeleteKeyW [ADVAPI32.@]
1241 * See RegDeleteKeyA.
1243 LSTATUS WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
1245 return RegDeleteKeyExW( hkey
, name
, 0, 0 );
1249 /******************************************************************************
1250 * RegDeleteKeyExA [ADVAPI32.@]
1252 LSTATUS WINAPI
RegDeleteKeyExA( HKEY hkey
, LPCSTR name
, REGSAM access
, DWORD reserved
)
1257 if (!name
) return ERROR_INVALID_PARAMETER
;
1259 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
1261 access
&= KEY_WOW64_64KEY
| KEY_WOW64_32KEY
;
1262 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, access
| DELETE
, &tmp
)))
1264 if (!is_version_nt()) /* win95 does recursive key deletes */
1268 while(!RegEnumKeyA(tmp
, 0, sub
, sizeof(sub
)))
1270 if(RegDeleteKeyExA(tmp
, sub
, access
, reserved
)) /* recurse */
1274 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
1277 TRACE("%s ret=%08x\n", debugstr_a(name
), ret
);
1282 /******************************************************************************
1283 * RegDeleteKeyA [ADVAPI32.@]
1285 * Delete a registry key.
1288 * hkey [I] Handle to parent key containing the key to delete
1289 * name [I] Name of the key user hkey to delete
1293 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1294 * right. In reality, it opens a new handle with DELETE access.
1297 * Success: ERROR_SUCCESS
1298 * Failure: Error code
1300 LSTATUS WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
1302 return RegDeleteKeyExA( hkey
, name
, 0, 0 );
1307 /******************************************************************************
1308 * RegSetValueExW [ADVAPI32.@]
1310 * Set the data and contents of a registry value.
1313 * hkey [I] Handle of key to set value for
1314 * name [I] Name of value to set
1315 * reserved [I] Reserved, must be zero
1316 * type [I] Type of the value being set
1317 * data [I] The new contents of the value to set
1318 * count [I] Size of data
1321 * Success: ERROR_SUCCESS
1322 * Failure: Error code
1324 LSTATUS WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
1325 DWORD type
, const BYTE
*data
, DWORD count
)
1327 UNICODE_STRING nameW
;
1329 /* no need for version check, not implemented on win9x anyway */
1331 if ((data
&& ((ULONG_PTR
)data
>> 16) == 0) || (!data
&& count
)) return ERROR_NOACCESS
;
1333 if (count
&& is_string(type
))
1335 LPCWSTR str
= (LPCWSTR
)data
;
1336 /* if user forgot to count terminating null, add it (yes NT does this) */
1337 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
1338 count
+= sizeof(WCHAR
);
1340 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1342 RtlInitUnicodeString( &nameW
, name
);
1343 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
1347 /******************************************************************************
1348 * RegSetValueExA [ADVAPI32.@]
1350 * See RegSetValueExW.
1353 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1354 * NT does definitely care (aj)
1356 LSTATUS WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1357 const BYTE
*data
, DWORD count
)
1360 UNICODE_STRING nameW
;
1361 WCHAR
*dataW
= NULL
;
1364 if (!is_version_nt()) /* win95 */
1368 if (!data
) return ERROR_INVALID_PARAMETER
;
1369 count
= strlen((const char *)data
) + 1;
1372 else if (count
&& is_string(type
))
1374 /* if user forgot to count terminating null, add it (yes NT does this) */
1375 if (data
[count
-1] && !data
[count
]) count
++;
1378 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1380 if (is_string( type
)) /* need to convert to Unicode */
1383 RtlMultiByteToUnicodeSize( &lenW
, (const char *)data
, count
);
1384 if (!(dataW
= heap_alloc( lenW
))) return ERROR_OUTOFMEMORY
;
1385 RtlMultiByteToUnicodeN( dataW
, lenW
, NULL
, (const char *)data
, count
);
1387 data
= (BYTE
*)dataW
;
1390 RtlInitAnsiString( &nameA
, name
);
1391 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1393 status
= NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
);
1394 RtlFreeUnicodeString( &nameW
);
1397 return RtlNtStatusToDosError( status
);
1401 /******************************************************************************
1402 * RegSetValueW [ADVAPI32.@]
1404 * Sets the data for the default or unnamed value of a reg key.
1407 * hkey [I] Handle to an open key.
1408 * subkey [I] Name of a subkey of hKey.
1409 * type [I] Type of information to store.
1410 * data [I] String that contains the data to set for the default value.
1411 * count [I] Ignored.
1414 * Success: ERROR_SUCCESS
1415 * Failure: nonzero error code from Winerror.h
1417 LSTATUS WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR subkey
, DWORD type
, LPCWSTR data
, DWORD count
)
1419 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_w(subkey
), type
, debugstr_w(data
), count
);
1421 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1423 return RegSetKeyValueW( hkey
, subkey
, NULL
, type
, data
, (strlenW(data
) + 1)*sizeof(WCHAR
) );
1426 /******************************************************************************
1427 * RegSetValueA [ADVAPI32.@]
1431 LSTATUS WINAPI
RegSetValueA( HKEY hkey
, LPCSTR subkey
, DWORD type
, LPCSTR data
, DWORD count
)
1433 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_a(subkey
), type
, debugstr_a(data
), count
);
1435 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1437 return RegSetKeyValueA( hkey
, subkey
, NULL
, type
, data
, strlen(data
) + 1 );
1440 /******************************************************************************
1441 * RegSetKeyValueW [ADVAPI32.@]
1443 LONG WINAPI
RegSetKeyValueW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR name
, DWORD type
, const void *data
, DWORD len
)
1445 HKEY hsubkey
= NULL
;
1448 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey
, debugstr_w(subkey
), debugstr_w(name
), type
, data
, len
);
1450 if (subkey
&& subkey
[0]) /* need to create the subkey */
1452 if ((ret
= RegCreateKeyW( hkey
, subkey
, &hsubkey
)) != ERROR_SUCCESS
) return ret
;
1456 ret
= RegSetValueExW( hkey
, name
, 0, type
, (const BYTE
*)data
, len
);
1457 if (hsubkey
) RegCloseKey( hsubkey
);
1461 /******************************************************************************
1462 * RegSetKeyValueA [ADVAPI32.@]
1464 LONG WINAPI
RegSetKeyValueA( HKEY hkey
, LPCSTR subkey
, LPCSTR name
, DWORD type
, const void *data
, DWORD len
)
1466 HKEY hsubkey
= NULL
;
1469 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey
, debugstr_a(subkey
), debugstr_a(name
), type
, data
, len
);
1471 if (subkey
&& subkey
[0]) /* need to create the subkey */
1473 if ((ret
= RegCreateKeyA( hkey
, subkey
, &hsubkey
)) != ERROR_SUCCESS
) return ret
;
1477 ret
= RegSetValueExA( hkey
, name
, 0, type
, (const BYTE
*)data
, len
);
1478 if (hsubkey
) RegCloseKey( hsubkey
);
1482 /******************************************************************************
1483 * RegQueryValueExW [ADVAPI32.@]
1485 * See RegQueryValueExA.
1487 LSTATUS WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
1488 LPBYTE data
, LPDWORD count
)
1491 UNICODE_STRING name_str
;
1493 char buffer
[256], *buf_ptr
= buffer
;
1494 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1495 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1497 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1498 hkey
, debugstr_w(name
), reserved
, type
, data
, count
,
1499 (count
&& data
) ? *count
: 0 );
1501 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1502 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1504 RtlInitUnicodeString( &name_str
, name
);
1506 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
1509 total_size
= info_size
;
1510 if (count
) *count
= 0;
1513 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1514 buffer
, total_size
, &total_size
);
1515 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1519 /* retry with a dynamically allocated buffer */
1520 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
1522 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1523 if (!(buf_ptr
= heap_alloc( total_size
)))
1524 return ERROR_NOT_ENOUGH_MEMORY
;
1525 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1526 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1527 buf_ptr
, total_size
, &total_size
);
1532 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1533 /* if the type is REG_SZ and data is not 0-terminated
1534 * and there is enough space in the buffer NT appends a \0 */
1535 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1537 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
1538 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1541 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1543 else status
= STATUS_SUCCESS
;
1545 if (type
) *type
= info
->Type
;
1546 if (count
) *count
= total_size
- info_size
;
1549 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1550 return RtlNtStatusToDosError(status
);
1554 /******************************************************************************
1555 * RegQueryValueExA [ADVAPI32.@]
1557 * Get the type and contents of a specified value under with a key.
1560 * hkey [I] Handle of the key to query
1561 * name [I] Name of value under hkey to query
1562 * reserved [I] Reserved - must be NULL
1563 * type [O] Destination for the value type, or NULL if not required
1564 * data [O] Destination for the values contents, or NULL if not required
1565 * count [I/O] Size of data, updated with the number of bytes returned
1568 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1569 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1570 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1571 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1574 * MSDN states that if data is too small it is partially filled. In reality
1575 * it remains untouched.
1577 LSTATUS WINAPI DECLSPEC_HOTPATCH
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
,
1578 LPDWORD type
, LPBYTE data
, LPDWORD count
)
1582 UNICODE_STRING nameW
;
1583 DWORD total_size
, datalen
= 0;
1584 char buffer
[256], *buf_ptr
= buffer
;
1585 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1586 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1588 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1589 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
1591 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1592 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1594 if (count
) datalen
= *count
;
1595 if (!data
&& count
) *count
= 0;
1597 /* this matches Win9x behaviour - NT sets *type to a random value */
1598 if (type
) *type
= REG_NONE
;
1600 RtlInitAnsiString( &nameA
, name
);
1601 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1602 return RtlNtStatusToDosError(status
);
1604 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1605 buffer
, sizeof(buffer
), &total_size
);
1606 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1608 /* we need to fetch the contents for a string type even if not requested,
1609 * because we need to compute the length of the ASCII string. */
1610 if (data
|| is_string(info
->Type
))
1612 /* retry with a dynamically allocated buffer */
1613 while (status
== STATUS_BUFFER_OVERFLOW
)
1615 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1616 if (!(buf_ptr
= heap_alloc( total_size
)))
1618 status
= STATUS_NO_MEMORY
;
1621 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1622 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1623 buf_ptr
, total_size
, &total_size
);
1626 if (status
) goto done
;
1628 if (is_string(info
->Type
))
1632 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
1633 total_size
- info_size
);
1636 if (len
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1639 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
1640 total_size
- info_size
);
1641 /* if the type is REG_SZ and data is not 0-terminated
1642 * and there is enough space in the buffer NT appends a \0 */
1643 if (len
< datalen
&& data
[len
-1]) data
[len
] = 0;
1646 total_size
= len
+ info_size
;
1650 if (total_size
- info_size
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1651 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1654 else status
= STATUS_SUCCESS
;
1656 if (type
) *type
= info
->Type
;
1657 if (count
) *count
= total_size
- info_size
;
1660 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1661 RtlFreeUnicodeString( &nameW
);
1662 return RtlNtStatusToDosError(status
);
1666 /******************************************************************************
1667 * RegQueryValueW [ADVAPI32.@]
1669 * Retrieves the data associated with the default or unnamed value of a key.
1672 * hkey [I] Handle to an open key.
1673 * name [I] Name of the subkey of hKey.
1674 * data [O] Receives the string associated with the default value
1676 * count [I/O] Size of lpValue in bytes.
1679 * Success: ERROR_SUCCESS
1680 * Failure: nonzero error code from Winerror.h
1682 LSTATUS WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
1687 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
1689 if (name
&& name
[0])
1691 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1693 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1694 if (subkey
!= hkey
) RegCloseKey( subkey
);
1695 if (ret
== ERROR_FILE_NOT_FOUND
)
1697 /* return empty string if default value not found */
1698 if (data
) *data
= 0;
1699 if (count
) *count
= sizeof(WCHAR
);
1700 ret
= ERROR_SUCCESS
;
1706 /******************************************************************************
1707 * RegQueryValueA [ADVAPI32.@]
1709 * See RegQueryValueW.
1711 LSTATUS WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
1716 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
1718 if (name
&& name
[0])
1720 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1722 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1723 if (subkey
!= hkey
) RegCloseKey( subkey
);
1724 if (ret
== ERROR_FILE_NOT_FOUND
)
1726 /* return empty string if default value not found */
1727 if (data
) *data
= 0;
1728 if (count
) *count
= 1;
1729 ret
= ERROR_SUCCESS
;
1735 /******************************************************************************
1736 * ADVAPI_ApplyRestrictions [internal]
1738 * Helper function for RegGetValueA/W.
1740 static VOID
ADVAPI_ApplyRestrictions( DWORD dwFlags
, DWORD dwType
,
1741 DWORD cbData
, PLONG ret
)
1743 /* Check if the type is restricted by the passed flags */
1744 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1750 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1751 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1752 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1753 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1754 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1755 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1756 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1759 if (dwFlags
& dwMask
)
1761 /* Type is not restricted, check for size mismatch */
1762 if (dwType
== REG_BINARY
)
1766 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
1768 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
1771 if (cbExpect
&& cbData
!= cbExpect
)
1772 *ret
= ERROR_DATATYPE_MISMATCH
;
1775 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1780 /******************************************************************************
1781 * RegGetValueW [ADVAPI32.@]
1783 * Retrieves the type and data for a value name associated with a key,
1784 * optionally expanding its content and restricting its type.
1787 * hKey [I] Handle to an open key.
1788 * pszSubKey [I] Name of the subkey of hKey.
1789 * pszValue [I] Name of value under hKey/szSubKey to query.
1790 * dwFlags [I] Flags restricting the value type to retrieve.
1791 * pdwType [O] Destination for the values type, may be NULL.
1792 * pvData [O] Destination for the values content, may be NULL.
1793 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1794 * retrieve the whole content, including the trailing '\0'
1798 * Success: ERROR_SUCCESS
1799 * Failure: nonzero error code from Winerror.h
1802 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1803 * expanded and pdwType is set to REG_SZ instead.
1804 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1805 * without RRF_NOEXPAND is thus not allowed.
1806 * An exception is the case where RRF_RT_ANY is specified, because then
1807 * RRF_NOEXPAND is allowed.
1809 LSTATUS WINAPI
RegGetValueW( HKEY hKey
, LPCWSTR pszSubKey
, LPCWSTR pszValue
,
1810 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1813 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1817 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1818 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1819 pvData
, pcbData
, cbData
);
1821 if (pvData
&& !pcbData
)
1822 return ERROR_INVALID_PARAMETER
;
1823 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1824 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1825 return ERROR_INVALID_PARAMETER
;
1827 if (pszSubKey
&& pszSubKey
[0])
1829 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1830 if (ret
!= ERROR_SUCCESS
) return ret
;
1833 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1835 /* If we are going to expand we need to read in the whole the value even
1836 * if the passed buffer was too small as the expanded string might be
1837 * smaller than the unexpanded one and could fit into cbData bytes. */
1838 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1839 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1844 pvBuf
= heap_alloc(cbData
);
1847 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1851 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1852 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
1853 &dwType
, pvBuf
, &cbData
);
1856 /* Even if cbData was large enough we have to copy the
1857 * string since ExpandEnvironmentStrings can't handle
1858 * overlapping buffers. */
1859 CopyMemory(pvBuf
, pvData
, cbData
);
1862 /* Both the type or the value itself could have been modified in
1863 * between so we have to keep retrying until the buffer is large
1864 * enough or we no longer have to expand the value. */
1865 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1867 if (ret
== ERROR_SUCCESS
)
1869 /* Recheck dwType in case it changed since the first call */
1870 if (dwType
== REG_EXPAND_SZ
)
1872 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
1873 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
1875 if(pvData
&& pcbData
&& cbData
> *pcbData
)
1876 ret
= ERROR_MORE_DATA
;
1879 CopyMemory(pvData
, pvBuf
, *pcbData
);
1885 if (pszSubKey
&& pszSubKey
[0])
1888 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1890 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1891 ZeroMemory(pvData
, *pcbData
);
1893 if (pdwType
) *pdwType
= dwType
;
1894 if (pcbData
) *pcbData
= cbData
;
1900 /******************************************************************************
1901 * RegGetValueA [ADVAPI32.@]
1905 LSTATUS WINAPI
RegGetValueA( HKEY hKey
, LPCSTR pszSubKey
, LPCSTR pszValue
,
1906 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1909 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1913 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1914 hKey
, debugstr_a(pszSubKey
), debugstr_a(pszValue
), dwFlags
,
1915 pdwType
, pvData
, pcbData
, cbData
);
1917 if (pvData
&& !pcbData
)
1918 return ERROR_INVALID_PARAMETER
;
1919 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1920 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1921 return ERROR_INVALID_PARAMETER
;
1923 if (pszSubKey
&& pszSubKey
[0])
1925 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1926 if (ret
!= ERROR_SUCCESS
) return ret
;
1929 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1931 /* If we are going to expand we need to read in the whole the value even
1932 * if the passed buffer was too small as the expanded string might be
1933 * smaller than the unexpanded one and could fit into cbData bytes. */
1934 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1935 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1940 pvBuf
= heap_alloc(cbData
);
1943 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1947 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1948 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
1949 &dwType
, pvBuf
, &cbData
);
1952 /* Even if cbData was large enough we have to copy the
1953 * string since ExpandEnvironmentStrings can't handle
1954 * overlapping buffers. */
1955 CopyMemory(pvBuf
, pvData
, cbData
);
1958 /* Both the type or the value itself could have been modified in
1959 * between so we have to keep retrying until the buffer is large
1960 * enough or we no longer have to expand the value. */
1961 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1963 if (ret
== ERROR_SUCCESS
)
1965 /* Recheck dwType in case it changed since the first call */
1966 if (dwType
== REG_EXPAND_SZ
)
1968 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
1969 pcbData
? *pcbData
: 0);
1971 if(pvData
&& pcbData
&& cbData
> *pcbData
)
1972 ret
= ERROR_MORE_DATA
;
1975 CopyMemory(pvData
, pvBuf
, *pcbData
);
1981 if (pszSubKey
&& pszSubKey
[0])
1984 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1986 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1987 ZeroMemory(pvData
, *pcbData
);
1989 if (pdwType
) *pdwType
= dwType
;
1990 if (pcbData
) *pcbData
= cbData
;
1996 /******************************************************************************
1997 * RegEnumValueW [ADVAPI32.@]
1999 * Enumerates the values for the specified open registry key.
2002 * hkey [I] Handle to key to query
2003 * index [I] Index of value to query
2004 * value [O] Value string
2005 * val_count [I/O] Size of value buffer (in wchars)
2006 * reserved [I] Reserved
2007 * type [O] Type code
2008 * data [O] Value data
2009 * count [I/O] Size of data buffer (in bytes)
2012 * Success: ERROR_SUCCESS
2013 * Failure: nonzero error code from Winerror.h
2016 LSTATUS WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
2017 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
2021 char buffer
[256], *buf_ptr
= buffer
;
2022 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2023 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
2025 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
2026 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
2028 if ((data
&& !count
) || reserved
|| !value
|| !val_count
)
2029 return ERROR_INVALID_PARAMETER
;
2030 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2032 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2033 if (data
) total_size
+= *count
;
2034 total_size
= min( sizeof(buffer
), total_size
);
2036 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
2037 buffer
, total_size
, &total_size
);
2039 /* retry with a dynamically allocated buffer */
2040 while (status
== STATUS_BUFFER_OVERFLOW
)
2042 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
2043 if (!(buf_ptr
= heap_alloc( total_size
)))
2044 return ERROR_NOT_ENOUGH_MEMORY
;
2045 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2046 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
2047 buf_ptr
, total_size
, &total_size
);
2050 if (status
) goto done
;
2052 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2054 status
= STATUS_BUFFER_OVERFLOW
;
2057 memcpy( value
, info
->Name
, info
->NameLength
);
2058 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2059 value
[*val_count
] = 0;
2063 if (total_size
- info
->DataOffset
> *count
)
2065 status
= STATUS_BUFFER_OVERFLOW
;
2068 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2069 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
2071 /* if the type is REG_SZ and data is not 0-terminated
2072 * and there is enough space in the buffer NT appends a \0 */
2073 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
2074 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2079 if (type
) *type
= info
->Type
;
2080 if (count
) *count
= info
->DataLength
;
2083 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
2084 return RtlNtStatusToDosError(status
);
2088 /******************************************************************************
2089 * RegEnumValueA [ADVAPI32.@]
2091 * See RegEnumValueW.
2093 LSTATUS WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
2094 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
2098 char buffer
[256], *buf_ptr
= buffer
;
2099 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2100 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
2102 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
2103 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
2105 if ((data
&& !count
) || reserved
|| !value
|| !val_count
)
2106 return ERROR_INVALID_PARAMETER
;
2107 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2109 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2110 if (data
) total_size
+= *count
;
2111 total_size
= min( sizeof(buffer
), total_size
);
2113 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
2114 buffer
, total_size
, &total_size
);
2116 /* we need to fetch the contents for a string type even if not requested,
2117 * because we need to compute the length of the ASCII string. */
2119 /* retry with a dynamically allocated buffer */
2120 while (status
== STATUS_BUFFER_OVERFLOW
)
2122 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
2123 if (!(buf_ptr
= heap_alloc( total_size
)))
2124 return ERROR_NOT_ENOUGH_MEMORY
;
2125 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2126 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
2127 buf_ptr
, total_size
, &total_size
);
2130 if (status
) goto done
;
2132 if (is_string(info
->Type
))
2135 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2136 total_size
- info
->DataOffset
);
2139 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2142 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2143 total_size
- info
->DataOffset
);
2144 /* if the type is REG_SZ and data is not 0-terminated
2145 * and there is enough space in the buffer NT appends a \0 */
2146 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2149 info
->DataLength
= len
;
2153 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2154 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2161 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2162 if (len
>= *val_count
)
2164 status
= STATUS_BUFFER_OVERFLOW
;
2167 len
= *val_count
- 1;
2168 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2174 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2180 if (type
) *type
= info
->Type
;
2181 if (count
) *count
= info
->DataLength
;
2184 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
2185 return RtlNtStatusToDosError(status
);
2188 /******************************************************************************
2189 * RegDeleteValueW [ADVAPI32.@]
2191 * See RegDeleteValueA.
2193 LSTATUS WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
2195 return RegDeleteKeyValueW( hkey
, NULL
, name
);
2198 /******************************************************************************
2199 * RegDeleteValueA [ADVAPI32.@]
2201 * Delete a value from the registry.
2204 * hkey [I] Registry handle of the key holding the value
2205 * name [I] Name of the value under hkey to delete
2208 * Success: ERROR_SUCCESS
2209 * Failure: nonzero error code from Winerror.h
2211 LSTATUS WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
2213 return RegDeleteKeyValueA( hkey
, NULL
, name
);
2216 /******************************************************************************
2217 * RegDeleteKeyValueW [ADVAPI32.@]
2219 LONG WINAPI
RegDeleteKeyValueW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR name
)
2221 UNICODE_STRING nameW
;
2225 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2229 if ((ret
= RegOpenKeyExW( hkey
, subkey
, 0, KEY_SET_VALUE
, &hsubkey
)))
2234 RtlInitUnicodeString( &nameW
, name
);
2235 ret
= RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
2236 if (hsubkey
) RegCloseKey( hsubkey
);
2240 /******************************************************************************
2241 * RegDeleteKeyValueA [ADVAPI32.@]
2243 LONG WINAPI
RegDeleteKeyValueA( HKEY hkey
, LPCSTR subkey
, LPCSTR name
)
2245 UNICODE_STRING nameW
;
2250 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2254 LONG ret
= RegOpenKeyExA( hkey
, subkey
, 0, KEY_SET_VALUE
, &hsubkey
);
2260 RtlInitAnsiString( &nameA
, name
);
2261 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
2263 status
= NtDeleteValueKey( hkey
, &nameW
);
2264 RtlFreeUnicodeString( &nameW
);
2267 if (hsubkey
) RegCloseKey( hsubkey
);
2268 return RtlNtStatusToDosError( status
);
2271 /******************************************************************************
2272 * RegLoadKeyW [ADVAPI32.@]
2274 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2275 * registration information from a specified file into that subkey.
2278 * hkey [I] Handle of open key
2279 * subkey [I] Address of name of subkey
2280 * filename [I] Address of filename for registry information
2283 * Success: ERROR_SUCCESS
2284 * Failure: nonzero error code from Winerror.h
2286 LSTATUS WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
2288 OBJECT_ATTRIBUTES destkey
, file
;
2289 UNICODE_STRING subkeyW
, filenameW
;
2292 if (!(hkey
= get_special_root_hkey(hkey
, 0))) return ERROR_INVALID_HANDLE
;
2294 destkey
.Length
= sizeof(destkey
);
2295 destkey
.RootDirectory
= hkey
; /* root key: HKLM or HKU */
2296 destkey
.ObjectName
= &subkeyW
; /* name of the key */
2297 destkey
.Attributes
= 0;
2298 destkey
.SecurityDescriptor
= NULL
;
2299 destkey
.SecurityQualityOfService
= NULL
;
2300 RtlInitUnicodeString(&subkeyW
, subkey
);
2302 file
.Length
= sizeof(file
);
2303 file
.RootDirectory
= NULL
;
2304 file
.ObjectName
= &filenameW
; /* file containing the hive */
2305 file
.Attributes
= OBJ_CASE_INSENSITIVE
;
2306 file
.SecurityDescriptor
= NULL
;
2307 file
.SecurityQualityOfService
= NULL
;
2308 RtlDosPathNameToNtPathName_U(filename
, &filenameW
, NULL
, NULL
);
2310 status
= NtLoadKey(&destkey
, &file
);
2311 RtlFreeUnicodeString(&filenameW
);
2312 return RtlNtStatusToDosError( status
);
2316 /******************************************************************************
2317 * RegLoadKeyA [ADVAPI32.@]
2321 LSTATUS WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
2323 UNICODE_STRING subkeyW
, filenameW
;
2324 STRING subkeyA
, filenameA
;
2328 RtlInitAnsiString(&subkeyA
, subkey
);
2329 RtlInitAnsiString(&filenameA
, filename
);
2331 RtlInitUnicodeString(&subkeyW
, NULL
);
2332 RtlInitUnicodeString(&filenameW
, NULL
);
2333 if (!(status
= RtlAnsiStringToUnicodeString(&subkeyW
, &subkeyA
, TRUE
)) &&
2334 !(status
= RtlAnsiStringToUnicodeString(&filenameW
, &filenameA
, TRUE
)))
2336 ret
= RegLoadKeyW(hkey
, subkeyW
.Buffer
, filenameW
.Buffer
);
2338 else ret
= RtlNtStatusToDosError(status
);
2339 RtlFreeUnicodeString(&subkeyW
);
2340 RtlFreeUnicodeString(&filenameW
);
2345 /******************************************************************************
2346 * RegSaveKeyW [ADVAPI32.@]
2348 * Save a key and all of its subkeys and values to a new file in the standard format.
2351 * hkey [I] Handle of key where save begins
2352 * lpFile [I] Address of filename to save to
2353 * sa [I] Address of security structure
2356 * Success: ERROR_SUCCESS
2357 * Failure: nonzero error code from Winerror.h
2359 LSTATUS WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
2361 static const WCHAR format
[] =
2362 {'r','e','g','%','0','4','x','.','t','m','p',0};
2363 WCHAR buffer
[MAX_PATH
];
2369 TRACE( "(%p,%s,%p)\n", hkey
, debugstr_w(file
), sa
);
2371 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
2372 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2374 err
= GetLastError();
2375 GetFullPathNameW( file
, sizeof(buffer
)/sizeof(WCHAR
), buffer
, &nameW
);
2379 snprintfW( nameW
, 16, format
, count
++ );
2380 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
2381 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
2382 if (handle
!= INVALID_HANDLE_VALUE
) break;
2383 if ((ret
= GetLastError()) != ERROR_FILE_EXISTS
) goto done
;
2385 /* Something gone haywire ? Please report if this happens abnormally */
2387 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
);
2390 ret
= RtlNtStatusToDosError(NtSaveKey(hkey
, handle
));
2392 CloseHandle( handle
);
2395 if (!MoveFileExW( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
2397 ERR( "Failed to move %s to %s\n", debugstr_w(buffer
),
2399 ret
= GetLastError();
2402 if (ret
) DeleteFileW( buffer
);
2405 SetLastError( err
); /* restore last error code */
2410 /******************************************************************************
2411 * RegSaveKeyA [ADVAPI32.@]
2415 LSTATUS WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
2417 UNICODE_STRING
*fileW
= &NtCurrentTeb()->StaticUnicodeString
;
2421 RtlInitAnsiString(&fileA
, file
);
2422 if ((status
= RtlAnsiStringToUnicodeString(fileW
, &fileA
, FALSE
)))
2423 return RtlNtStatusToDosError( status
);
2424 return RegSaveKeyW(hkey
, fileW
->Buffer
, sa
);
2428 /******************************************************************************
2429 * RegRestoreKeyW [ADVAPI32.@]
2431 * Read the registry information from a file and copy it over a key.
2434 * hkey [I] Handle of key where restore begins
2435 * lpFile [I] Address of filename containing saved tree
2436 * dwFlags [I] Optional flags
2439 * Success: ERROR_SUCCESS
2440 * Failure: nonzero error code from Winerror.h
2442 LSTATUS WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
2444 TRACE("(%p,%s,%d)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2446 /* It seems to do this check before the hkey check */
2447 if (!lpFile
|| !*lpFile
)
2448 return ERROR_INVALID_PARAMETER
;
2450 FIXME("(%p,%s,%d): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2452 /* Check for file existence */
2454 return ERROR_SUCCESS
;
2458 /******************************************************************************
2459 * RegRestoreKeyA [ADVAPI32.@]
2461 * See RegRestoreKeyW.
2463 LSTATUS WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
2465 UNICODE_STRING lpFileW
;
2468 RtlCreateUnicodeStringFromAsciiz( &lpFileW
, lpFile
);
2469 ret
= RegRestoreKeyW( hkey
, lpFileW
.Buffer
, dwFlags
);
2470 RtlFreeUnicodeString( &lpFileW
);
2475 /******************************************************************************
2476 * RegUnLoadKeyW [ADVAPI32.@]
2478 * Unload a registry key and its subkeys from the registry.
2481 * hkey [I] Handle of open key
2482 * lpSubKey [I] Address of name of subkey to unload
2485 * Success: ERROR_SUCCESS
2486 * Failure: nonzero error code from Winerror.h
2488 LSTATUS WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
2492 OBJECT_ATTRIBUTES attr
;
2493 UNICODE_STRING subkey
;
2495 TRACE("(%p,%s)\n",hkey
, debugstr_w(lpSubKey
));
2497 ret
= RegOpenKeyW(hkey
,lpSubKey
,&shkey
);
2499 return ERROR_INVALID_PARAMETER
;
2501 RtlInitUnicodeString(&subkey
, lpSubKey
);
2502 InitializeObjectAttributes(&attr
, &subkey
, OBJ_CASE_INSENSITIVE
, shkey
, NULL
);
2503 ret
= RtlNtStatusToDosError(NtUnloadKey(&attr
));
2511 /******************************************************************************
2512 * RegUnLoadKeyA [ADVAPI32.@]
2514 * See RegUnLoadKeyW.
2516 LSTATUS WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
2518 UNICODE_STRING lpSubKeyW
;
2521 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2522 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
.Buffer
);
2523 RtlFreeUnicodeString( &lpSubKeyW
);
2528 /******************************************************************************
2529 * RegReplaceKeyW [ADVAPI32.@]
2531 * Replace the file backing a registry key and all its subkeys with another file.
2534 * hkey [I] Handle of open key
2535 * lpSubKey [I] Address of name of subkey
2536 * lpNewFile [I] Address of filename for file with new data
2537 * lpOldFile [I] Address of filename for backup file
2540 * Success: ERROR_SUCCESS
2541 * Failure: nonzero error code from Winerror.h
2543 LSTATUS WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
2546 FIXME("(%p,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
2547 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
2548 return ERROR_SUCCESS
;
2552 /******************************************************************************
2553 * RegReplaceKeyA [ADVAPI32.@]
2555 * See RegReplaceKeyW.
2557 LSTATUS WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
2560 UNICODE_STRING lpSubKeyW
;
2561 UNICODE_STRING lpNewFileW
;
2562 UNICODE_STRING lpOldFileW
;
2565 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2566 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW
, lpOldFile
);
2567 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW
, lpNewFile
);
2568 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
.Buffer
, lpNewFileW
.Buffer
, lpOldFileW
.Buffer
);
2569 RtlFreeUnicodeString( &lpOldFileW
);
2570 RtlFreeUnicodeString( &lpNewFileW
);
2571 RtlFreeUnicodeString( &lpSubKeyW
);
2576 /******************************************************************************
2577 * RegSetKeySecurity [ADVAPI32.@]
2579 * Set the security of an open registry key.
2582 * hkey [I] Open handle of key to set
2583 * SecurityInfo [I] Descriptor contents
2584 * pSecurityDesc [I] Address of descriptor for key
2587 * Success: ERROR_SUCCESS
2588 * Failure: nonzero error code from Winerror.h
2590 LSTATUS WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
2591 PSECURITY_DESCRIPTOR pSecurityDesc
)
2593 TRACE("(%p,%d,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
2595 /* It seems to perform this check before the hkey check */
2596 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
2597 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
2598 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
2599 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
2602 return ERROR_INVALID_PARAMETER
;
2605 return ERROR_INVALID_PARAMETER
;
2607 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2609 return RtlNtStatusToDosError( NtSetSecurityObject( hkey
, SecurityInfo
, pSecurityDesc
) );
2613 /******************************************************************************
2614 * RegGetKeySecurity [ADVAPI32.@]
2616 * Get a copy of the security descriptor for a given registry key.
2619 * hkey [I] Open handle of key to set
2620 * SecurityInformation [I] Descriptor contents
2621 * pSecurityDescriptor [O] Address of descriptor for key
2622 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2625 * Success: ERROR_SUCCESS
2626 * Failure: Error code
2628 LSTATUS WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
2629 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2630 LPDWORD lpcbSecurityDescriptor
)
2632 TRACE("(%p,%d,%p,%d)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
2633 *lpcbSecurityDescriptor
);
2635 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2637 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey
,
2638 SecurityInformation
, pSecurityDescriptor
,
2639 *lpcbSecurityDescriptor
, lpcbSecurityDescriptor
) );
2643 /******************************************************************************
2644 * RegFlushKey [ADVAPI32.@]
2646 * Immediately write a registry key to registry.
2649 * hkey [I] Handle of key to write
2652 * Success: ERROR_SUCCESS
2653 * Failure: Error code
2655 LSTATUS WINAPI
RegFlushKey( HKEY hkey
)
2657 hkey
= get_special_root_hkey( hkey
, 0 );
2658 if (!hkey
) return ERROR_INVALID_HANDLE
;
2660 return RtlNtStatusToDosError( NtFlushKey( hkey
) );
2664 /******************************************************************************
2665 * RegConnectRegistryW [ADVAPI32.@]
2667 * Establish a connection to a predefined registry key on another computer.
2670 * lpMachineName [I] Address of name of remote computer
2671 * hHey [I] Predefined registry handle
2672 * phkResult [I] Address of buffer for remote registry handle
2675 * Success: ERROR_SUCCESS
2676 * Failure: nonzero error code from Winerror.h
2678 LSTATUS WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
2683 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName
), hKey
, phkResult
);
2685 if (!lpMachineName
|| !*lpMachineName
) {
2686 /* Use the local machine name */
2687 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
2690 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
2691 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
2693 /* MSDN says lpMachineName must start with \\ : not so */
2694 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
2696 if (GetComputerNameW(compName
, &len
))
2698 if (!strcmpiW(lpMachineName
, compName
))
2699 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
2702 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
2703 ret
= ERROR_BAD_NETPATH
;
2707 ret
= GetLastError();
2713 /******************************************************************************
2714 * RegConnectRegistryA [ADVAPI32.@]
2716 * See RegConnectRegistryW.
2718 LSTATUS WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, PHKEY reskey
)
2720 UNICODE_STRING machineW
;
2723 RtlCreateUnicodeStringFromAsciiz( &machineW
, machine
);
2724 ret
= RegConnectRegistryW( machineW
.Buffer
, hkey
, reskey
);
2725 RtlFreeUnicodeString( &machineW
);
2730 /******************************************************************************
2731 * RegNotifyChangeKeyValue [ADVAPI32.@]
2733 * Notify the caller about changes to the attributes or contents of a registry key.
2736 * hkey [I] Handle of key to watch
2737 * fWatchSubTree [I] Flag for subkey notification
2738 * fdwNotifyFilter [I] Changes to be reported
2739 * hEvent [I] Handle of signaled event
2740 * fAsync [I] Flag for asynchronous reporting
2743 * Success: ERROR_SUCCESS
2744 * Failure: nonzero error code from Winerror.h
2746 LSTATUS WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
2747 DWORD fdwNotifyFilter
, HANDLE hEvent
,
2751 IO_STATUS_BLOCK iosb
;
2753 hkey
= get_special_root_hkey( hkey
, 0 );
2754 if (!hkey
) return ERROR_INVALID_HANDLE
;
2756 TRACE("(%p,%i,%d,%p,%i)\n", hkey
, fWatchSubTree
, fdwNotifyFilter
,
2759 status
= NtNotifyChangeKey( hkey
, hEvent
, NULL
, NULL
, &iosb
,
2760 fdwNotifyFilter
, fWatchSubTree
, NULL
, 0,
2763 if (status
&& status
!= STATUS_PENDING
)
2764 return RtlNtStatusToDosError( status
);
2766 return ERROR_SUCCESS
;
2769 /******************************************************************************
2770 * RegOpenUserClassesRoot [ADVAPI32.@]
2772 * Open the HKEY_CLASSES_ROOT key for a user.
2775 * hToken [I] Handle of token representing the user
2776 * dwOptions [I] Reserved, must be 0
2777 * samDesired [I] Desired access rights
2778 * phkResult [O] Destination for the resulting key handle
2781 * Success: ERROR_SUCCESS
2782 * Failure: nonzero error code from Winerror.h
2785 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2786 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2787 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2789 LSTATUS WINAPI
RegOpenUserClassesRoot(
2796 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken
, dwOptions
, samDesired
, phkResult
);
2798 *phkResult
= HKEY_CLASSES_ROOT
;
2799 return ERROR_SUCCESS
;
2802 /******************************************************************************
2803 * load_string [Internal]
2805 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2806 * avoid importing user32, which is higher level than advapi32. Helper for
2809 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
2816 /* Negative values have to be inverted. */
2817 if (HIWORD(resId
) == 0xffff)
2818 resId
= (UINT
)(-((INT
)resId
));
2820 /* Load the resource into memory and get a pointer to it. */
2821 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
2822 if (!hResource
) return 0;
2823 hMemory
= LoadResource(hModule
, hResource
);
2824 if (!hMemory
) return 0;
2825 pString
= LockResource(hMemory
);
2827 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2828 idxString
= resId
& 0xf;
2829 while (idxString
--) pString
+= *pString
+ 1;
2831 /* If no buffer is given, return length of the string. */
2832 if (!pwszBuffer
) return *pString
;
2834 /* Else copy over the string, respecting the buffer size. */
2835 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
2836 if (cMaxChars
>= 0) {
2837 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
2838 pwszBuffer
[cMaxChars
] = '\0';
2844 /******************************************************************************
2845 * RegLoadMUIStringW [ADVAPI32.@]
2847 * Load the localized version of a string resource from some PE, respective
2848 * id and path of which are given in the registry value in the format
2849 * @[path]\dllname,-resourceId
2852 * hKey [I] Key, of which to load the string value from.
2853 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2854 * pszBuffer [O] Buffer to store the localized string in.
2855 * cbBuffer [I] Size of the destination buffer in bytes.
2856 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2857 * dwFlags [I] None supported yet.
2858 * pszBaseDir [I] Not supported yet.
2861 * Success: ERROR_SUCCESS,
2862 * Failure: nonzero error code from winerror.h
2865 * This is an API of Windows Vista, which wasn't available at the time this code
2866 * was written. We have to check for the correct behaviour once it's available.
2868 LSTATUS WINAPI
RegLoadMUIStringW(HKEY hKey
, LPCWSTR pwszValue
, LPWSTR pwszBuffer
, DWORD cbBuffer
,
2869 LPDWORD pcbData
, DWORD dwFlags
, LPCWSTR pwszBaseDir
)
2871 DWORD dwValueType
, cbData
;
2872 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
2875 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2876 "dwFlags = %d, pwszBaseDir = %s)\n", hKey
, debugstr_w(pwszValue
), pwszBuffer
,
2877 cbBuffer
, pcbData
, dwFlags
, debugstr_w(pwszBaseDir
));
2879 /* Parameter sanity checks. */
2880 if (!hKey
|| !pwszBuffer
)
2881 return ERROR_INVALID_PARAMETER
;
2883 if (pwszBaseDir
&& *pwszBaseDir
) {
2884 FIXME("BaseDir parameter not yet supported!\n");
2885 return ERROR_INVALID_PARAMETER
;
2888 /* Check for value existence and correctness of its type, allocate a buffer and load it. */
2889 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
2890 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2891 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
) {
2892 result
= ERROR_FILE_NOT_FOUND
;
2895 pwszTempBuffer
= heap_alloc(cbData
);
2896 if (!pwszTempBuffer
) {
2897 result
= ERROR_NOT_ENOUGH_MEMORY
;
2900 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
2901 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2903 /* Expand environment variables, if appropriate, or copy the original string over. */
2904 if (dwValueType
== REG_EXPAND_SZ
) {
2905 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
2906 if (!cbData
) goto cleanup
;
2907 pwszExpandedBuffer
= heap_alloc(cbData
);
2908 if (!pwszExpandedBuffer
) {
2909 result
= ERROR_NOT_ENOUGH_MEMORY
;
2912 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
2914 pwszExpandedBuffer
= heap_alloc(cbData
);
2915 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
2918 /* If the value references a resource based string, parse the value and load the string.
2919 * Else just copy over the original value. */
2920 result
= ERROR_SUCCESS
;
2921 if (*pwszExpandedBuffer
!= '@') { /* '@' is the prefix for resource based string entries. */
2922 lstrcpynW(pwszBuffer
, pwszExpandedBuffer
, cbBuffer
/ sizeof(WCHAR
));
2924 WCHAR
*pComma
= strrchrW(pwszExpandedBuffer
, ',');
2928 /* Format of the expanded value is 'path_to_dll,-resId' */
2929 if (!pComma
|| pComma
[1] != '-') {
2930 result
= ERROR_BADKEY
;
2934 uiStringId
= atoiW(pComma
+2);
2937 hModule
= LoadLibraryW(pwszExpandedBuffer
+ 1);
2938 if (!hModule
|| !load_string(hModule
, uiStringId
, pwszBuffer
, cbBuffer
/sizeof(WCHAR
)))
2939 result
= ERROR_BADKEY
;
2940 FreeLibrary(hModule
);
2944 heap_free(pwszTempBuffer
);
2945 heap_free(pwszExpandedBuffer
);
2949 /******************************************************************************
2950 * RegLoadMUIStringA [ADVAPI32.@]
2952 * See RegLoadMUIStringW
2954 LSTATUS WINAPI
RegLoadMUIStringA(HKEY hKey
, LPCSTR pszValue
, LPSTR pszBuffer
, DWORD cbBuffer
,
2955 LPDWORD pcbData
, DWORD dwFlags
, LPCSTR pszBaseDir
)
2957 UNICODE_STRING valueW
, baseDirW
;
2959 DWORD cbData
= cbBuffer
* sizeof(WCHAR
);
2962 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
2963 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
2964 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszBaseDir
) ||
2965 !(pwszBuffer
= heap_alloc(cbData
)))
2967 result
= ERROR_NOT_ENOUGH_MEMORY
;
2971 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, dwFlags
,
2974 if (result
== ERROR_SUCCESS
) {
2975 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszBuffer
, cbBuffer
, NULL
, NULL
);
2981 heap_free(pwszBuffer
);
2982 RtlFreeUnicodeString(&baseDirW
);
2983 RtlFreeUnicodeString(&valueW
);
2988 /******************************************************************************
2989 * RegDisablePredefinedCache [ADVAPI32.@]
2991 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2997 * Success: ERROR_SUCCESS
2998 * Failure: nonzero error code from Winerror.h
3001 * This is useful for services that use impersonation.
3003 LSTATUS WINAPI
RegDisablePredefinedCache(void)
3005 HKEY hkey_current_user
;
3006 int idx
= HandleToUlong(HKEY_CURRENT_USER
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
3008 /* prevent caching of future requests */
3009 hkcu_cache_disabled
= TRUE
;
3011 hkey_current_user
= InterlockedExchangePointer( (void **)&special_root_keys
[idx
], NULL
);
3013 if (hkey_current_user
)
3014 NtClose( hkey_current_user
);
3016 return ERROR_SUCCESS
;
3020 /******************************************************************************
3021 * RegDeleteTreeW [ADVAPI32.@]
3024 LSTATUS WINAPI
RegDeleteTreeW( HKEY hkey
, const WCHAR
*subkey
)
3026 static const WCHAR emptyW
[] = {0};
3027 DWORD name_size
, max_name
, max_subkey
;
3028 WCHAR
*name_buf
= NULL
;
3031 TRACE( "(%p, %s)\n", hkey
, debugstr_w(subkey
) );
3033 if (subkey
&& *subkey
)
3035 ret
= RegOpenKeyExW( hkey
, subkey
, 0, KEY_READ
, &hkey
);
3036 if (ret
) return ret
;
3039 ret
= RegQueryInfoKeyW( hkey
, NULL
, NULL
, NULL
, NULL
, &max_subkey
,
3040 NULL
, NULL
, &max_name
, NULL
, NULL
, NULL
);
3044 max_name
= max( max_subkey
, max_name
) + 1;
3045 if (!(name_buf
= heap_alloc( max_name
* sizeof(WCHAR
) )))
3047 ret
= ERROR_NOT_ENOUGH_MEMORY
;
3051 /* Recursively delete subkeys */
3054 name_size
= max_name
;
3055 ret
= RegEnumKeyExW( hkey
, 0, name_buf
, &name_size
, NULL
, NULL
, NULL
, NULL
);
3056 if (ret
== ERROR_NO_MORE_ITEMS
) break;
3057 if (ret
) goto cleanup
;
3058 ret
= RegDeleteTreeW( hkey
, name_buf
);
3059 if (ret
) goto cleanup
;
3062 /* Delete the key itself */
3063 if (subkey
&& *subkey
)
3065 ret
= RegDeleteKeyW( hkey
, emptyW
);
3072 name_size
= max_name
;
3073 ret
= RegEnumValueW( hkey
, 0, name_buf
, &name_size
, NULL
, NULL
, NULL
, NULL
);
3074 if (ret
== ERROR_NO_MORE_ITEMS
) break;
3075 if (ret
) goto cleanup
;
3076 ret
= RegDeleteValueW( hkey
, name_buf
);
3077 if (ret
) goto cleanup
;
3080 ret
= ERROR_SUCCESS
;
3083 heap_free( name_buf
);
3084 if (subkey
&& *subkey
)
3085 RegCloseKey( hkey
);
3090 /******************************************************************************
3091 * RegDeleteTreeA [ADVAPI32.@]
3094 LSTATUS WINAPI
RegDeleteTreeA( HKEY hkey
, const char *subkey
)
3096 UNICODE_STRING subkeyW
;
3099 if (subkey
) RtlCreateUnicodeStringFromAsciiz( &subkeyW
, subkey
);
3100 else subkeyW
.Buffer
= NULL
;
3101 ret
= RegDeleteTreeW( hkey
, subkeyW
.Buffer
);
3102 RtlFreeUnicodeString( &subkeyW
);
3107 /******************************************************************************
3108 * RegCopyTreeW [ADVAPI32.@]
3111 LONG WINAPI
RegCopyTreeW( HKEY hsrc
, const WCHAR
*subkey
, HKEY hdst
)
3113 DWORD name_size
, max_name
;
3114 DWORD value_size
, max_value
;
3115 DWORD max_subkey
, i
, type
;
3116 WCHAR
*name_buf
= NULL
;
3117 BYTE
*value_buf
= NULL
;
3121 TRACE( "(%p, %s, %p)\n", hsrc
, debugstr_w(subkey
), hdst
);
3125 ret
= RegOpenKeyExW( hsrc
, subkey
, 0, KEY_READ
, &hsrc
);
3126 if (ret
) return ret
;
3129 ret
= RegQueryInfoKeyW( hsrc
, NULL
, NULL
, NULL
, NULL
, &max_subkey
,
3130 NULL
, NULL
, &max_name
, &max_value
, NULL
, NULL
);
3134 max_name
= max( max_subkey
, max_name
) + 1;
3135 if (!(name_buf
= heap_alloc( max_name
* sizeof(WCHAR
) )))
3137 ret
= ERROR_NOT_ENOUGH_MEMORY
;
3141 if (!(value_buf
= heap_alloc( max_value
)))
3143 ret
= ERROR_NOT_ENOUGH_MEMORY
;
3150 name_size
= max_name
;
3151 value_size
= max_value
;
3152 ret
= RegEnumValueW( hsrc
, i
, name_buf
, &name_size
, NULL
, &type
, value_buf
, &value_size
);
3153 if (ret
== ERROR_NO_MORE_ITEMS
) break;
3154 if (ret
) goto cleanup
;
3155 ret
= RegSetValueExW( hdst
, name_buf
, 0, type
, value_buf
, value_size
);
3156 if (ret
) goto cleanup
;
3159 /* Recursively copy subkeys */
3162 name_size
= max_name
;
3163 ret
= RegEnumKeyExW( hsrc
, i
, name_buf
, &name_size
, NULL
, NULL
, NULL
, NULL
);
3164 if (ret
== ERROR_NO_MORE_ITEMS
) break;
3165 if (ret
) goto cleanup
;
3166 ret
= RegCreateKeyExW( hdst
, name_buf
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hkey
, NULL
);
3167 if (ret
) goto cleanup
;
3168 ret
= RegCopyTreeW( hsrc
, name_buf
, hkey
);
3169 RegCloseKey( hkey
);
3170 if (ret
) goto cleanup
;
3173 ret
= ERROR_SUCCESS
;
3176 heap_free( name_buf
);
3177 heap_free( value_buf
);
3179 RegCloseKey( hsrc
);
3184 /******************************************************************************
3185 * RegCopyTreeA [ADVAPI32.@]
3188 LONG WINAPI
RegCopyTreeA( HKEY hsrc
, const char *subkey
, HKEY hdst
)
3190 UNICODE_STRING subkeyW
;
3193 if (subkey
) RtlCreateUnicodeStringFromAsciiz( &subkeyW
, subkey
);
3194 else subkeyW
.Buffer
= NULL
;
3195 ret
= RegCopyTreeW( hsrc
, subkeyW
.Buffer
, hdst
);
3196 RtlFreeUnicodeString( &subkeyW
);
3201 /******************************************************************************
3202 * RegDisableReflectionKey [ADVAPI32.@]
3205 LONG WINAPI
RegDisableReflectionKey(HKEY base
)
3207 FIXME("%p: stub\n", base
);
3208 return ERROR_SUCCESS
;