4 * Copyright (C) 1999 Alexandre Julliard
5 * Copyright (C) 2017 Dmitry Timoshkov
7 * Based on misc/registry.c code
8 * Copyright (C) 1996 Marcus Meissner
9 * Copyright (C) 1998 Matthew Becker
10 * Copyright (C) 1999 Sylvain St-Germain
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #define WIN32_NO_STATUS
43 #include "advapi32_misc.h"
45 #include "wine/unicode.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
50 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
51 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
53 static const WCHAR name_CLASSES_ROOT
[] =
54 {'\\','R','e','g','i','s','t','r','y','\\',
55 'M','a','c','h','i','n','e','\\',
56 'S','o','f','t','w','a','r','e','\\',
57 'C','l','a','s','s','e','s',0};
58 static const WCHAR name_LOCAL_MACHINE
[] =
59 {'\\','R','e','g','i','s','t','r','y','\\',
60 'M','a','c','h','i','n','e',0};
61 static const WCHAR name_USERS
[] =
62 {'\\','R','e','g','i','s','t','r','y','\\',
64 static const WCHAR name_PERFORMANCE_DATA
[] =
65 {'\\','R','e','g','i','s','t','r','y','\\',
66 'P','e','r','f','D','a','t','a',0};
67 static const WCHAR name_CURRENT_CONFIG
[] =
68 {'\\','R','e','g','i','s','t','r','y','\\',
69 'M','a','c','h','i','n','e','\\',
70 'S','y','s','t','e','m','\\',
71 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
72 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
73 'C','u','r','r','e','n','t',0};
74 static const WCHAR name_DYN_DATA
[] =
75 {'\\','R','e','g','i','s','t','r','y','\\',
76 'D','y','n','D','a','t','a',0};
78 static const WCHAR
* const root_key_names
[] =
81 NULL
, /* HKEY_CURRENT_USER is determined dynamically */
84 name_PERFORMANCE_DATA
,
89 static HKEY special_root_keys
[ARRAY_SIZE(root_key_names
)];
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 (NtOpenKeyEx( &ret
, MAXIMUM_ALLOWED
, &attr
, 0 )) 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 NtOpenKeyEx to handle Wow6432 nodes */
206 static NTSTATUS
open_key( HKEY
*retkey
, DWORD options
, 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 pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
219 if (options
& REG_OPTION_OPEN_LINK
) attr
->Attributes
|= OBJ_OPENLINK
;
220 return NtOpenKeyEx( (HANDLE
*)retkey
, access
, attr
, options
);
223 if (len
&& buffer
[0] == '\\') return STATUS_OBJECT_PATH_INVALID
;
224 while (i
< len
&& buffer
[i
] != '\\') i
++;
225 attr
->ObjectName
= &str
;
229 str
.Buffer
= buffer
+ pos
;
230 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
231 if (force_wow32
&& pos
)
233 if (is_wow6432node( &str
)) force_wow32
= FALSE
;
234 else if ((subkey
= open_wow6432node( attr
->RootDirectory
)))
236 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
237 attr
->RootDirectory
= subkey
;
243 if (options
& REG_OPTION_OPEN_LINK
) attr
->Attributes
|= OBJ_OPENLINK
;
244 status
= NtOpenKeyEx( &subkey
, access
, attr
, options
);
248 if (!(options
& REG_OPTION_OPEN_LINK
)) attr
->Attributes
&= ~OBJ_OPENLINK
;
249 status
= NtOpenKeyEx( &subkey
, access
, attr
, options
& ~REG_OPTION_OPEN_LINK
);
251 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
252 if (status
) return status
;
253 attr
->RootDirectory
= subkey
;
255 while (i
< len
&& buffer
[i
] == '\\') i
++;
257 while (i
< len
&& buffer
[i
] != '\\') i
++;
259 if (force_wow32
&& (subkey
= open_wow6432node( attr
->RootDirectory
)))
261 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
262 attr
->RootDirectory
= subkey
;
264 *retkey
= attr
->RootDirectory
;
268 /* create one of the HKEY_* special root keys */
269 static HKEY
create_special_root_hkey( HKEY hkey
, DWORD access
)
272 int idx
= HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
274 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CURRENT_USER
))
276 if (RtlOpenCurrentUser( access
, (HANDLE
*)&hkey
)) return 0;
277 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey
);
279 /* don't cache the key in the table if caching is disabled */
280 if (hkcu_cache_disabled
)
285 OBJECT_ATTRIBUTES attr
;
288 attr
.Length
= sizeof(attr
);
289 attr
.RootDirectory
= 0;
290 attr
.ObjectName
= &name
;
292 attr
.SecurityDescriptor
= NULL
;
293 attr
.SecurityQualityOfService
= NULL
;
294 RtlInitUnicodeString( &name
, root_key_names
[idx
] );
295 if (create_key( &hkey
, access
, &attr
, NULL
, 0, NULL
)) return 0;
296 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
299 if (!(access
& (KEY_WOW64_64KEY
| KEY_WOW64_32KEY
)))
301 if (!(ret
= InterlockedCompareExchangePointer( (void **)&special_root_keys
[idx
], hkey
, 0 )))
304 NtClose( hkey
); /* somebody beat us to it */
311 /* map the hkey from special root to normal key if necessary */
312 static inline HKEY
get_special_root_hkey( HKEY hkey
, REGSAM access
)
316 if ((HandleToUlong(hkey
) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
))
317 && (HandleToUlong(hkey
) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
321 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
))
322 mask
= KEY_WOW64_32KEY
| KEY_WOW64_64KEY
;
324 if ((access
& mask
) ||
325 !(ret
= special_root_keys
[HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
)]))
326 ret
= create_special_root_hkey( hkey
, MAXIMUM_ALLOWED
| (access
& mask
) );
332 /******************************************************************************
333 * RegOverridePredefKey [ADVAPI32.@]
335 LSTATUS WINAPI
RegOverridePredefKey( HKEY hkey
, HKEY override
)
340 TRACE("(%p %p)\n", hkey
, override
);
342 if ((HandleToUlong(hkey
) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
))
343 || (HandleToUlong(hkey
) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
344 return ERROR_INVALID_PARAMETER
;
345 idx
= HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
349 NTSTATUS status
= NtDuplicateObject( GetCurrentProcess(), override
,
350 GetCurrentProcess(), (HANDLE
*)&override
,
351 0, 0, DUPLICATE_SAME_ACCESS
);
352 if (status
) return RtlNtStatusToDosError( status
);
355 old_key
= InterlockedExchangePointer( (void **)&special_root_keys
[idx
], override
);
356 if (old_key
) NtClose( old_key
);
357 return ERROR_SUCCESS
;
361 /******************************************************************************
362 * RegCreateKeyExW [ADVAPI32.@]
364 * See RegCreateKeyExA.
366 LSTATUS WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
367 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
368 PHKEY retkey
, LPDWORD dispos
)
370 OBJECT_ATTRIBUTES attr
;
371 UNICODE_STRING nameW
, classW
;
373 if (reserved
) return ERROR_INVALID_PARAMETER
;
374 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
376 attr
.Length
= sizeof(attr
);
377 attr
.RootDirectory
= hkey
;
378 attr
.ObjectName
= &nameW
;
380 attr
.SecurityDescriptor
= NULL
;
381 attr
.SecurityQualityOfService
= NULL
;
382 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
383 RtlInitUnicodeString( &nameW
, name
);
384 RtlInitUnicodeString( &classW
, class );
386 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
, &classW
, options
, dispos
) );
390 /******************************************************************************
391 * RegCreateKeyExA [ADVAPI32.@]
393 * Open a registry key, creating it if it doesn't exist.
396 * hkey [I] Handle of the parent registry key
397 * name [I] Name of the new key to open or create
398 * reserved [I] Reserved, pass 0
399 * class [I] The object type of the new key
400 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
401 * access [I] Access level desired
402 * sa [I] Security attributes for the key
403 * retkey [O] Destination for the resulting handle
404 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
407 * Success: ERROR_SUCCESS.
408 * Failure: A standard Win32 error code. retkey remains untouched.
411 * MAXIMUM_ALLOWED in access mask not supported by server
413 LSTATUS WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
414 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
415 PHKEY retkey
, LPDWORD dispos
)
417 OBJECT_ATTRIBUTES attr
;
418 UNICODE_STRING classW
;
419 ANSI_STRING nameA
, classA
;
422 if (reserved
) return ERROR_INVALID_PARAMETER
;
423 if (!is_version_nt())
425 access
= MAXIMUM_ALLOWED
; /* Win95 ignores the access mask */
426 if (name
&& *name
== '\\') name
++; /* win9x,ME ignores one (and only one) beginning backslash */
428 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
430 attr
.Length
= sizeof(attr
);
431 attr
.RootDirectory
= hkey
;
432 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
434 attr
.SecurityDescriptor
= NULL
;
435 attr
.SecurityQualityOfService
= NULL
;
436 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
437 RtlInitAnsiString( &nameA
, name
);
438 RtlInitAnsiString( &classA
, class );
440 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
443 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
445 status
= create_key( retkey
, access
, &attr
, &classW
, options
, dispos
);
446 RtlFreeUnicodeString( &classW
);
449 return RtlNtStatusToDosError( status
);
453 /******************************************************************************
454 * RegCreateKeyW [ADVAPI32.@]
456 * Creates the specified reg key.
459 * hKey [I] Handle to an open key.
460 * lpSubKey [I] Name of a key that will be opened or created.
461 * phkResult [O] Receives a handle to the opened or created key.
464 * Success: ERROR_SUCCESS
465 * Failure: nonzero error code defined in Winerror.h
467 LSTATUS WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpSubKey
, PHKEY phkResult
)
469 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
470 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
471 return RegCreateKeyExW( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
472 MAXIMUM_ALLOWED
, NULL
, phkResult
, NULL
);
476 /******************************************************************************
477 * RegCreateKeyA [ADVAPI32.@]
481 LSTATUS WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpSubKey
, PHKEY phkResult
)
483 return RegCreateKeyExA( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
484 MAXIMUM_ALLOWED
, NULL
, phkResult
, NULL
);
488 /******************************************************************************
489 * RegCreateKeyTransactedW [ADVAPI32.@]
491 LSTATUS WINAPI
RegCreateKeyTransactedW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
492 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
493 PHKEY retkey
, LPDWORD dispos
, HANDLE transaction
, PVOID reserved2
)
495 FIXME( "(%p,%s,%u,%s,%u,%u,%p,%p,%p,%p,%p): stub\n", hkey
, debugstr_w(name
), reserved
,
496 debugstr_w(class), options
, access
, sa
, retkey
, dispos
, transaction
, reserved2
);
497 return ERROR_CALL_NOT_IMPLEMENTED
;
501 /******************************************************************************
502 * RegCreateKeyTransactedA [ADVAPI32.@]
504 LSTATUS WINAPI
RegCreateKeyTransactedA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
505 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
506 PHKEY retkey
, LPDWORD dispos
, HANDLE transaction
, PVOID reserved2
)
508 FIXME( "(%p,%s,%u,%s,%u,%u,%p,%p,%p,%p,%p): stub\n", hkey
, debugstr_a(name
), reserved
,
509 debugstr_a(class), options
, access
, sa
, retkey
, dispos
, transaction
, reserved2
);
510 return ERROR_CALL_NOT_IMPLEMENTED
;
514 /******************************************************************************
515 * RegOpenKeyExW [ADVAPI32.@]
519 LSTATUS WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD options
, REGSAM access
, PHKEY retkey
)
521 OBJECT_ATTRIBUTES attr
;
522 UNICODE_STRING nameW
;
524 if (retkey
&& (!name
|| !name
[0]) &&
525 (HandleToUlong(hkey
) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
)) &&
526 (HandleToUlong(hkey
) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
529 return ERROR_SUCCESS
;
532 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
533 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
) && name
&& *name
== '\\') name
++;
535 if (!retkey
) return ERROR_INVALID_PARAMETER
;
536 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
538 attr
.Length
= sizeof(attr
);
539 attr
.RootDirectory
= hkey
;
540 attr
.ObjectName
= &nameW
;
542 attr
.SecurityDescriptor
= NULL
;
543 attr
.SecurityQualityOfService
= NULL
;
544 RtlInitUnicodeString( &nameW
, name
);
545 return RtlNtStatusToDosError( open_key( retkey
, options
, access
, &attr
) );
549 /******************************************************************************
550 * RegOpenKeyExA [ADVAPI32.@]
552 * Open a registry key.
555 * hkey [I] Handle of open key
556 * name [I] Name of subkey to open
557 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
558 * access [I] Security access mask
559 * retkey [O] Handle to open key
562 * Success: ERROR_SUCCESS
563 * Failure: A standard Win32 error code. retkey is set to 0.
566 * Unlike RegCreateKeyExA(), this function will not create the key if it
569 LSTATUS WINAPI DECLSPEC_HOTPATCH
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD options
, REGSAM access
, PHKEY retkey
)
571 OBJECT_ATTRIBUTES attr
;
575 if (retkey
&& (!name
|| !name
[0]) &&
576 (HandleToUlong(hkey
) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
)) &&
577 (HandleToUlong(hkey
) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
580 return ERROR_SUCCESS
;
583 if (!is_version_nt()) access
= MAXIMUM_ALLOWED
; /* Win95 ignores the access mask */
586 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
587 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
) && name
&& *name
== '\\') name
++;
590 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
592 attr
.Length
= sizeof(attr
);
593 attr
.RootDirectory
= hkey
;
594 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
596 attr
.SecurityDescriptor
= NULL
;
597 attr
.SecurityQualityOfService
= NULL
;
599 RtlInitAnsiString( &nameA
, name
);
600 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
603 status
= open_key( retkey
, options
, access
, &attr
);
605 return RtlNtStatusToDosError( status
);
609 /******************************************************************************
610 * RegOpenKeyW [ADVAPI32.@]
614 LSTATUS WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, PHKEY retkey
)
617 return ERROR_INVALID_PARAMETER
;
622 return ERROR_SUCCESS
;
624 return RegOpenKeyExW( hkey
, name
, 0, MAXIMUM_ALLOWED
, retkey
);
628 /******************************************************************************
629 * RegOpenKeyA [ADVAPI32.@]
631 * Open a registry key.
634 * hkey [I] Handle of parent key to open the new key under
635 * name [I] Name of the key under hkey to open
636 * retkey [O] Destination for the resulting Handle
639 * Success: ERROR_SUCCESS
640 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
642 LSTATUS WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, PHKEY retkey
)
645 return ERROR_INVALID_PARAMETER
;
650 return ERROR_SUCCESS
;
652 return RegOpenKeyExA( hkey
, name
, 0, MAXIMUM_ALLOWED
, retkey
);
655 static WCHAR
*get_thread_token_user_sid(HANDLE token
)
657 WCHAR
*sidstring
= NULL
;
661 GetTokenInformation(token
, TokenUser
, NULL
, 0, &len
);
663 info
= heap_alloc(len
);
664 if (GetTokenInformation(token
, TokenUser
, info
, len
, &len
))
665 ConvertSidToStringSidW(info
->User
.Sid
, &sidstring
);
671 /******************************************************************************
672 * RegOpenCurrentUser [ADVAPI32.@]
674 * Get a handle to the HKEY_CURRENT_USER key for the user
675 * the current thread is impersonating.
678 * access [I] Desired access rights to the key
679 * retkey [O] Handle to the opened key
682 * Success: ERROR_SUCCESS
683 * Failure: nonzero error code from Winerror.h
686 * This function is supposed to retrieve a handle to the
687 * HKEY_CURRENT_USER for the user the current thread is impersonating.
688 * Since Wine does not currently allow threads to impersonate other users,
689 * this stub should work fine.
691 LSTATUS WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
693 WCHAR
*sidstring
= NULL
;
697 /* get current user SID */
698 if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY
, FALSE
, &threadtoken
))
700 sidstring
= get_thread_token_user_sid(threadtoken
);
701 CloseHandle(threadtoken
);
706 ImpersonateSelf(SecurityIdentification
);
707 if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY
, FALSE
, &threadtoken
))
709 sidstring
= get_thread_token_user_sid(threadtoken
);
710 CloseHandle(threadtoken
);
717 ret
= RegOpenKeyExW( HKEY_USERS
, sidstring
, 0, access
, retkey
);
718 LocalFree(sidstring
);
721 ret
= RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
728 /******************************************************************************
729 * RegEnumKeyExW [ADVAPI32.@]
731 * Enumerate subkeys of the specified open registry key.
734 * hkey [I] Handle to key to enumerate
735 * index [I] Index of subkey to enumerate
736 * name [O] Buffer for subkey name
737 * name_len [O] Size of subkey buffer
738 * reserved [I] Reserved
739 * class [O] Buffer for class string
740 * class_len [O] Size of class buffer
741 * ft [O] Time key last written to
744 * Success: ERROR_SUCCESS
745 * Failure: System error code. If there are no more subkeys available, the
746 * function returns ERROR_NO_MORE_ITEMS.
748 LSTATUS WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
749 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
752 char buffer
[256], *buf_ptr
= buffer
;
753 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
756 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
757 name_len
? *name_len
: 0, reserved
, class, class_len
, ft
);
759 if (reserved
) return ERROR_INVALID_PARAMETER
;
760 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
762 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
763 buffer
, sizeof(buffer
), &total_size
);
765 while (status
== STATUS_BUFFER_OVERFLOW
)
767 /* retry with a dynamically allocated buffer */
768 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
769 if (!(buf_ptr
= heap_alloc( total_size
)))
770 return ERROR_NOT_ENOUGH_MEMORY
;
771 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
772 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
773 buf_ptr
, total_size
, &total_size
);
778 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
779 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
781 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
783 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
784 status
= STATUS_BUFFER_OVERFLOW
;
788 memcpy( name
, info
->Name
, info
->NameLength
);
792 *class_len
= cls_len
;
795 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
802 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
803 return RtlNtStatusToDosError( status
);
807 /******************************************************************************
808 * RegEnumKeyExA [ADVAPI32.@]
812 LSTATUS WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
813 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
816 char buffer
[256], *buf_ptr
= buffer
;
817 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
820 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
821 name_len
? *name_len
: 0, reserved
, class, class_len
, ft
);
823 if (reserved
) return ERROR_INVALID_PARAMETER
;
824 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
826 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
827 buffer
, sizeof(buffer
), &total_size
);
829 while (status
== STATUS_BUFFER_OVERFLOW
)
831 /* retry with a dynamically allocated buffer */
832 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
833 if (!(buf_ptr
= heap_alloc( total_size
)))
834 return ERROR_NOT_ENOUGH_MEMORY
;
835 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
836 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
837 buf_ptr
, total_size
, &total_size
);
844 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
845 RtlUnicodeToMultiByteSize( &cls_len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
847 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
849 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
850 status
= STATUS_BUFFER_OVERFLOW
;
854 RtlUnicodeToMultiByteN( name
, len
, NULL
, info
->Name
, info
->NameLength
);
858 *class_len
= cls_len
;
861 RtlUnicodeToMultiByteN( class, cls_len
, NULL
,
862 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
870 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
871 return RtlNtStatusToDosError( status
);
875 /******************************************************************************
876 * RegEnumKeyW [ADVAPI32.@]
878 * Enumerates subkeys of the specified open reg key.
881 * hKey [I] Handle to an open key.
882 * dwIndex [I] Index of the subkey of hKey to retrieve.
883 * lpName [O] Name of the subkey.
884 * cchName [I] Size of lpName in TCHARS.
887 * Success: ERROR_SUCCESS
888 * Failure: system error code. If there are no more subkeys available, the
889 * function returns ERROR_NO_MORE_ITEMS.
891 LSTATUS WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
893 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
897 /******************************************************************************
898 * RegEnumKeyA [ADVAPI32.@]
902 LSTATUS WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
904 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
908 /******************************************************************************
909 * RegQueryInfoKeyW [ADVAPI32.@]
911 * Retrieves information about the specified registry key.
914 * hkey [I] Handle to key to query
915 * class [O] Buffer for class string
916 * class_len [O] Size of class string buffer
917 * reserved [I] Reserved
918 * subkeys [O] Buffer for number of subkeys
919 * max_subkey [O] Buffer for longest subkey name length
920 * max_class [O] Buffer for longest class string length
921 * values [O] Buffer for number of value entries
922 * max_value [O] Buffer for longest value name length
923 * max_data [O] Buffer for longest value data length
924 * security [O] Buffer for security descriptor length
925 * modif [O] Modification time
928 * Success: ERROR_SUCCESS
929 * Failure: system error code.
932 * - win95 allows class to be valid and class_len to be NULL
933 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
934 * - both allow class to be NULL and class_len to be NULL
935 * (it's hard to test validity, so test !NULL instead)
937 LSTATUS WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
938 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
939 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
940 LPDWORD security
, FILETIME
*modif
)
943 char buffer
[256], *buf_ptr
= buffer
;
944 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
947 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
948 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
950 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
951 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
953 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
954 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
956 if (class && class_len
&& *class_len
)
958 /* retry with a dynamically allocated buffer */
959 while (status
== STATUS_BUFFER_OVERFLOW
)
961 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
962 if (!(buf_ptr
= heap_alloc( total_size
)))
963 return ERROR_NOT_ENOUGH_MEMORY
;
964 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
965 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
968 if (status
) goto done
;
970 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
972 status
= STATUS_BUFFER_TOO_SMALL
;
976 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
977 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
980 else status
= STATUS_SUCCESS
;
982 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
983 if (subkeys
) *subkeys
= info
->SubKeys
;
984 if (max_subkey
) *max_subkey
= info
->MaxNameLen
/ sizeof(WCHAR
);
985 if (max_class
) *max_class
= info
->MaxClassLen
/ sizeof(WCHAR
);
986 if (values
) *values
= info
->Values
;
987 if (max_value
) *max_value
= info
->MaxValueNameLen
/ sizeof(WCHAR
);
988 if (max_data
) *max_data
= info
->MaxValueDataLen
;
989 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
993 FIXME( "security argument not supported.\n");
998 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
999 return RtlNtStatusToDosError( status
);
1003 /******************************************************************************
1004 * RegQueryMultipleValuesA [ADVAPI32.@]
1006 * Retrieves the type and data for a list of value names associated with a key.
1009 * hKey [I] Handle to an open key.
1010 * val_list [O] Array of VALENT structures that describes the entries.
1011 * num_vals [I] Number of elements in val_list.
1012 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
1013 * ldwTotsize [I/O] Size of lpValueBuf.
1016 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
1017 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
1020 LSTATUS WINAPI
RegQueryMultipleValuesA( HKEY hkey
, PVALENTA val_list
, DWORD num_vals
,
1021 LPSTR lpValueBuf
, LPDWORD ldwTotsize
)
1024 DWORD maxBytes
= *ldwTotsize
;
1026 LPSTR bufptr
= lpValueBuf
;
1029 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
1031 for(i
=0; i
< num_vals
; ++i
)
1034 val_list
[i
].ve_valuelen
=0;
1035 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
1036 if(status
!= ERROR_SUCCESS
)
1041 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
1043 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
1044 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
1045 if(status
!= ERROR_SUCCESS
)
1050 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
1052 bufptr
+= val_list
[i
].ve_valuelen
;
1055 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
1057 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
1061 /******************************************************************************
1062 * RegQueryMultipleValuesW [ADVAPI32.@]
1064 * See RegQueryMultipleValuesA.
1066 LSTATUS WINAPI
RegQueryMultipleValuesW( HKEY hkey
, PVALENTW val_list
, DWORD num_vals
,
1067 LPWSTR lpValueBuf
, LPDWORD ldwTotsize
)
1070 DWORD maxBytes
= *ldwTotsize
;
1072 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
1075 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
1077 for(i
=0; i
< num_vals
; ++i
)
1079 val_list
[i
].ve_valuelen
=0;
1080 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
1081 if(status
!= ERROR_SUCCESS
)
1086 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
1088 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
1089 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
1090 if(status
!= ERROR_SUCCESS
)
1095 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
1097 bufptr
+= val_list
[i
].ve_valuelen
;
1100 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
1102 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
1105 /******************************************************************************
1106 * RegQueryInfoKeyA [ADVAPI32.@]
1108 * Retrieves information about a registry key.
1111 * hKey [I] Handle to an open key.
1112 * lpClass [O] Class string of the key.
1113 * lpcClass [I/O] size of lpClass.
1114 * lpReserved [I] Reserved; must be NULL.
1115 * lpcSubKeys [O] Number of subkeys contained by the key.
1116 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
1117 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
1119 * lpcValues [O] Number of values associated with the key.
1120 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
1121 * lpcMaxValueLen [O] Longest data component among the key's values
1122 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
1123 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
1126 * Success: ERROR_SUCCESS
1127 * Failure: nonzero error code from Winerror.h
1129 LSTATUS WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
1130 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
1131 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
1132 LPDWORD security
, FILETIME
*modif
)
1135 char buffer
[256], *buf_ptr
= buffer
;
1136 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
1137 DWORD total_size
, len
;
1139 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
1140 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
1142 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
1143 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1145 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
1146 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1148 if (class || class_len
)
1150 /* retry with a dynamically allocated buffer */
1151 while (status
== STATUS_BUFFER_OVERFLOW
)
1153 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1154 if (!(buf_ptr
= heap_alloc( total_size
)))
1155 return ERROR_NOT_ENOUGH_MEMORY
;
1156 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
1157 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
1160 if (status
) goto done
;
1163 if (class && class_len
) len
= *class_len
;
1164 RtlUnicodeToMultiByteN( class, len
, class_len
,
1165 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
), info
->ClassLength
);
1168 if (*class_len
+ 1 > len
)
1170 status
= STATUS_BUFFER_OVERFLOW
;
1173 class[*class_len
] = 0;
1176 else status
= STATUS_SUCCESS
;
1178 if (subkeys
) *subkeys
= info
->SubKeys
;
1179 if (max_subkey
) *max_subkey
= info
->MaxNameLen
/ sizeof(WCHAR
);
1180 if (max_class
) *max_class
= info
->MaxClassLen
/ sizeof(WCHAR
);
1181 if (values
) *values
= info
->Values
;
1182 if (max_value
) *max_value
= info
->MaxValueNameLen
/ sizeof(WCHAR
);
1183 if (max_data
) *max_data
= info
->MaxValueDataLen
;
1184 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
1188 FIXME( "security argument not supported.\n");
1193 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1194 return RtlNtStatusToDosError( status
);
1197 /******************************************************************************
1198 * RegQueryReflectionKey [ADVAPI32.@]
1200 LONG WINAPI
RegQueryReflectionKey( HKEY hkey
, BOOL
*is_reflection_disabled
)
1202 FIXME( "%p, %p stub\n", hkey
, is_reflection_disabled
);
1203 *is_reflection_disabled
= TRUE
;
1204 return ERROR_CALL_NOT_IMPLEMENTED
;
1207 /******************************************************************************
1208 * RegCloseKey [ADVAPI32.@]
1210 * Close an open registry key.
1213 * hkey [I] Handle of key to close
1216 * Success: ERROR_SUCCESS
1217 * Failure: Error code
1219 LSTATUS WINAPI DECLSPEC_HOTPATCH
RegCloseKey( HKEY hkey
)
1221 if (!hkey
) return ERROR_INVALID_HANDLE
;
1222 if (hkey
>= (HKEY
)0x80000000) return ERROR_SUCCESS
;
1223 return RtlNtStatusToDosError( NtClose( hkey
) );
1227 /******************************************************************************
1228 * RegDeleteKeyExW [ADVAPI32.@]
1230 LSTATUS WINAPI
RegDeleteKeyExW( HKEY hkey
, LPCWSTR name
, REGSAM access
, DWORD reserved
)
1235 if (!name
) return ERROR_INVALID_PARAMETER
;
1237 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
1239 access
&= KEY_WOW64_64KEY
| KEY_WOW64_32KEY
;
1240 if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, access
| DELETE
, &tmp
)))
1242 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
1245 TRACE("%s ret=%08x\n", debugstr_w(name
), ret
);
1250 /******************************************************************************
1251 * RegDeleteKeyW [ADVAPI32.@]
1253 * See RegDeleteKeyA.
1255 LSTATUS WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
1257 return RegDeleteKeyExW( hkey
, name
, 0, 0 );
1261 /******************************************************************************
1262 * RegDeleteKeyExA [ADVAPI32.@]
1264 LSTATUS WINAPI
RegDeleteKeyExA( HKEY hkey
, LPCSTR name
, REGSAM access
, DWORD reserved
)
1269 if (!name
) return ERROR_INVALID_PARAMETER
;
1271 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
1273 access
&= KEY_WOW64_64KEY
| KEY_WOW64_32KEY
;
1274 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, access
| DELETE
, &tmp
)))
1276 if (!is_version_nt()) /* win95 does recursive key deletes */
1280 while(!RegEnumKeyA(tmp
, 0, sub
, sizeof(sub
)))
1282 if(RegDeleteKeyExA(tmp
, sub
, access
, reserved
)) /* recurse */
1286 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
1289 TRACE("%s ret=%08x\n", debugstr_a(name
), ret
);
1294 /******************************************************************************
1295 * RegDeleteKeyA [ADVAPI32.@]
1297 * Delete a registry key.
1300 * hkey [I] Handle to parent key containing the key to delete
1301 * name [I] Name of the key user hkey to delete
1305 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1306 * right. In reality, it opens a new handle with DELETE access.
1309 * Success: ERROR_SUCCESS
1310 * Failure: Error code
1312 LSTATUS WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
1314 return RegDeleteKeyExA( hkey
, name
, 0, 0 );
1319 /******************************************************************************
1320 * RegSetValueExW [ADVAPI32.@]
1322 * Set the data and contents of a registry value.
1325 * hkey [I] Handle of key to set value for
1326 * name [I] Name of value to set
1327 * reserved [I] Reserved, must be zero
1328 * type [I] Type of the value being set
1329 * data [I] The new contents of the value to set
1330 * count [I] Size of data
1333 * Success: ERROR_SUCCESS
1334 * Failure: Error code
1336 LSTATUS WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
1337 DWORD type
, const BYTE
*data
, DWORD count
)
1339 UNICODE_STRING nameW
;
1341 /* no need for version check, not implemented on win9x anyway */
1343 if ((data
&& ((ULONG_PTR
)data
>> 16) == 0) || (!data
&& count
)) return ERROR_NOACCESS
;
1345 if (count
&& is_string(type
))
1347 LPCWSTR str
= (LPCWSTR
)data
;
1348 /* if user forgot to count terminating null, add it (yes NT does this) */
1349 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
1350 count
+= sizeof(WCHAR
);
1352 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1354 RtlInitUnicodeString( &nameW
, name
);
1355 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
1359 /******************************************************************************
1360 * RegSetValueExA [ADVAPI32.@]
1362 * See RegSetValueExW.
1365 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1366 * NT does definitely care (aj)
1368 LSTATUS WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1369 const BYTE
*data
, DWORD count
)
1372 UNICODE_STRING nameW
;
1373 WCHAR
*dataW
= NULL
;
1376 if (!is_version_nt()) /* win95 */
1380 if (!data
) return ERROR_INVALID_PARAMETER
;
1381 count
= strlen((const char *)data
) + 1;
1384 else if (count
&& is_string(type
))
1386 /* if user forgot to count terminating null, add it (yes NT does this) */
1387 if (data
[count
-1] && !data
[count
]) count
++;
1390 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1392 if (is_string( type
)) /* need to convert to Unicode */
1395 RtlMultiByteToUnicodeSize( &lenW
, (const char *)data
, count
);
1396 if (!(dataW
= heap_alloc( lenW
))) return ERROR_OUTOFMEMORY
;
1397 RtlMultiByteToUnicodeN( dataW
, lenW
, NULL
, (const char *)data
, count
);
1399 data
= (BYTE
*)dataW
;
1402 RtlInitAnsiString( &nameA
, name
);
1403 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1405 status
= NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
);
1406 RtlFreeUnicodeString( &nameW
);
1409 return RtlNtStatusToDosError( status
);
1413 /******************************************************************************
1414 * RegSetValueW [ADVAPI32.@]
1416 * Sets the data for the default or unnamed value of a reg key.
1419 * hkey [I] Handle to an open key.
1420 * subkey [I] Name of a subkey of hKey.
1421 * type [I] Type of information to store.
1422 * data [I] String that contains the data to set for the default value.
1423 * count [I] Ignored.
1426 * Success: ERROR_SUCCESS
1427 * Failure: nonzero error code from Winerror.h
1429 LSTATUS WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR subkey
, DWORD type
, LPCWSTR data
, DWORD count
)
1431 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_w(subkey
), type
, debugstr_w(data
), count
);
1433 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1435 return RegSetKeyValueW( hkey
, subkey
, NULL
, type
, data
, (strlenW(data
) + 1)*sizeof(WCHAR
) );
1438 /******************************************************************************
1439 * RegSetValueA [ADVAPI32.@]
1443 LSTATUS WINAPI
RegSetValueA( HKEY hkey
, LPCSTR subkey
, DWORD type
, LPCSTR data
, DWORD count
)
1445 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_a(subkey
), type
, debugstr_a(data
), count
);
1447 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1449 return RegSetKeyValueA( hkey
, subkey
, NULL
, type
, data
, strlen(data
) + 1 );
1452 /******************************************************************************
1453 * RegSetKeyValueW [ADVAPI32.@]
1455 LONG WINAPI
RegSetKeyValueW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR name
, DWORD type
, const void *data
, DWORD len
)
1457 HKEY hsubkey
= NULL
;
1460 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey
, debugstr_w(subkey
), debugstr_w(name
), type
, data
, len
);
1462 if (subkey
&& subkey
[0]) /* need to create the subkey */
1464 if ((ret
= RegCreateKeyW( hkey
, subkey
, &hsubkey
)) != ERROR_SUCCESS
) return ret
;
1468 ret
= RegSetValueExW( hkey
, name
, 0, type
, (const BYTE
*)data
, len
);
1469 if (hsubkey
) RegCloseKey( hsubkey
);
1473 /******************************************************************************
1474 * RegSetKeyValueA [ADVAPI32.@]
1476 LONG WINAPI
RegSetKeyValueA( HKEY hkey
, LPCSTR subkey
, LPCSTR name
, DWORD type
, const void *data
, DWORD len
)
1478 HKEY hsubkey
= NULL
;
1481 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey
, debugstr_a(subkey
), debugstr_a(name
), type
, data
, len
);
1483 if (subkey
&& subkey
[0]) /* need to create the subkey */
1485 if ((ret
= RegCreateKeyA( hkey
, subkey
, &hsubkey
)) != ERROR_SUCCESS
) return ret
;
1489 ret
= RegSetValueExA( hkey
, name
, 0, type
, (const BYTE
*)data
, len
);
1490 if (hsubkey
) RegCloseKey( hsubkey
);
1494 struct perf_provider
1497 WCHAR linkage
[MAX_PATH
];
1498 WCHAR objects
[MAX_PATH
];
1499 PM_OPEN_PROC
*pOpen
;
1500 PM_CLOSE_PROC
*pClose
;
1501 PM_COLLECT_PROC
*pCollect
;
1504 static void *get_provider_entry(HKEY perf
, HMODULE perflib
, const char *name
)
1507 DWORD err
, type
, len
;
1509 len
= sizeof(buf
) - 1;
1510 err
= RegQueryValueExA(perf
, name
, NULL
, &type
, (BYTE
*)buf
, &len
);
1511 if (err
!= ERROR_SUCCESS
|| type
!= REG_SZ
)
1515 TRACE("Loading function pointer for %s: %s\n", name
, debugstr_a(buf
));
1517 return GetProcAddress(perflib
, buf
);
1520 static BOOL
load_provider(HKEY root
, const WCHAR
*name
, struct perf_provider
*provider
)
1522 static const WCHAR object_listW
[] = { 'O','b','j','e','c','t',' ','L','i','s','t',0 };
1523 static const WCHAR performanceW
[] = { 'P','e','r','f','o','r','m','a','n','c','e',0 };
1524 static const WCHAR libraryW
[] = { 'L','i','b','r','a','r','y',0 };
1525 static const WCHAR linkageW
[] = { 'L','i','n','k','a','g','e',0 };
1526 static const WCHAR exportW
[] = { 'E','x','p','o','r','t',0 };
1527 WCHAR buf
[MAX_PATH
], buf2
[MAX_PATH
];
1528 DWORD err
, type
, len
;
1531 err
= RegOpenKeyExW(root
, name
, 0, KEY_READ
, &service
);
1532 if (err
!= ERROR_SUCCESS
)
1535 provider
->linkage
[0] = 0;
1536 err
= RegOpenKeyExW(service
, linkageW
, 0, KEY_READ
, &perf
);
1537 if (err
== ERROR_SUCCESS
)
1539 len
= sizeof(buf
) - sizeof(WCHAR
);
1540 err
= RegQueryValueExW(perf
, exportW
, NULL
, &type
, (BYTE
*)buf
, &len
);
1541 if (err
== ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_MULTI_SZ
))
1543 memcpy(provider
->linkage
, buf
, len
);
1544 provider
->linkage
[len
/ sizeof(WCHAR
)] = 0;
1545 TRACE("Export: %s\n", debugstr_w(provider
->linkage
));
1550 err
= RegOpenKeyExW(service
, performanceW
, 0, KEY_READ
, &perf
);
1551 RegCloseKey(service
);
1552 if (err
!= ERROR_SUCCESS
)
1555 provider
->objects
[0] = 0;
1556 len
= sizeof(buf
) - sizeof(WCHAR
);
1557 err
= RegQueryValueExW(perf
, object_listW
, NULL
, &type
, (BYTE
*)buf
, &len
);
1558 if (err
== ERROR_SUCCESS
&& (type
== REG_SZ
|| type
== REG_MULTI_SZ
))
1560 memcpy(provider
->objects
, buf
, len
);
1561 provider
->objects
[len
/ sizeof(WCHAR
)] = 0;
1562 TRACE("Object List: %s\n", debugstr_w(provider
->objects
));
1565 len
= sizeof(buf
) - sizeof(WCHAR
);
1566 err
= RegQueryValueExW(perf
, libraryW
, NULL
, &type
, (BYTE
*)buf
, &len
);
1567 if (err
!= ERROR_SUCCESS
|| !(type
== REG_SZ
|| type
== REG_EXPAND_SZ
))
1570 buf
[len
/ sizeof(WCHAR
)] = 0;
1571 if (type
== REG_EXPAND_SZ
)
1573 len
= ExpandEnvironmentStringsW(buf
, buf2
, MAX_PATH
);
1574 if (!len
|| len
> MAX_PATH
) goto error
;
1578 if (!(provider
->perflib
= LoadLibraryW(buf
)))
1580 WARN("Failed to load %s\n", debugstr_w(buf
));
1584 GetModuleFileNameW(provider
->perflib
, buf
, MAX_PATH
);
1585 TRACE("Loaded provider %s\n", wine_dbgstr_w(buf
));
1587 provider
->pOpen
= get_provider_entry(perf
, provider
->perflib
, "Open");
1588 provider
->pClose
= get_provider_entry(perf
, provider
->perflib
, "Close");
1589 provider
->pCollect
= get_provider_entry(perf
, provider
->perflib
, "Collect");
1590 if (provider
->pOpen
&& provider
->pClose
&& provider
->pCollect
)
1596 TRACE("Provider is missing required exports\n");
1597 FreeLibrary(provider
->perflib
);
1604 static DWORD
collect_data(struct perf_provider
*provider
, const WCHAR
*query
, void **data
, DWORD
*size
, DWORD
*obj_count
)
1606 static const WCHAR globalW
[] = { 'G','l','o','b','a','l',0 };
1607 WCHAR
*linkage
= provider
->linkage
[0] ? provider
->linkage
: NULL
;
1610 if (!query
|| !query
[0])
1613 err
= provider
->pOpen(linkage
);
1614 if (err
!= ERROR_SUCCESS
)
1616 TRACE("Open(%s) error %u (%#x)\n", debugstr_w(linkage
), err
, err
);
1621 err
= provider
->pCollect((WCHAR
*)query
, data
, size
, obj_count
);
1622 if (err
!= ERROR_SUCCESS
)
1624 TRACE("Collect error %u (%#x)\n", err
, err
);
1632 #define MAX_SERVICE_NAME 260
1634 static DWORD
query_perf_data(const WCHAR
*query
, DWORD
*type
, void *data
, DWORD
*ret_size
)
1636 static const WCHAR SZ_SERVICES_KEY
[] = { 'S','y','s','t','e','m','\\',
1637 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1638 'S','e','r','v','i','c','e','s',0 };
1639 DWORD err
, i
, data_size
;
1641 PERF_DATA_BLOCK
*pdb
;
1644 return ERROR_INVALID_PARAMETER
;
1646 data_size
= *ret_size
;
1652 if (!data
|| data_size
< sizeof(*pdb
))
1653 return ERROR_MORE_DATA
;
1657 pdb
->Signature
[0] = 'P';
1658 pdb
->Signature
[1] = 'E';
1659 pdb
->Signature
[2] = 'R';
1660 pdb
->Signature
[3] = 'F';
1661 #ifdef WORDS_BIGENDIAN
1662 pdb
->LittleEndian
= FALSE
;
1664 pdb
->LittleEndian
= TRUE
;
1666 pdb
->Version
= PERF_DATA_VERSION
;
1667 pdb
->Revision
= PERF_DATA_REVISION
;
1668 pdb
->TotalByteLength
= 0;
1669 pdb
->HeaderLength
= sizeof(*pdb
);
1670 pdb
->NumObjectTypes
= 0;
1671 pdb
->DefaultObject
= 0;
1672 QueryPerformanceCounter(&pdb
->PerfTime
);
1673 QueryPerformanceFrequency(&pdb
->PerfFreq
);
1676 pdb
->SystemNameOffset
= sizeof(*pdb
);
1677 pdb
->SystemNameLength
= (data_size
- sizeof(*pdb
)) / sizeof(WCHAR
);
1678 if (!GetComputerNameW(data
, &pdb
->SystemNameLength
))
1679 return ERROR_MORE_DATA
;
1681 pdb
->SystemNameLength
++;
1682 pdb
->SystemNameLength
*= sizeof(WCHAR
);
1684 pdb
->HeaderLength
+= pdb
->SystemNameLength
;
1686 /* align to 8 bytes */
1687 if (pdb
->SystemNameLength
& 7)
1688 pdb
->HeaderLength
+= 8 - (pdb
->SystemNameLength
& 7);
1690 if (data_size
< pdb
->HeaderLength
)
1691 return ERROR_MORE_DATA
;
1693 pdb
->TotalByteLength
= pdb
->HeaderLength
;
1695 data_size
-= pdb
->HeaderLength
;
1696 data
= (char *)data
+ pdb
->HeaderLength
;
1698 err
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, SZ_SERVICES_KEY
, 0, KEY_READ
, &root
);
1699 if (err
!= ERROR_SUCCESS
)
1705 DWORD collected_size
= data_size
, obj_count
= 0;
1706 struct perf_provider provider
;
1707 WCHAR name
[MAX_SERVICE_NAME
];
1708 void *collected_data
= data
;
1710 err
= RegEnumKeyW(root
, i
++, name
, MAX_SERVICE_NAME
);
1711 if (err
== ERROR_NO_MORE_ITEMS
)
1713 err
= ERROR_SUCCESS
;
1717 if (err
!= ERROR_SUCCESS
)
1720 if (!load_provider(root
, name
, &provider
))
1723 err
= collect_data(&provider
, query
, &collected_data
, &collected_size
, &obj_count
);
1724 FreeLibrary(provider
.perflib
);
1726 if (err
== ERROR_MORE_DATA
)
1729 if (err
== ERROR_SUCCESS
)
1731 PERF_OBJECT_TYPE
*obj
= (PERF_OBJECT_TYPE
*)data
;
1733 TRACE("Collect: obj->TotalByteLength %u, collected_size %u\n",
1734 obj
->TotalByteLength
, collected_size
);
1736 data_size
-= collected_size
;
1737 data
= collected_data
;
1739 pdb
->TotalByteLength
+= collected_size
;
1740 pdb
->NumObjectTypes
+= obj_count
;
1746 if (err
== ERROR_SUCCESS
)
1748 *ret_size
= pdb
->TotalByteLength
;
1750 GetSystemTime(&pdb
->SystemTime
);
1751 GetSystemTimeAsFileTime((FILETIME
*)&pdb
->PerfTime100nSec
);
1757 /******************************************************************************
1758 * RegQueryValueExW [ADVAPI32.@]
1760 * See RegQueryValueExA.
1762 LSTATUS WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
1763 LPBYTE data
, LPDWORD count
)
1766 UNICODE_STRING name_str
;
1768 char buffer
[256], *buf_ptr
= buffer
;
1769 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1770 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1772 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1773 hkey
, debugstr_w(name
), reserved
, type
, data
, count
,
1774 (count
&& data
) ? *count
: 0 );
1776 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1778 if (hkey
== HKEY_PERFORMANCE_DATA
)
1779 return query_perf_data(name
, type
, data
, count
);
1781 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1783 RtlInitUnicodeString( &name_str
, name
);
1785 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
1788 total_size
= info_size
;
1789 if (count
) *count
= 0;
1792 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1793 buffer
, total_size
, &total_size
);
1794 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1798 /* retry with a dynamically allocated buffer */
1799 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
1801 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1802 if (!(buf_ptr
= heap_alloc( total_size
)))
1803 return ERROR_NOT_ENOUGH_MEMORY
;
1804 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1805 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1806 buf_ptr
, total_size
, &total_size
);
1811 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1812 /* if the type is REG_SZ and data is not 0-terminated
1813 * and there is enough space in the buffer NT appends a \0 */
1814 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1816 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
1817 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1820 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1822 else status
= STATUS_SUCCESS
;
1824 if (type
) *type
= info
->Type
;
1825 if (count
) *count
= total_size
- info_size
;
1828 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1829 return RtlNtStatusToDosError(status
);
1833 /******************************************************************************
1834 * RegQueryValueExA [ADVAPI32.@]
1836 * Get the type and contents of a specified value under with a key.
1839 * hkey [I] Handle of the key to query
1840 * name [I] Name of value under hkey to query
1841 * reserved [I] Reserved - must be NULL
1842 * type [O] Destination for the value type, or NULL if not required
1843 * data [O] Destination for the values contents, or NULL if not required
1844 * count [I/O] Size of data, updated with the number of bytes returned
1847 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1848 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1849 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1850 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1853 * MSDN states that if data is too small it is partially filled. In reality
1854 * it remains untouched.
1856 LSTATUS WINAPI DECLSPEC_HOTPATCH
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
,
1857 LPDWORD type
, LPBYTE data
, LPDWORD count
)
1861 UNICODE_STRING nameW
;
1862 DWORD total_size
, datalen
= 0;
1863 char buffer
[256], *buf_ptr
= buffer
;
1864 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1865 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1867 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1868 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
1870 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1871 if (hkey
!= HKEY_PERFORMANCE_DATA
&& !(hkey
= get_special_root_hkey( hkey
, 0 )))
1872 return ERROR_INVALID_HANDLE
;
1874 if (count
) datalen
= *count
;
1875 if (!data
&& count
) *count
= 0;
1877 /* this matches Win9x behaviour - NT sets *type to a random value */
1878 if (type
) *type
= REG_NONE
;
1880 RtlInitAnsiString( &nameA
, name
);
1881 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1882 return RtlNtStatusToDosError(status
);
1884 if (hkey
== HKEY_PERFORMANCE_DATA
)
1886 DWORD ret
= query_perf_data( nameW
.Buffer
, type
, data
, count
);
1887 RtlFreeUnicodeString( &nameW
);
1891 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1892 buffer
, sizeof(buffer
), &total_size
);
1893 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1895 /* we need to fetch the contents for a string type even if not requested,
1896 * because we need to compute the length of the ASCII string. */
1897 if (data
|| is_string(info
->Type
))
1899 /* retry with a dynamically allocated buffer */
1900 while (status
== STATUS_BUFFER_OVERFLOW
)
1902 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1903 if (!(buf_ptr
= heap_alloc( total_size
)))
1905 status
= STATUS_NO_MEMORY
;
1908 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1909 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1910 buf_ptr
, total_size
, &total_size
);
1913 if (status
) goto done
;
1915 if (is_string(info
->Type
))
1919 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
1920 total_size
- info_size
);
1923 if (len
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1926 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
1927 total_size
- info_size
);
1928 /* if the type is REG_SZ and data is not 0-terminated
1929 * and there is enough space in the buffer NT appends a \0 */
1930 if (len
< datalen
&& data
[len
-1]) data
[len
] = 0;
1933 total_size
= len
+ info_size
;
1937 if (total_size
- info_size
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1938 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1941 else status
= STATUS_SUCCESS
;
1943 if (type
) *type
= info
->Type
;
1944 if (count
) *count
= total_size
- info_size
;
1947 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1948 RtlFreeUnicodeString( &nameW
);
1949 return RtlNtStatusToDosError(status
);
1953 /******************************************************************************
1954 * RegQueryValueW [ADVAPI32.@]
1956 * Retrieves the data associated with the default or unnamed value of a key.
1959 * hkey [I] Handle to an open key.
1960 * name [I] Name of the subkey of hKey.
1961 * data [O] Receives the string associated with the default value
1963 * count [I/O] Size of lpValue in bytes.
1966 * Success: ERROR_SUCCESS
1967 * Failure: nonzero error code from Winerror.h
1969 LSTATUS WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
1974 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
1976 if (name
&& name
[0])
1978 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1980 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1981 if (subkey
!= hkey
) RegCloseKey( subkey
);
1982 if (ret
== ERROR_FILE_NOT_FOUND
)
1984 /* return empty string if default value not found */
1985 if (data
) *data
= 0;
1986 if (count
) *count
= sizeof(WCHAR
);
1987 ret
= ERROR_SUCCESS
;
1993 /******************************************************************************
1994 * RegQueryValueA [ADVAPI32.@]
1996 * See RegQueryValueW.
1998 LSTATUS WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
2003 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
2005 if (name
&& name
[0])
2007 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
2009 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
2010 if (subkey
!= hkey
) RegCloseKey( subkey
);
2011 if (ret
== ERROR_FILE_NOT_FOUND
)
2013 /* return empty string if default value not found */
2014 if (data
) *data
= 0;
2015 if (count
) *count
= 1;
2016 ret
= ERROR_SUCCESS
;
2022 /******************************************************************************
2023 * ADVAPI_ApplyRestrictions [internal]
2025 * Helper function for RegGetValueA/W.
2027 static VOID
ADVAPI_ApplyRestrictions( DWORD dwFlags
, DWORD dwType
,
2028 DWORD cbData
, PLONG ret
)
2030 /* Check if the type is restricted by the passed flags */
2031 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
2037 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
2038 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
2039 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
2040 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
2041 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
2042 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
2043 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
2046 if (dwFlags
& dwMask
)
2048 /* Type is not restricted, check for size mismatch */
2049 if (dwType
== REG_BINARY
)
2053 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
2055 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
2058 if (cbExpect
&& cbData
!= cbExpect
)
2059 *ret
= ERROR_DATATYPE_MISMATCH
;
2062 else *ret
= ERROR_UNSUPPORTED_TYPE
;
2067 /******************************************************************************
2068 * RegGetValueW [ADVAPI32.@]
2070 * Retrieves the type and data for a value name associated with a key,
2071 * optionally expanding its content and restricting its type.
2074 * hKey [I] Handle to an open key.
2075 * pszSubKey [I] Name of the subkey of hKey.
2076 * pszValue [I] Name of value under hKey/szSubKey to query.
2077 * dwFlags [I] Flags restricting the value type to retrieve.
2078 * pdwType [O] Destination for the values type, may be NULL.
2079 * pvData [O] Destination for the values content, may be NULL.
2080 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
2081 * retrieve the whole content, including the trailing '\0'
2085 * Success: ERROR_SUCCESS
2086 * Failure: nonzero error code from Winerror.h
2089 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
2090 * expanded and pdwType is set to REG_SZ instead.
2091 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
2092 * without RRF_NOEXPAND is thus not allowed.
2093 * An exception is the case where RRF_RT_ANY is specified, because then
2094 * RRF_NOEXPAND is allowed.
2096 LSTATUS WINAPI
RegGetValueW( HKEY hKey
, LPCWSTR pszSubKey
, LPCWSTR pszValue
,
2097 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
2100 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2104 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
2105 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
2106 pvData
, pcbData
, cbData
);
2108 if (pvData
&& !pcbData
)
2109 return ERROR_INVALID_PARAMETER
;
2110 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2111 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2112 return ERROR_INVALID_PARAMETER
;
2114 if (pszSubKey
&& pszSubKey
[0])
2116 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2117 if (ret
!= ERROR_SUCCESS
) return ret
;
2120 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2122 /* If we are going to expand we need to read in the whole the value even
2123 * if the passed buffer was too small as the expanded string might be
2124 * smaller than the unexpanded one and could fit into cbData bytes. */
2125 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2126 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
2131 pvBuf
= heap_alloc(cbData
);
2134 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2138 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2139 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
2140 &dwType
, pvBuf
, &cbData
);
2143 /* Even if cbData was large enough we have to copy the
2144 * string since ExpandEnvironmentStrings can't handle
2145 * overlapping buffers. */
2146 CopyMemory(pvBuf
, pvData
, cbData
);
2149 /* Both the type or the value itself could have been modified in
2150 * between so we have to keep retrying until the buffer is large
2151 * enough or we no longer have to expand the value. */
2152 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2154 if (ret
== ERROR_SUCCESS
)
2156 /* Recheck dwType in case it changed since the first call */
2157 if (dwType
== REG_EXPAND_SZ
)
2159 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
2160 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
2162 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2163 ret
= ERROR_MORE_DATA
;
2166 CopyMemory(pvData
, pvBuf
, *pcbData
);
2172 if (pszSubKey
&& pszSubKey
[0])
2175 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2177 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2178 ZeroMemory(pvData
, *pcbData
);
2180 if (pdwType
) *pdwType
= dwType
;
2181 if (pcbData
) *pcbData
= cbData
;
2187 /******************************************************************************
2188 * RegGetValueA [ADVAPI32.@]
2192 LSTATUS WINAPI
RegGetValueA( HKEY hKey
, LPCSTR pszSubKey
, LPCSTR pszValue
,
2193 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
2196 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
2200 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
2201 hKey
, debugstr_a(pszSubKey
), debugstr_a(pszValue
), dwFlags
,
2202 pdwType
, pvData
, pcbData
, cbData
);
2204 if (pvData
&& !pcbData
)
2205 return ERROR_INVALID_PARAMETER
;
2206 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
2207 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
2208 return ERROR_INVALID_PARAMETER
;
2210 if (pszSubKey
&& pszSubKey
[0])
2212 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
2213 if (ret
!= ERROR_SUCCESS
) return ret
;
2216 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
2218 /* If we are going to expand we need to read in the whole the value even
2219 * if the passed buffer was too small as the expanded string might be
2220 * smaller than the unexpanded one and could fit into cbData bytes. */
2221 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
2222 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
2227 pvBuf
= heap_alloc(cbData
);
2230 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2234 if (ret
== ERROR_MORE_DATA
|| !pvData
)
2235 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
2236 &dwType
, pvBuf
, &cbData
);
2239 /* Even if cbData was large enough we have to copy the
2240 * string since ExpandEnvironmentStrings can't handle
2241 * overlapping buffers. */
2242 CopyMemory(pvBuf
, pvData
, cbData
);
2245 /* Both the type or the value itself could have been modified in
2246 * between so we have to keep retrying until the buffer is large
2247 * enough or we no longer have to expand the value. */
2248 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
2250 if (ret
== ERROR_SUCCESS
)
2252 /* Recheck dwType in case it changed since the first call */
2253 if (dwType
== REG_EXPAND_SZ
)
2255 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
2256 pcbData
? *pcbData
: 0);
2258 if(pvData
&& pcbData
&& cbData
> *pcbData
)
2259 ret
= ERROR_MORE_DATA
;
2262 CopyMemory(pvData
, pvBuf
, *pcbData
);
2268 if (pszSubKey
&& pszSubKey
[0])
2271 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
2273 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
2274 ZeroMemory(pvData
, *pcbData
);
2276 if (pdwType
) *pdwType
= dwType
;
2277 if (pcbData
) *pcbData
= cbData
;
2283 /******************************************************************************
2284 * RegEnumValueW [ADVAPI32.@]
2286 * Enumerates the values for the specified open registry key.
2289 * hkey [I] Handle to key to query
2290 * index [I] Index of value to query
2291 * value [O] Value string
2292 * val_count [I/O] Size of value buffer (in wchars)
2293 * reserved [I] Reserved
2294 * type [O] Type code
2295 * data [O] Value data
2296 * count [I/O] Size of data buffer (in bytes)
2299 * Success: ERROR_SUCCESS
2300 * Failure: nonzero error code from Winerror.h
2303 LSTATUS WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
2304 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
2308 char buffer
[256], *buf_ptr
= buffer
;
2309 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2310 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
2312 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
2313 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
2315 if ((data
&& !count
) || reserved
|| !value
|| !val_count
)
2316 return ERROR_INVALID_PARAMETER
;
2317 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2319 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2320 if (data
) total_size
+= *count
;
2321 total_size
= min( sizeof(buffer
), total_size
);
2323 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
2324 buffer
, total_size
, &total_size
);
2326 /* retry with a dynamically allocated buffer */
2327 while (status
== STATUS_BUFFER_OVERFLOW
)
2329 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
2330 if (!(buf_ptr
= heap_alloc( total_size
)))
2331 return ERROR_NOT_ENOUGH_MEMORY
;
2332 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2333 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
2334 buf_ptr
, total_size
, &total_size
);
2337 if (status
) goto done
;
2339 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
2341 status
= STATUS_BUFFER_OVERFLOW
;
2344 memcpy( value
, info
->Name
, info
->NameLength
);
2345 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
2346 value
[*val_count
] = 0;
2350 if (total_size
- info
->DataOffset
> *count
)
2352 status
= STATUS_BUFFER_OVERFLOW
;
2355 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2356 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
2358 /* if the type is REG_SZ and data is not 0-terminated
2359 * and there is enough space in the buffer NT appends a \0 */
2360 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
2361 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
2366 if (type
) *type
= info
->Type
;
2367 if (count
) *count
= info
->DataLength
;
2370 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
2371 return RtlNtStatusToDosError(status
);
2375 /******************************************************************************
2376 * RegEnumValueA [ADVAPI32.@]
2378 * See RegEnumValueW.
2380 LSTATUS WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
2381 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
2385 char buffer
[256], *buf_ptr
= buffer
;
2386 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
2387 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
2389 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
2390 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
2392 if ((data
&& !count
) || reserved
|| !value
|| !val_count
)
2393 return ERROR_INVALID_PARAMETER
;
2394 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2396 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2397 if (data
) total_size
+= *count
;
2398 total_size
= min( sizeof(buffer
), total_size
);
2400 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
2401 buffer
, total_size
, &total_size
);
2403 /* we need to fetch the contents for a string type even if not requested,
2404 * because we need to compute the length of the ASCII string. */
2406 /* retry with a dynamically allocated buffer */
2407 while (status
== STATUS_BUFFER_OVERFLOW
)
2409 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
2410 if (!(buf_ptr
= heap_alloc( total_size
)))
2411 return ERROR_NOT_ENOUGH_MEMORY
;
2412 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2413 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
2414 buf_ptr
, total_size
, &total_size
);
2417 if (status
) goto done
;
2419 if (is_string(info
->Type
))
2422 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2423 total_size
- info
->DataOffset
);
2426 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2429 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2430 total_size
- info
->DataOffset
);
2431 /* if the type is REG_SZ and data is not 0-terminated
2432 * and there is enough space in the buffer NT appends a \0 */
2433 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2436 info
->DataLength
= len
;
2440 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2441 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2448 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2449 if (len
>= *val_count
)
2451 status
= STATUS_BUFFER_OVERFLOW
;
2454 len
= *val_count
- 1;
2455 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2461 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2467 if (type
) *type
= info
->Type
;
2468 if (count
) *count
= info
->DataLength
;
2471 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
2472 return RtlNtStatusToDosError(status
);
2475 /******************************************************************************
2476 * RegDeleteValueW [ADVAPI32.@]
2478 * See RegDeleteValueA.
2480 LSTATUS WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
2482 return RegDeleteKeyValueW( hkey
, NULL
, name
);
2485 /******************************************************************************
2486 * RegDeleteValueA [ADVAPI32.@]
2488 * Delete a value from the registry.
2491 * hkey [I] Registry handle of the key holding the value
2492 * name [I] Name of the value under hkey to delete
2495 * Success: ERROR_SUCCESS
2496 * Failure: nonzero error code from Winerror.h
2498 LSTATUS WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
2500 return RegDeleteKeyValueA( hkey
, NULL
, name
);
2503 /******************************************************************************
2504 * RegDeleteKeyValueW [ADVAPI32.@]
2506 LONG WINAPI
RegDeleteKeyValueW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR name
)
2508 UNICODE_STRING nameW
;
2512 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2516 if ((ret
= RegOpenKeyExW( hkey
, subkey
, 0, KEY_SET_VALUE
, &hsubkey
)))
2521 RtlInitUnicodeString( &nameW
, name
);
2522 ret
= RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
2523 if (hsubkey
) RegCloseKey( hsubkey
);
2527 /******************************************************************************
2528 * RegDeleteKeyValueA [ADVAPI32.@]
2530 LONG WINAPI
RegDeleteKeyValueA( HKEY hkey
, LPCSTR subkey
, LPCSTR name
)
2532 UNICODE_STRING nameW
;
2537 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2541 LONG ret
= RegOpenKeyExA( hkey
, subkey
, 0, KEY_SET_VALUE
, &hsubkey
);
2547 RtlInitAnsiString( &nameA
, name
);
2548 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
2550 status
= NtDeleteValueKey( hkey
, &nameW
);
2551 RtlFreeUnicodeString( &nameW
);
2554 if (hsubkey
) RegCloseKey( hsubkey
);
2555 return RtlNtStatusToDosError( status
);
2558 /******************************************************************************
2559 * RegLoadKeyW [ADVAPI32.@]
2561 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2562 * registration information from a specified file into that subkey.
2565 * hkey [I] Handle of open key
2566 * subkey [I] Address of name of subkey
2567 * filename [I] Address of filename for registry information
2570 * Success: ERROR_SUCCESS
2571 * Failure: nonzero error code from Winerror.h
2573 LSTATUS WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
2575 OBJECT_ATTRIBUTES destkey
, file
;
2576 UNICODE_STRING subkeyW
, filenameW
;
2579 if (!(hkey
= get_special_root_hkey(hkey
, 0))) return ERROR_INVALID_HANDLE
;
2581 destkey
.Length
= sizeof(destkey
);
2582 destkey
.RootDirectory
= hkey
; /* root key: HKLM or HKU */
2583 destkey
.ObjectName
= &subkeyW
; /* name of the key */
2584 destkey
.Attributes
= 0;
2585 destkey
.SecurityDescriptor
= NULL
;
2586 destkey
.SecurityQualityOfService
= NULL
;
2587 RtlInitUnicodeString(&subkeyW
, subkey
);
2589 file
.Length
= sizeof(file
);
2590 file
.RootDirectory
= NULL
;
2591 file
.ObjectName
= &filenameW
; /* file containing the hive */
2592 file
.Attributes
= OBJ_CASE_INSENSITIVE
;
2593 file
.SecurityDescriptor
= NULL
;
2594 file
.SecurityQualityOfService
= NULL
;
2595 RtlDosPathNameToNtPathName_U(filename
, &filenameW
, NULL
, NULL
);
2597 status
= NtLoadKey(&destkey
, &file
);
2598 RtlFreeUnicodeString(&filenameW
);
2599 return RtlNtStatusToDosError( status
);
2603 /******************************************************************************
2604 * RegLoadKeyA [ADVAPI32.@]
2608 LSTATUS WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
2610 UNICODE_STRING subkeyW
, filenameW
;
2611 STRING subkeyA
, filenameA
;
2615 RtlInitAnsiString(&subkeyA
, subkey
);
2616 RtlInitAnsiString(&filenameA
, filename
);
2618 RtlInitUnicodeString(&subkeyW
, NULL
);
2619 RtlInitUnicodeString(&filenameW
, NULL
);
2620 if (!(status
= RtlAnsiStringToUnicodeString(&subkeyW
, &subkeyA
, TRUE
)) &&
2621 !(status
= RtlAnsiStringToUnicodeString(&filenameW
, &filenameA
, TRUE
)))
2623 ret
= RegLoadKeyW(hkey
, subkeyW
.Buffer
, filenameW
.Buffer
);
2625 else ret
= RtlNtStatusToDosError(status
);
2626 RtlFreeUnicodeString(&subkeyW
);
2627 RtlFreeUnicodeString(&filenameW
);
2632 /******************************************************************************
2633 * RegSaveKeyW [ADVAPI32.@]
2635 * Save a key and all of its subkeys and values to a new file in the standard format.
2638 * hkey [I] Handle of key where save begins
2639 * lpFile [I] Address of filename to save to
2640 * sa [I] Address of security structure
2643 * Success: ERROR_SUCCESS
2644 * Failure: nonzero error code from Winerror.h
2646 LSTATUS WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
2648 static const WCHAR format
[] =
2649 {'r','e','g','%','0','4','x','.','t','m','p',0};
2650 WCHAR buffer
[MAX_PATH
];
2656 TRACE( "(%p,%s,%p)\n", hkey
, debugstr_w(file
), sa
);
2658 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
2659 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2661 err
= GetLastError();
2662 GetFullPathNameW( file
, ARRAY_SIZE( buffer
), buffer
, &nameW
);
2666 snprintfW( nameW
, 16, format
, count
++ );
2667 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
2668 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
2669 if (handle
!= INVALID_HANDLE_VALUE
) break;
2670 if ((ret
= GetLastError()) != ERROR_FILE_EXISTS
) goto done
;
2672 /* Something gone haywire ? Please report if this happens abnormally */
2674 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
);
2677 ret
= RtlNtStatusToDosError(NtSaveKey(hkey
, handle
));
2679 CloseHandle( handle
);
2682 if (!MoveFileExW( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
2684 ERR( "Failed to move %s to %s\n", debugstr_w(buffer
),
2686 ret
= GetLastError();
2689 if (ret
) DeleteFileW( buffer
);
2692 SetLastError( err
); /* restore last error code */
2697 /******************************************************************************
2698 * RegSaveKeyA [ADVAPI32.@]
2702 LSTATUS WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
2704 UNICODE_STRING
*fileW
= &NtCurrentTeb()->StaticUnicodeString
;
2708 RtlInitAnsiString(&fileA
, file
);
2709 if ((status
= RtlAnsiStringToUnicodeString(fileW
, &fileA
, FALSE
)))
2710 return RtlNtStatusToDosError( status
);
2711 return RegSaveKeyW(hkey
, fileW
->Buffer
, sa
);
2714 /******************************************************************************
2715 * RegSaveKeyExA [ADVAPI32.@]
2718 LSTATUS WINAPI
RegSaveKeyExA( HKEY hkey
, LPCSTR file
, SECURITY_ATTRIBUTES
*sa
, DWORD flags
)
2720 FIXME( "(%p,%s,%p,%d) flags not handled\n", hkey
, debugstr_a(file
), sa
, flags
);
2721 return RegSaveKeyA(hkey
, file
, sa
);
2724 /******************************************************************************
2725 * RegSaveKeyExW [ADVAPI32.@]
2728 LSTATUS WINAPI
RegSaveKeyExW( HKEY hkey
, LPCWSTR file
, SECURITY_ATTRIBUTES
*sa
, DWORD flags
)
2730 FIXME( "(%p,%s,%p,%d) flags not handled\n", hkey
, debugstr_w(file
), sa
, flags
);
2731 return RegSaveKeyW(hkey
, file
, sa
);
2734 /******************************************************************************
2735 * RegRestoreKeyW [ADVAPI32.@]
2737 * Read the registry information from a file and copy it over a key.
2740 * hkey [I] Handle of key where restore begins
2741 * lpFile [I] Address of filename containing saved tree
2742 * dwFlags [I] Optional flags
2745 * Success: ERROR_SUCCESS
2746 * Failure: nonzero error code from Winerror.h
2748 LSTATUS WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
2750 TRACE("(%p,%s,%d)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2752 /* It seems to do this check before the hkey check */
2753 if (!lpFile
|| !*lpFile
)
2754 return ERROR_INVALID_PARAMETER
;
2756 FIXME("(%p,%s,%d): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2758 /* Check for file existence */
2760 return ERROR_SUCCESS
;
2764 /******************************************************************************
2765 * RegRestoreKeyA [ADVAPI32.@]
2767 * See RegRestoreKeyW.
2769 LSTATUS WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
2771 UNICODE_STRING lpFileW
;
2774 RtlCreateUnicodeStringFromAsciiz( &lpFileW
, lpFile
);
2775 ret
= RegRestoreKeyW( hkey
, lpFileW
.Buffer
, dwFlags
);
2776 RtlFreeUnicodeString( &lpFileW
);
2781 /******************************************************************************
2782 * RegUnLoadKeyW [ADVAPI32.@]
2784 * Unload a registry key and its subkeys from the registry.
2787 * hkey [I] Handle of open key
2788 * lpSubKey [I] Address of name of subkey to unload
2791 * Success: ERROR_SUCCESS
2792 * Failure: nonzero error code from Winerror.h
2794 LSTATUS WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
2798 OBJECT_ATTRIBUTES attr
;
2799 UNICODE_STRING subkey
;
2801 TRACE("(%p,%s)\n",hkey
, debugstr_w(lpSubKey
));
2803 ret
= RegOpenKeyW(hkey
,lpSubKey
,&shkey
);
2805 return ERROR_INVALID_PARAMETER
;
2807 RtlInitUnicodeString(&subkey
, lpSubKey
);
2808 InitializeObjectAttributes(&attr
, &subkey
, OBJ_CASE_INSENSITIVE
, shkey
, NULL
);
2809 ret
= RtlNtStatusToDosError(NtUnloadKey(&attr
));
2817 /******************************************************************************
2818 * RegUnLoadKeyA [ADVAPI32.@]
2820 * See RegUnLoadKeyW.
2822 LSTATUS WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
2824 UNICODE_STRING lpSubKeyW
;
2827 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2828 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
.Buffer
);
2829 RtlFreeUnicodeString( &lpSubKeyW
);
2834 /******************************************************************************
2835 * RegReplaceKeyW [ADVAPI32.@]
2837 * Replace the file backing a registry key and all its subkeys with another file.
2840 * hkey [I] Handle of open key
2841 * lpSubKey [I] Address of name of subkey
2842 * lpNewFile [I] Address of filename for file with new data
2843 * lpOldFile [I] Address of filename for backup file
2846 * Success: ERROR_SUCCESS
2847 * Failure: nonzero error code from Winerror.h
2849 LSTATUS WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
2852 FIXME("(%p,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
2853 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
2854 return ERROR_SUCCESS
;
2858 /******************************************************************************
2859 * RegReplaceKeyA [ADVAPI32.@]
2861 * See RegReplaceKeyW.
2863 LSTATUS WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
2866 UNICODE_STRING lpSubKeyW
;
2867 UNICODE_STRING lpNewFileW
;
2868 UNICODE_STRING lpOldFileW
;
2871 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2872 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW
, lpOldFile
);
2873 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW
, lpNewFile
);
2874 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
.Buffer
, lpNewFileW
.Buffer
, lpOldFileW
.Buffer
);
2875 RtlFreeUnicodeString( &lpOldFileW
);
2876 RtlFreeUnicodeString( &lpNewFileW
);
2877 RtlFreeUnicodeString( &lpSubKeyW
);
2882 /******************************************************************************
2883 * RegSetKeySecurity [ADVAPI32.@]
2885 * Set the security of an open registry key.
2888 * hkey [I] Open handle of key to set
2889 * SecurityInfo [I] Descriptor contents
2890 * pSecurityDesc [I] Address of descriptor for key
2893 * Success: ERROR_SUCCESS
2894 * Failure: nonzero error code from Winerror.h
2896 LSTATUS WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
2897 PSECURITY_DESCRIPTOR pSecurityDesc
)
2899 TRACE("(%p,%d,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
2901 /* It seems to perform this check before the hkey check */
2902 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
2903 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
2904 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
2905 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
2908 return ERROR_INVALID_PARAMETER
;
2911 return ERROR_INVALID_PARAMETER
;
2913 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2915 return RtlNtStatusToDosError( NtSetSecurityObject( hkey
, SecurityInfo
, pSecurityDesc
) );
2919 /******************************************************************************
2920 * RegGetKeySecurity [ADVAPI32.@]
2922 * Get a copy of the security descriptor for a given registry key.
2925 * hkey [I] Open handle of key to set
2926 * SecurityInformation [I] Descriptor contents
2927 * pSecurityDescriptor [O] Address of descriptor for key
2928 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2931 * Success: ERROR_SUCCESS
2932 * Failure: Error code
2934 LSTATUS WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
2935 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2936 LPDWORD lpcbSecurityDescriptor
)
2938 TRACE("(%p,%d,%p,%d)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
2939 *lpcbSecurityDescriptor
);
2941 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2943 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey
,
2944 SecurityInformation
, pSecurityDescriptor
,
2945 *lpcbSecurityDescriptor
, lpcbSecurityDescriptor
) );
2949 /******************************************************************************
2950 * RegFlushKey [ADVAPI32.@]
2952 * Immediately write a registry key to registry.
2955 * hkey [I] Handle of key to write
2958 * Success: ERROR_SUCCESS
2959 * Failure: Error code
2961 LSTATUS WINAPI
RegFlushKey( HKEY hkey
)
2963 hkey
= get_special_root_hkey( hkey
, 0 );
2964 if (!hkey
) return ERROR_INVALID_HANDLE
;
2966 return RtlNtStatusToDosError( NtFlushKey( hkey
) );
2970 /******************************************************************************
2971 * RegConnectRegistryW [ADVAPI32.@]
2973 * Establish a connection to a predefined registry key on another computer.
2976 * lpMachineName [I] Address of name of remote computer
2977 * hHey [I] Predefined registry handle
2978 * phkResult [I] Address of buffer for remote registry handle
2981 * Success: ERROR_SUCCESS
2982 * Failure: nonzero error code from Winerror.h
2984 LSTATUS WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
2989 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName
), hKey
, phkResult
);
2991 if (!lpMachineName
|| !*lpMachineName
) {
2992 /* Use the local machine name */
2993 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
2996 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
2997 DWORD len
= ARRAY_SIZE( compName
);
2999 /* MSDN says lpMachineName must start with \\ : not so */
3000 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
3002 if (GetComputerNameW(compName
, &len
))
3004 if (!strcmpiW(lpMachineName
, compName
))
3005 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
3008 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
3009 ret
= ERROR_BAD_NETPATH
;
3013 ret
= GetLastError();
3019 /******************************************************************************
3020 * RegConnectRegistryA [ADVAPI32.@]
3022 * See RegConnectRegistryW.
3024 LSTATUS WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, PHKEY reskey
)
3026 UNICODE_STRING machineW
;
3029 RtlCreateUnicodeStringFromAsciiz( &machineW
, machine
);
3030 ret
= RegConnectRegistryW( machineW
.Buffer
, hkey
, reskey
);
3031 RtlFreeUnicodeString( &machineW
);
3036 /******************************************************************************
3037 * RegNotifyChangeKeyValue [ADVAPI32.@]
3039 * Notify the caller about changes to the attributes or contents of a registry key.
3042 * hkey [I] Handle of key to watch
3043 * fWatchSubTree [I] Flag for subkey notification
3044 * fdwNotifyFilter [I] Changes to be reported
3045 * hEvent [I] Handle of signaled event
3046 * fAsync [I] Flag for asynchronous reporting
3049 * Success: ERROR_SUCCESS
3050 * Failure: nonzero error code from Winerror.h
3052 LSTATUS WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
3053 DWORD fdwNotifyFilter
, HANDLE hEvent
,
3057 IO_STATUS_BLOCK iosb
;
3059 hkey
= get_special_root_hkey( hkey
, 0 );
3060 if (!hkey
) return ERROR_INVALID_HANDLE
;
3062 TRACE("(%p,%i,%d,%p,%i)\n", hkey
, fWatchSubTree
, fdwNotifyFilter
,
3065 status
= NtNotifyChangeKey( hkey
, hEvent
, NULL
, NULL
, &iosb
,
3066 fdwNotifyFilter
, fWatchSubTree
, NULL
, 0,
3069 if (status
&& status
!= STATUS_PENDING
)
3070 return RtlNtStatusToDosError( status
);
3072 return ERROR_SUCCESS
;
3075 /******************************************************************************
3076 * RegOpenUserClassesRoot [ADVAPI32.@]
3078 * Open the HKEY_CLASSES_ROOT key for a user.
3081 * hToken [I] Handle of token representing the user
3082 * dwOptions [I] Reserved, must be 0
3083 * samDesired [I] Desired access rights
3084 * phkResult [O] Destination for the resulting key handle
3087 * Success: ERROR_SUCCESS
3088 * Failure: nonzero error code from Winerror.h
3091 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
3092 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
3093 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
3095 LSTATUS WINAPI
RegOpenUserClassesRoot(
3102 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken
, dwOptions
, samDesired
, phkResult
);
3104 *phkResult
= HKEY_CLASSES_ROOT
;
3105 return ERROR_SUCCESS
;
3108 /******************************************************************************
3109 * load_string [Internal]
3111 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
3112 * avoid importing user32, which is higher level than advapi32. Helper for
3115 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
3122 /* Negative values have to be inverted. */
3123 if (HIWORD(resId
) == 0xffff)
3124 resId
= (UINT
)(-((INT
)resId
));
3126 /* Load the resource into memory and get a pointer to it. */
3127 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
3128 if (!hResource
) return 0;
3129 hMemory
= LoadResource(hModule
, hResource
);
3130 if (!hMemory
) return 0;
3131 pString
= LockResource(hMemory
);
3133 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
3134 idxString
= resId
& 0xf;
3135 while (idxString
--) pString
+= *pString
+ 1;
3137 /* If no buffer is given, return length of the string. */
3138 if (!pwszBuffer
) return *pString
;
3140 /* Else copy over the string, respecting the buffer size. */
3141 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
3142 if (cMaxChars
>= 0) {
3143 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
3144 pwszBuffer
[cMaxChars
] = '\0';
3150 /******************************************************************************
3151 * RegLoadMUIStringW [ADVAPI32.@]
3153 * Load the localized version of a string resource from some PE, respective
3154 * id and path of which are given in the registry value in the format
3155 * @[path]\dllname,-resourceId
3158 * hKey [I] Key, of which to load the string value from.
3159 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
3160 * pszBuffer [O] Buffer to store the localized string in.
3161 * cbBuffer [I] Size of the destination buffer in bytes.
3162 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
3163 * dwFlags [I] None supported yet.
3164 * pszBaseDir [I] Not supported yet.
3167 * Success: ERROR_SUCCESS,
3168 * Failure: nonzero error code from winerror.h
3171 * This is an API of Windows Vista, which wasn't available at the time this code
3172 * was written. We have to check for the correct behaviour once it's available.
3174 LSTATUS WINAPI
RegLoadMUIStringW(HKEY hKey
, LPCWSTR pwszValue
, LPWSTR pwszBuffer
, DWORD cbBuffer
,
3175 LPDWORD pcbData
, DWORD dwFlags
, LPCWSTR pwszBaseDir
)
3177 DWORD dwValueType
, cbData
;
3178 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
3181 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
3182 "dwFlags = %d, pwszBaseDir = %s)\n", hKey
, debugstr_w(pwszValue
), pwszBuffer
,
3183 cbBuffer
, pcbData
, dwFlags
, debugstr_w(pwszBaseDir
));
3185 /* Parameter sanity checks. */
3186 if (!hKey
|| !pwszBuffer
)
3187 return ERROR_INVALID_PARAMETER
;
3189 if (pwszBaseDir
&& *pwszBaseDir
) {
3190 FIXME("BaseDir parameter not yet supported!\n");
3191 return ERROR_INVALID_PARAMETER
;
3194 /* Check for value existence and correctness of its type, allocate a buffer and load it. */
3195 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
3196 if (result
!= ERROR_SUCCESS
) goto cleanup
;
3197 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
) {
3198 result
= ERROR_FILE_NOT_FOUND
;
3201 pwszTempBuffer
= heap_alloc(cbData
);
3202 if (!pwszTempBuffer
) {
3203 result
= ERROR_NOT_ENOUGH_MEMORY
;
3206 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
3207 if (result
!= ERROR_SUCCESS
) goto cleanup
;
3209 /* Expand environment variables, if appropriate, or copy the original string over. */
3210 if (dwValueType
== REG_EXPAND_SZ
) {
3211 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
3212 if (!cbData
) goto cleanup
;
3213 pwszExpandedBuffer
= heap_alloc(cbData
);
3214 if (!pwszExpandedBuffer
) {
3215 result
= ERROR_NOT_ENOUGH_MEMORY
;
3218 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
3220 pwszExpandedBuffer
= heap_alloc(cbData
);
3221 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
3224 /* If the value references a resource based string, parse the value and load the string.
3225 * Else just copy over the original value. */
3226 result
= ERROR_SUCCESS
;
3227 if (*pwszExpandedBuffer
!= '@') { /* '@' is the prefix for resource based string entries. */
3228 lstrcpynW(pwszBuffer
, pwszExpandedBuffer
, cbBuffer
/ sizeof(WCHAR
));
3230 WCHAR
*pComma
= strrchrW(pwszExpandedBuffer
, ',');
3234 /* Format of the expanded value is 'path_to_dll,-resId' */
3235 if (!pComma
|| pComma
[1] != '-') {
3236 result
= ERROR_BADKEY
;
3240 uiStringId
= atoiW(pComma
+2);
3243 hModule
= LoadLibraryW(pwszExpandedBuffer
+ 1);
3244 if (!hModule
|| !load_string(hModule
, uiStringId
, pwszBuffer
, cbBuffer
/sizeof(WCHAR
)))
3245 result
= ERROR_BADKEY
;
3246 FreeLibrary(hModule
);
3250 heap_free(pwszTempBuffer
);
3251 heap_free(pwszExpandedBuffer
);
3255 /******************************************************************************
3256 * RegLoadMUIStringA [ADVAPI32.@]
3258 * See RegLoadMUIStringW
3260 LSTATUS WINAPI
RegLoadMUIStringA(HKEY hKey
, LPCSTR pszValue
, LPSTR pszBuffer
, DWORD cbBuffer
,
3261 LPDWORD pcbData
, DWORD dwFlags
, LPCSTR pszBaseDir
)
3263 UNICODE_STRING valueW
, baseDirW
;
3265 DWORD cbData
= cbBuffer
* sizeof(WCHAR
);
3268 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
3269 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
3270 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszBaseDir
) ||
3271 !(pwszBuffer
= heap_alloc(cbData
)))
3273 result
= ERROR_NOT_ENOUGH_MEMORY
;
3277 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, dwFlags
,
3280 if (result
== ERROR_SUCCESS
) {
3281 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszBuffer
, cbBuffer
, NULL
, NULL
);
3287 heap_free(pwszBuffer
);
3288 RtlFreeUnicodeString(&baseDirW
);
3289 RtlFreeUnicodeString(&valueW
);
3294 /******************************************************************************
3295 * RegDisablePredefinedCache [ADVAPI32.@]
3297 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
3303 * Success: ERROR_SUCCESS
3304 * Failure: nonzero error code from Winerror.h
3307 * This is useful for services that use impersonation.
3309 LSTATUS WINAPI
RegDisablePredefinedCache(void)
3311 HKEY hkey_current_user
;
3312 int idx
= HandleToUlong(HKEY_CURRENT_USER
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
3314 /* prevent caching of future requests */
3315 hkcu_cache_disabled
= TRUE
;
3317 hkey_current_user
= InterlockedExchangePointer( (void **)&special_root_keys
[idx
], NULL
);
3319 if (hkey_current_user
)
3320 NtClose( hkey_current_user
);
3322 return ERROR_SUCCESS
;
3326 /******************************************************************************
3327 * RegDeleteTreeW [ADVAPI32.@]
3330 LSTATUS WINAPI
RegDeleteTreeW( HKEY hkey
, const WCHAR
*subkey
)
3332 static const WCHAR emptyW
[] = {0};
3333 DWORD name_size
, max_name
, max_subkey
;
3334 WCHAR
*name_buf
= NULL
;
3337 TRACE( "(%p, %s)\n", hkey
, debugstr_w(subkey
) );
3339 if (subkey
&& *subkey
)
3341 ret
= RegOpenKeyExW( hkey
, subkey
, 0, KEY_READ
, &hkey
);
3342 if (ret
) return ret
;
3345 ret
= RegQueryInfoKeyW( hkey
, NULL
, NULL
, NULL
, NULL
, &max_subkey
,
3346 NULL
, NULL
, &max_name
, NULL
, NULL
, NULL
);
3350 max_name
= max( max_subkey
, max_name
) + 1;
3351 if (!(name_buf
= heap_alloc( max_name
* sizeof(WCHAR
) )))
3353 ret
= ERROR_NOT_ENOUGH_MEMORY
;
3357 /* Recursively delete subkeys */
3360 name_size
= max_name
;
3361 ret
= RegEnumKeyExW( hkey
, 0, name_buf
, &name_size
, NULL
, NULL
, NULL
, NULL
);
3362 if (ret
== ERROR_NO_MORE_ITEMS
) break;
3363 if (ret
) goto cleanup
;
3364 ret
= RegDeleteTreeW( hkey
, name_buf
);
3365 if (ret
) goto cleanup
;
3368 /* Delete the key itself */
3369 if (subkey
&& *subkey
)
3371 ret
= RegDeleteKeyW( hkey
, emptyW
);
3378 name_size
= max_name
;
3379 ret
= RegEnumValueW( hkey
, 0, name_buf
, &name_size
, NULL
, NULL
, NULL
, NULL
);
3380 if (ret
== ERROR_NO_MORE_ITEMS
) break;
3381 if (ret
) goto cleanup
;
3382 ret
= RegDeleteValueW( hkey
, name_buf
);
3383 if (ret
) goto cleanup
;
3386 ret
= ERROR_SUCCESS
;
3389 heap_free( name_buf
);
3390 if (subkey
&& *subkey
)
3391 RegCloseKey( hkey
);
3396 /******************************************************************************
3397 * RegDeleteTreeA [ADVAPI32.@]
3400 LSTATUS WINAPI
RegDeleteTreeA( HKEY hkey
, const char *subkey
)
3402 UNICODE_STRING subkeyW
;
3405 if (subkey
) RtlCreateUnicodeStringFromAsciiz( &subkeyW
, subkey
);
3406 else subkeyW
.Buffer
= NULL
;
3407 ret
= RegDeleteTreeW( hkey
, subkeyW
.Buffer
);
3408 RtlFreeUnicodeString( &subkeyW
);
3413 /******************************************************************************
3414 * RegCopyTreeW [ADVAPI32.@]
3417 LONG WINAPI
RegCopyTreeW( HKEY hsrc
, const WCHAR
*subkey
, HKEY hdst
)
3419 DWORD name_size
, max_name
;
3420 DWORD value_size
, max_value
;
3421 DWORD max_subkey
, i
, type
;
3422 WCHAR
*name_buf
= NULL
;
3423 BYTE
*value_buf
= NULL
;
3427 TRACE( "(%p, %s, %p)\n", hsrc
, debugstr_w(subkey
), hdst
);
3431 ret
= RegOpenKeyExW( hsrc
, subkey
, 0, KEY_READ
, &hsrc
);
3432 if (ret
) return ret
;
3435 ret
= RegQueryInfoKeyW( hsrc
, NULL
, NULL
, NULL
, NULL
, &max_subkey
,
3436 NULL
, NULL
, &max_name
, &max_value
, NULL
, NULL
);
3440 max_name
= max( max_subkey
, max_name
) + 1;
3441 if (!(name_buf
= heap_alloc( max_name
* sizeof(WCHAR
) )))
3443 ret
= ERROR_NOT_ENOUGH_MEMORY
;
3447 if (!(value_buf
= heap_alloc( max_value
)))
3449 ret
= ERROR_NOT_ENOUGH_MEMORY
;
3456 name_size
= max_name
;
3457 value_size
= max_value
;
3458 ret
= RegEnumValueW( hsrc
, i
, name_buf
, &name_size
, NULL
, &type
, value_buf
, &value_size
);
3459 if (ret
== ERROR_NO_MORE_ITEMS
) break;
3460 if (ret
) goto cleanup
;
3461 ret
= RegSetValueExW( hdst
, name_buf
, 0, type
, value_buf
, value_size
);
3462 if (ret
) goto cleanup
;
3465 /* Recursively copy subkeys */
3468 name_size
= max_name
;
3469 ret
= RegEnumKeyExW( hsrc
, i
, name_buf
, &name_size
, NULL
, NULL
, NULL
, NULL
);
3470 if (ret
== ERROR_NO_MORE_ITEMS
) break;
3471 if (ret
) goto cleanup
;
3472 ret
= RegCreateKeyExW( hdst
, name_buf
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hkey
, NULL
);
3473 if (ret
) goto cleanup
;
3474 ret
= RegCopyTreeW( hsrc
, name_buf
, hkey
);
3475 RegCloseKey( hkey
);
3476 if (ret
) goto cleanup
;
3479 ret
= ERROR_SUCCESS
;
3482 heap_free( name_buf
);
3483 heap_free( value_buf
);
3485 RegCloseKey( hsrc
);
3490 /******************************************************************************
3491 * RegCopyTreeA [ADVAPI32.@]
3494 LONG WINAPI
RegCopyTreeA( HKEY hsrc
, const char *subkey
, HKEY hdst
)
3496 UNICODE_STRING subkeyW
;
3499 if (subkey
) RtlCreateUnicodeStringFromAsciiz( &subkeyW
, subkey
);
3500 else subkeyW
.Buffer
= NULL
;
3501 ret
= RegCopyTreeW( hsrc
, subkeyW
.Buffer
, hdst
);
3502 RtlFreeUnicodeString( &subkeyW
);
3507 /******************************************************************************
3508 * RegDisableReflectionKey [ADVAPI32.@]
3511 LONG WINAPI
RegDisableReflectionKey(HKEY base
)
3513 FIXME("%p: stub\n", base
);
3514 return ERROR_SUCCESS
;