rpcrt4: Write the function header into the procedure format string.
[wine.git] / dlls / advapi32 / registry.c
blob9989097ff4d909dad6059ae58cba844f80f0657d
1 /*
2 * Registry management
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
27 #include "config.h"
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38 #include "winerror.h"
39 #include "winternl.h"
40 #include "winperf.h"
41 #include "winuser.h"
42 #include "sddl.h"
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','\\',
63 'U','s','e','r',0};
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[] =
80 name_CLASSES_ROOT,
81 NULL, /* HKEY_CURRENT_USER is determined dynamically */
82 name_LOCAL_MACHINE,
83 name_USERS,
84 name_PERFORMANCE_DATA,
85 name_CURRENT_CONFIG,
86 name_DYN_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;
120 HANDLE ret;
122 attr.Length = sizeof(attr);
123 attr.RootDirectory = key;
124 attr.ObjectName = &nameW;
125 attr.Attributes = 0;
126 attr.SecurityDescriptor = NULL;
127 attr.SecurityQualityOfService = NULL;
128 RtlInitUnicodeString( &nameW, wow6432nodeW );
129 if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) ret = 0;
130 return ret;
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);
148 UNICODE_STRING str;
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;
161 for (;;)
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;
172 force_wow32 = FALSE;
175 if (i == len)
177 attr->Attributes = attrs;
178 status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos );
180 else
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;
188 if (i == len) break;
189 attr->RootDirectory = subkey;
190 while (i < len && buffer[i] == '\\') i++;
191 pos = 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;
202 return status;
205 /* wrapper for NtOpenKeyEx to handle Wow6432 nodes */
206 static NTSTATUS open_key( HKEY *retkey, DWORD options, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
208 NTSTATUS status;
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);
213 UNICODE_STRING str;
215 *retkey = NULL;
217 if (!force_wow32)
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;
227 for (;;)
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;
238 force_wow32 = FALSE;
241 if (i == len)
243 if (options & REG_OPTION_OPEN_LINK) attr->Attributes |= OBJ_OPENLINK;
244 status = NtOpenKeyEx( &subkey, access, attr, options );
246 else
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;
254 if (i == len) break;
255 while (i < len && buffer[i] == '\\') i++;
256 pos = 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;
265 return status;
268 /* create one of the HKEY_* special root keys */
269 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
271 HKEY ret = 0;
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)
281 return hkey;
283 else
285 OBJECT_ATTRIBUTES attr;
286 UNICODE_STRING name;
288 attr.Length = sizeof(attr);
289 attr.RootDirectory = 0;
290 attr.ObjectName = &name;
291 attr.Attributes = 0;
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 )))
302 ret = hkey;
303 else
304 NtClose( hkey ); /* somebody beat us to it */
306 else
307 ret = hkey;
308 return ret;
311 /* map the hkey from special root to normal key if necessary */
312 static inline HKEY get_special_root_hkey( HKEY hkey, REGSAM access )
314 HKEY ret = hkey;
316 if ((HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST))
317 && (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
319 REGSAM mask = 0;
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) );
328 return ret;
332 /******************************************************************************
333 * RegOverridePredefKey [ADVAPI32.@]
335 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
337 HKEY old_key;
338 int idx;
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);
347 if (override)
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;
379 attr.Attributes = 0;
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.
395 * PARAMS
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
406 * RETURNS
407 * Success: ERROR_SUCCESS.
408 * Failure: A standard Win32 error code. retkey remains untouched.
410 * FIXME
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;
420 NTSTATUS status;
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;
433 attr.Attributes = 0;
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,
441 &nameA, FALSE )))
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.
458 * PARAMS
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.
463 * RETURNS
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.@]
479 * See RegCreateKeyW.
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.@]
517 * See RegOpenKeyExA.
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)))
528 *retkey = hkey;
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;
541 attr.Attributes = 0;
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.
554 * PARAMS
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
561 * RETURNS
562 * Success: ERROR_SUCCESS
563 * Failure: A standard Win32 error code. retkey is set to 0.
565 * NOTES
566 * Unlike RegCreateKeyExA(), this function will not create the key if it
567 * does not exist.
569 LSTATUS WINAPI DECLSPEC_HOTPATCH RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
571 OBJECT_ATTRIBUTES attr;
572 STRING nameA;
573 NTSTATUS status;
575 if (retkey && (!name || !name[0]) &&
576 (HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) &&
577 (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
579 *retkey = hkey;
580 return ERROR_SUCCESS;
583 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
584 else
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;
595 attr.Attributes = 0;
596 attr.SecurityDescriptor = NULL;
597 attr.SecurityQualityOfService = NULL;
599 RtlInitAnsiString( &nameA, name );
600 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
601 &nameA, FALSE )))
603 status = open_key( retkey, options, access, &attr );
605 return RtlNtStatusToDosError( status );
609 /******************************************************************************
610 * RegOpenKeyW [ADVAPI32.@]
612 * See RegOpenKeyA.
614 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
616 if (!retkey)
617 return ERROR_INVALID_PARAMETER;
619 if (!name || !*name)
621 *retkey = hkey;
622 return ERROR_SUCCESS;
624 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
628 /******************************************************************************
629 * RegOpenKeyA [ADVAPI32.@]
631 * Open a registry key.
633 * PARAMS
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
638 * RETURNS
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 )
644 if (!retkey)
645 return ERROR_INVALID_PARAMETER;
647 if (!name || !*name)
649 *retkey = hkey;
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;
658 TOKEN_USER *info;
659 DWORD len = 0;
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);
666 heap_free(info);
668 return sidstring;
671 /******************************************************************************
672 * RegOpenCurrentUser [ADVAPI32.@]
674 * Get a handle to the HKEY_CURRENT_USER key for the user
675 * the current thread is impersonating.
677 * PARAMS
678 * access [I] Desired access rights to the key
679 * retkey [O] Handle to the opened key
681 * RETURNS
682 * Success: ERROR_SUCCESS
683 * Failure: nonzero error code from Winerror.h
685 * FIXME
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;
694 HANDLE threadtoken;
695 LSTATUS ret;
697 /* get current user SID */
698 if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &threadtoken))
700 sidstring = get_thread_token_user_sid(threadtoken);
701 CloseHandle(threadtoken);
704 if (!sidstring)
706 ImpersonateSelf(SecurityIdentification);
707 if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &threadtoken))
709 sidstring = get_thread_token_user_sid(threadtoken);
710 CloseHandle(threadtoken);
712 RevertToSelf();
715 if (sidstring)
717 ret = RegOpenKeyExW( HKEY_USERS, sidstring, 0, access, retkey );
718 LocalFree(sidstring);
720 else
721 ret = RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
723 return ret;
728 /******************************************************************************
729 * RegEnumKeyExW [ADVAPI32.@]
731 * Enumerate subkeys of the specified open registry key.
733 * PARAMS
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
743 * RETURNS
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 )
751 NTSTATUS status;
752 char buffer[256], *buf_ptr = buffer;
753 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
754 DWORD total_size;
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 );
776 if (!status)
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;
785 else
787 *name_len = len;
788 memcpy( name, info->Name, info->NameLength );
789 name[len] = 0;
790 if (class_len)
792 *class_len = cls_len;
793 if (class)
795 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
796 class[cls_len] = 0;
802 if (buf_ptr != buffer) heap_free( buf_ptr );
803 return RtlNtStatusToDosError( status );
807 /******************************************************************************
808 * RegEnumKeyExA [ADVAPI32.@]
810 * See RegEnumKeyExW.
812 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
813 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
815 NTSTATUS status;
816 char buffer[256], *buf_ptr = buffer;
817 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
818 DWORD total_size;
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 );
840 if (!status)
842 DWORD len, cls_len;
844 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
845 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
846 info->ClassLength );
847 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
849 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
850 status = STATUS_BUFFER_OVERFLOW;
851 else
853 *name_len = len;
854 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
855 name[len] = 0;
856 if (class_len)
858 *class_len = cls_len;
859 if (class)
861 RtlUnicodeToMultiByteN( class, cls_len, NULL,
862 (WCHAR *)(buf_ptr + info->ClassOffset),
863 info->ClassLength );
864 class[cls_len] = 0;
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.
880 * PARAMS
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.
886 * RETURNS
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.@]
900 * See RegEnumKeyW.
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.
913 * PARAMS
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
927 * RETURNS
928 * Success: ERROR_SUCCESS
929 * Failure: system error code.
931 * NOTES
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 )
942 NTSTATUS status;
943 char buffer[256], *buf_ptr = buffer;
944 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
945 DWORD total_size;
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;
974 else
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;
991 if (security)
993 FIXME( "security argument not supported.\n");
994 *security = 0;
997 done:
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.
1008 * PARAMS
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.
1015 * RETURNS
1016 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
1017 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
1018 * bytes.
1020 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
1021 LPSTR lpValueBuf, LPDWORD ldwTotsize )
1023 unsigned int i;
1024 DWORD maxBytes = *ldwTotsize;
1025 LSTATUS status;
1026 LPSTR bufptr = lpValueBuf;
1027 *ldwTotsize = 0;
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)
1038 return status;
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)
1047 return status;
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 )
1069 unsigned int i;
1070 DWORD maxBytes = *ldwTotsize;
1071 LSTATUS status;
1072 LPSTR bufptr = (LPSTR)lpValueBuf;
1073 *ldwTotsize = 0;
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)
1083 return status;
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)
1092 return status;
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.
1110 * PARAMS
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
1118 * class in TCHARS.
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.
1125 * RETURNS
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 )
1134 NTSTATUS status;
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;
1162 len = 0;
1163 if (class && class_len) len = *class_len;
1164 RtlUnicodeToMultiByteN( class, len, class_len,
1165 (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength );
1166 if (len)
1168 if (*class_len + 1 > len)
1170 status = STATUS_BUFFER_OVERFLOW;
1171 *class_len -= 1;
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;
1186 if (security)
1188 FIXME( "security argument not supported.\n");
1189 *security = 0;
1192 done:
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.
1212 * PARAMS
1213 * hkey [I] Handle of key to close
1215 * RETURNS
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 )
1232 DWORD ret;
1233 HKEY tmp;
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 ) );
1243 RegCloseKey( tmp );
1245 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
1246 return 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 )
1266 DWORD ret;
1267 HKEY tmp;
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 */
1278 CHAR sub[MAX_PATH];
1280 while(!RegEnumKeyA(tmp, 0, sub, sizeof(sub)))
1282 if(RegDeleteKeyExA(tmp, sub, access, reserved)) /* recurse */
1283 break;
1286 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1287 RegCloseKey( tmp );
1289 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1290 return ret;
1294 /******************************************************************************
1295 * RegDeleteKeyA [ADVAPI32.@]
1297 * Delete a registry key.
1299 * PARAMS
1300 * hkey [I] Handle to parent key containing the key to delete
1301 * name [I] Name of the key user hkey to delete
1303 * NOTES
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.
1308 * RETURNS
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.
1324 * PARAMS
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
1332 * RETURNS
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.
1364 * NOTES
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 )
1371 ANSI_STRING nameA;
1372 UNICODE_STRING nameW;
1373 WCHAR *dataW = NULL;
1374 NTSTATUS status;
1376 if (!is_version_nt()) /* win95 */
1378 if (type == REG_SZ)
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 */
1394 DWORD lenW;
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 );
1398 count = lenW;
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 );
1408 heap_free( dataW );
1409 return RtlNtStatusToDosError( status );
1413 /******************************************************************************
1414 * RegSetValueW [ADVAPI32.@]
1416 * Sets the data for the default or unnamed value of a reg key.
1418 * PARAMS
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.
1425 * RETURNS
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.@]
1441 * See RegSetValueW.
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;
1458 DWORD ret;
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;
1465 hkey = hsubkey;
1468 ret = RegSetValueExW( hkey, name, 0, type, (const BYTE*)data, len );
1469 if (hsubkey) RegCloseKey( hsubkey );
1470 return ret;
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;
1479 DWORD ret;
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;
1486 hkey = hsubkey;
1489 ret = RegSetValueExA( hkey, name, 0, type, (const BYTE*)data, len );
1490 if (hsubkey) RegCloseKey( hsubkey );
1491 return ret;
1494 struct perf_provider
1496 HMODULE perflib;
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)
1506 char buf[MAX_PATH];
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)
1512 return NULL;
1514 buf[len] = 0;
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;
1529 HKEY service, perf;
1531 err = RegOpenKeyExW(root, name, 0, KEY_READ, &service);
1532 if (err != ERROR_SUCCESS)
1533 return FALSE;
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));
1547 RegCloseKey(perf);
1550 err = RegOpenKeyExW(service, performanceW, 0, KEY_READ, &perf);
1551 RegCloseKey(service);
1552 if (err != ERROR_SUCCESS)
1553 return FALSE;
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))
1568 goto error;
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;
1575 strcpyW(buf, buf2);
1578 if (!(provider->perflib = LoadLibraryW(buf)))
1580 WARN("Failed to load %s\n", debugstr_w(buf));
1581 goto error;
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)
1592 RegCloseKey(perf);
1593 return TRUE;
1596 TRACE("Provider is missing required exports\n");
1597 FreeLibrary(provider->perflib);
1599 error:
1600 RegCloseKey(perf);
1601 return FALSE;
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;
1608 DWORD err;
1610 if (!query || !query[0])
1611 query = globalW;
1613 err = provider->pOpen(linkage);
1614 if (err != ERROR_SUCCESS)
1616 TRACE("Open(%s) error %u (%#x)\n", debugstr_w(linkage), err, err);
1617 return err;
1620 *obj_count = 0;
1621 err = provider->pCollect((WCHAR *)query, data, size, obj_count);
1622 if (err != ERROR_SUCCESS)
1624 TRACE("Collect error %u (%#x)\n", err, err);
1625 *obj_count = 0;
1628 provider->pClose();
1629 return 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;
1640 HKEY root;
1641 PERF_DATA_BLOCK *pdb;
1643 if (!ret_size)
1644 return ERROR_INVALID_PARAMETER;
1646 data_size = *ret_size;
1647 *ret_size = 0;
1649 if (type)
1650 *type = REG_BINARY;
1652 if (!data || data_size < sizeof(*pdb))
1653 return ERROR_MORE_DATA;
1655 pdb = 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;
1663 #else
1664 pdb->LittleEndian = TRUE;
1665 #endif
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);
1675 data = pdb + 1;
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)
1700 return err;
1702 i = 0;
1703 for (;;)
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;
1714 break;
1717 if (err != ERROR_SUCCESS)
1718 continue;
1720 if (!load_provider(root, name, &provider))
1721 continue;
1723 err = collect_data(&provider, query, &collected_data, &collected_size, &obj_count);
1724 FreeLibrary(provider.perflib);
1726 if (err == ERROR_MORE_DATA)
1727 break;
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;
1744 RegCloseKey(root);
1746 if (err == ERROR_SUCCESS)
1748 *ret_size = pdb->TotalByteLength;
1750 GetSystemTime(&pdb->SystemTime);
1751 GetSystemTimeAsFileTime((FILETIME *)&pdb->PerfTime100nSec);
1754 return err;
1757 /******************************************************************************
1758 * RegQueryValueExW [ADVAPI32.@]
1760 * See RegQueryValueExA.
1762 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1763 LPBYTE data, LPDWORD count )
1765 NTSTATUS status;
1766 UNICODE_STRING name_str;
1767 DWORD total_size;
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 );
1786 else
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;
1796 if (data)
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 );
1809 if (!status)
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;
1827 done:
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.
1838 * PARAMS
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
1846 * RETURNS
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.
1852 * NOTES
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 )
1859 NTSTATUS status;
1860 ANSI_STRING nameA;
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 );
1888 return ret;
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;
1906 goto done;
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))
1917 DWORD len;
1919 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1920 total_size - info_size );
1921 if (data && len)
1923 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1924 else
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;
1935 else if (data)
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;
1946 done:
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.
1958 * PARAMS
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
1962 * of the key.
1963 * count [I/O] Size of lpValue in bytes.
1965 * RETURNS
1966 * Success: ERROR_SUCCESS
1967 * Failure: nonzero error code from Winerror.h
1969 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1971 DWORD ret;
1972 HKEY subkey = hkey;
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;
1989 return ret;
1993 /******************************************************************************
1994 * RegQueryValueA [ADVAPI32.@]
1996 * See RegQueryValueW.
1998 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
2000 DWORD ret;
2001 HKEY subkey = hkey;
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;
2018 return ret;
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)
2033 DWORD dwMask = 0;
2035 switch (dwType)
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)
2051 DWORD cbExpect = 0;
2053 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
2054 cbExpect = 4;
2055 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
2056 cbExpect = 8;
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.
2073 * PARAMS
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'
2082 * for strings.
2084 * RETURNS
2085 * Success: ERROR_SUCCESS
2086 * Failure: nonzero error code from Winerror.h
2088 * NOTES
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,
2098 LPDWORD pcbData )
2100 DWORD dwType, cbData = pcbData ? *pcbData : 0;
2101 PVOID pvBuf = NULL;
2102 LONG ret;
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))
2128 do {
2129 heap_free(pvBuf);
2131 pvBuf = heap_alloc(cbData);
2132 if (!pvBuf)
2134 ret = ERROR_NOT_ENOUGH_MEMORY;
2135 break;
2138 if (ret == ERROR_MORE_DATA || !pvData)
2139 ret = RegQueryValueExW(hKey, pszValue, NULL,
2140 &dwType, pvBuf, &cbData);
2141 else
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);
2161 dwType = REG_SZ;
2162 if(pvData && pcbData && cbData > *pcbData)
2163 ret = ERROR_MORE_DATA;
2165 else if (pvData)
2166 CopyMemory(pvData, pvBuf, *pcbData);
2169 heap_free(pvBuf);
2172 if (pszSubKey && pszSubKey[0])
2173 RegCloseKey(hKey);
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;
2183 return ret;
2187 /******************************************************************************
2188 * RegGetValueA [ADVAPI32.@]
2190 * See RegGetValueW.
2192 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
2193 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
2194 LPDWORD pcbData )
2196 DWORD dwType, cbData = pcbData ? *pcbData : 0;
2197 PVOID pvBuf = NULL;
2198 LONG ret;
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))
2224 do {
2225 heap_free(pvBuf);
2227 pvBuf = heap_alloc(cbData);
2228 if (!pvBuf)
2230 ret = ERROR_NOT_ENOUGH_MEMORY;
2231 break;
2234 if (ret == ERROR_MORE_DATA || !pvData)
2235 ret = RegQueryValueExA(hKey, pszValue, NULL,
2236 &dwType, pvBuf, &cbData);
2237 else
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);
2257 dwType = REG_SZ;
2258 if(pvData && pcbData && cbData > *pcbData)
2259 ret = ERROR_MORE_DATA;
2261 else if (pvData)
2262 CopyMemory(pvData, pvBuf, *pcbData);
2265 heap_free(pvBuf);
2268 if (pszSubKey && pszSubKey[0])
2269 RegCloseKey(hKey);
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;
2279 return ret;
2283 /******************************************************************************
2284 * RegEnumValueW [ADVAPI32.@]
2286 * Enumerates the values for the specified open registry key.
2288 * PARAMS
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)
2298 * RETURNS
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 )
2306 NTSTATUS status;
2307 DWORD total_size;
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;
2342 goto overflow;
2344 memcpy( value, info->Name, info->NameLength );
2345 *val_count = info->NameLength / sizeof(WCHAR);
2346 value[*val_count] = 0;
2348 if (data)
2350 if (total_size - info->DataOffset > *count)
2352 status = STATUS_BUFFER_OVERFLOW;
2353 goto 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;
2365 overflow:
2366 if (type) *type = info->Type;
2367 if (count) *count = info->DataLength;
2369 done:
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 )
2383 NTSTATUS status;
2384 DWORD total_size;
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))
2421 DWORD len;
2422 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
2423 total_size - info->DataOffset );
2424 if (data && len)
2426 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
2427 else
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;
2438 else if (data)
2440 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
2441 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2444 if (!status)
2446 DWORD len;
2448 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2449 if (len >= *val_count)
2451 status = STATUS_BUFFER_OVERFLOW;
2452 if (*val_count)
2454 len = *val_count - 1;
2455 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2456 value[len] = 0;
2459 else
2461 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2462 value[len] = 0;
2463 *val_count = len;
2467 if (type) *type = info->Type;
2468 if (count) *count = info->DataLength;
2470 done:
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.
2490 * PARAMS
2491 * hkey [I] Registry handle of the key holding the value
2492 * name [I] Name of the value under hkey to delete
2494 * RETURNS
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;
2509 HKEY hsubkey = 0;
2510 LONG ret;
2512 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2514 if (subkey)
2516 if ((ret = RegOpenKeyExW( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey )))
2517 return ret;
2518 hkey = hsubkey;
2521 RtlInitUnicodeString( &nameW, name );
2522 ret = RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2523 if (hsubkey) RegCloseKey( hsubkey );
2524 return ret;
2527 /******************************************************************************
2528 * RegDeleteKeyValueA [ADVAPI32.@]
2530 LONG WINAPI RegDeleteKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name )
2532 UNICODE_STRING nameW;
2533 HKEY hsubkey = 0;
2534 ANSI_STRING nameA;
2535 NTSTATUS status;
2537 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2539 if (subkey)
2541 LONG ret = RegOpenKeyExA( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey );
2542 if (ret)
2543 return ret;
2544 hkey = 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.
2564 * PARAMS
2565 * hkey [I] Handle of open key
2566 * subkey [I] Address of name of subkey
2567 * filename [I] Address of filename for registry information
2569 * RETURNS
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;
2577 NTSTATUS status;
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.@]
2606 * See RegLoadKeyW.
2608 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2610 UNICODE_STRING subkeyW, filenameW;
2611 STRING subkeyA, filenameA;
2612 NTSTATUS status;
2613 LONG ret;
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);
2628 return ret;
2632 /******************************************************************************
2633 * RegSaveKeyW [ADVAPI32.@]
2635 * Save a key and all of its subkeys and values to a new file in the standard format.
2637 * PARAMS
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
2642 * RETURNS
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];
2651 int count = 0;
2652 LPWSTR nameW;
2653 DWORD ret, err;
2654 HANDLE handle;
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 );
2664 for (;;)
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 */
2673 if (count >= 100)
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 );
2680 if (!ret)
2682 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2684 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2685 debugstr_w(file) );
2686 ret = GetLastError();
2689 if (ret) DeleteFileW( buffer );
2691 done:
2692 SetLastError( err ); /* restore last error code */
2693 return ret;
2697 /******************************************************************************
2698 * RegSaveKeyA [ADVAPI32.@]
2700 * See RegSaveKeyW.
2702 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2704 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2705 NTSTATUS status;
2706 STRING fileA;
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.
2739 * PARAMS
2740 * hkey [I] Handle of key where restore begins
2741 * lpFile [I] Address of filename containing saved tree
2742 * dwFlags [I] Optional flags
2744 * RETURNS
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;
2772 LONG ret;
2774 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2775 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2776 RtlFreeUnicodeString( &lpFileW );
2777 return ret;
2781 /******************************************************************************
2782 * RegUnLoadKeyW [ADVAPI32.@]
2784 * Unload a registry key and its subkeys from the registry.
2786 * PARAMS
2787 * hkey [I] Handle of open key
2788 * lpSubKey [I] Address of name of subkey to unload
2790 * RETURNS
2791 * Success: ERROR_SUCCESS
2792 * Failure: nonzero error code from Winerror.h
2794 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2796 DWORD ret;
2797 HKEY shkey;
2798 OBJECT_ATTRIBUTES attr;
2799 UNICODE_STRING subkey;
2801 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2803 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2804 if( ret )
2805 return ERROR_INVALID_PARAMETER;
2807 RtlInitUnicodeString(&subkey, lpSubKey);
2808 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2809 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2811 RegCloseKey(shkey);
2813 return ret;
2817 /******************************************************************************
2818 * RegUnLoadKeyA [ADVAPI32.@]
2820 * See RegUnLoadKeyW.
2822 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2824 UNICODE_STRING lpSubKeyW;
2825 LONG ret;
2827 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2828 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2829 RtlFreeUnicodeString( &lpSubKeyW );
2830 return ret;
2834 /******************************************************************************
2835 * RegReplaceKeyW [ADVAPI32.@]
2837 * Replace the file backing a registry key and all its subkeys with another file.
2839 * PARAMS
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
2845 * RETURNS
2846 * Success: ERROR_SUCCESS
2847 * Failure: nonzero error code from Winerror.h
2849 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2850 LPCWSTR lpOldFile )
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,
2864 LPCSTR lpOldFile )
2866 UNICODE_STRING lpSubKeyW;
2867 UNICODE_STRING lpNewFileW;
2868 UNICODE_STRING lpOldFileW;
2869 LONG ret;
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 );
2878 return ret;
2882 /******************************************************************************
2883 * RegSetKeySecurity [ADVAPI32.@]
2885 * Set the security of an open registry key.
2887 * PARAMS
2888 * hkey [I] Open handle of key to set
2889 * SecurityInfo [I] Descriptor contents
2890 * pSecurityDesc [I] Address of descriptor for key
2892 * RETURNS
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)) {
2906 /* Param OK */
2907 } else
2908 return ERROR_INVALID_PARAMETER;
2910 if (!pSecurityDesc)
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.
2924 * PARAMS
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
2930 * RETURNS
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.
2954 * PARAMS
2955 * hkey [I] Handle of key to write
2957 * RETURNS
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.
2975 * PARAMS
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
2980 * RETURNS
2981 * Success: ERROR_SUCCESS
2982 * Failure: nonzero error code from Winerror.h
2984 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2985 PHKEY phkResult )
2987 LONG ret;
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 );
2995 else {
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] == '\\')
3001 lpMachineName += 2;
3002 if (GetComputerNameW(compName, &len))
3004 if (!strcmpiW(lpMachineName, compName))
3005 ret = RegOpenKeyW(hKey, NULL, phkResult);
3006 else
3008 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
3009 ret = ERROR_BAD_NETPATH;
3012 else
3013 ret = GetLastError();
3015 return ret;
3019 /******************************************************************************
3020 * RegConnectRegistryA [ADVAPI32.@]
3022 * See RegConnectRegistryW.
3024 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
3026 UNICODE_STRING machineW;
3027 LONG ret;
3029 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
3030 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
3031 RtlFreeUnicodeString( &machineW );
3032 return ret;
3036 /******************************************************************************
3037 * RegNotifyChangeKeyValue [ADVAPI32.@]
3039 * Notify the caller about changes to the attributes or contents of a registry key.
3041 * PARAMS
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
3048 * RETURNS
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,
3054 BOOL fAsync )
3056 NTSTATUS status;
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,
3063 hEvent, fAsync);
3065 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
3066 fdwNotifyFilter, fWatchSubTree, NULL, 0,
3067 fAsync);
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.
3080 * PARAMS
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
3086 * RETURNS
3087 * Success: ERROR_SUCCESS
3088 * Failure: nonzero error code from Winerror.h
3090 * NOTES
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(
3096 HANDLE hToken,
3097 DWORD dwOptions,
3098 REGSAM samDesired,
3099 PHKEY phkResult
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
3113 * RegLoadMUIString.
3115 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
3117 HGLOBAL hMemory;
3118 HRSRC hResource;
3119 WCHAR *pString;
3120 int idxString;
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';
3147 return cMaxChars;
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
3157 * PARAMS
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.
3166 * RETURNS
3167 * Success: ERROR_SUCCESS,
3168 * Failure: nonzero error code from winerror.h
3170 * NOTES
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;
3179 LONG result;
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;
3199 goto cleanup;
3201 pwszTempBuffer = heap_alloc(cbData);
3202 if (!pwszTempBuffer) {
3203 result = ERROR_NOT_ENOUGH_MEMORY;
3204 goto cleanup;
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;
3216 goto cleanup;
3218 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
3219 } else {
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));
3229 } else {
3230 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
3231 UINT uiStringId;
3232 HMODULE hModule;
3234 /* Format of the expanded value is 'path_to_dll,-resId' */
3235 if (!pComma || pComma[1] != '-') {
3236 result = ERROR_BADKEY;
3237 goto cleanup;
3240 uiStringId = atoiW(pComma+2);
3241 *pComma = '\0';
3243 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
3244 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
3245 result = ERROR_BADKEY;
3246 FreeLibrary(hModule);
3249 cleanup:
3250 heap_free(pwszTempBuffer);
3251 heap_free(pwszExpandedBuffer);
3252 return result;
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;
3264 WCHAR *pwszBuffer;
3265 DWORD cbData = cbBuffer * sizeof(WCHAR);
3266 LONG result;
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;
3274 goto cleanup;
3277 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
3278 baseDirW.Buffer);
3280 if (result == ERROR_SUCCESS) {
3281 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
3282 if (pcbData)
3283 *pcbData = cbData;
3286 cleanup:
3287 heap_free(pwszBuffer);
3288 RtlFreeUnicodeString(&baseDirW);
3289 RtlFreeUnicodeString(&valueW);
3291 return result;
3294 /******************************************************************************
3295 * RegDisablePredefinedCache [ADVAPI32.@]
3297 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
3299 * PARAMS
3300 * None.
3302 * RETURNS
3303 * Success: ERROR_SUCCESS
3304 * Failure: nonzero error code from Winerror.h
3306 * NOTES
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;
3335 LONG ret;
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 );
3347 if (ret)
3348 goto cleanup;
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;
3354 goto cleanup;
3357 /* Recursively delete subkeys */
3358 for (;;)
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 );
3372 goto cleanup;
3375 /* Delete values */
3376 for (;;)
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;
3388 cleanup:
3389 heap_free( name_buf );
3390 if (subkey && *subkey)
3391 RegCloseKey( hkey );
3392 return ret;
3396 /******************************************************************************
3397 * RegDeleteTreeA [ADVAPI32.@]
3400 LSTATUS WINAPI RegDeleteTreeA( HKEY hkey, const char *subkey )
3402 UNICODE_STRING subkeyW;
3403 LONG ret;
3405 if (subkey) RtlCreateUnicodeStringFromAsciiz( &subkeyW, subkey );
3406 else subkeyW.Buffer = NULL;
3407 ret = RegDeleteTreeW( hkey, subkeyW.Buffer );
3408 RtlFreeUnicodeString( &subkeyW );
3409 return ret;
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;
3424 HKEY hkey;
3425 LONG ret;
3427 TRACE( "(%p, %s, %p)\n", hsrc, debugstr_w(subkey), hdst );
3429 if (subkey)
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 );
3437 if (ret)
3438 goto cleanup;
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;
3444 goto cleanup;
3447 if (!(value_buf = heap_alloc( max_value )))
3449 ret = ERROR_NOT_ENOUGH_MEMORY;
3450 goto cleanup;
3453 /* Copy values */
3454 for (i = 0;; i++)
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 */
3466 for (i = 0;; i++)
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;
3481 cleanup:
3482 heap_free( name_buf );
3483 heap_free( value_buf );
3484 if (subkey)
3485 RegCloseKey( hsrc );
3486 return ret;
3490 /******************************************************************************
3491 * RegCopyTreeA [ADVAPI32.@]
3494 LONG WINAPI RegCopyTreeA( HKEY hsrc, const char *subkey, HKEY hdst )
3496 UNICODE_STRING subkeyW;
3497 LONG ret;
3499 if (subkey) RtlCreateUnicodeStringFromAsciiz( &subkeyW, subkey );
3500 else subkeyW.Buffer = NULL;
3501 ret = RegCopyTreeW( hsrc, subkeyW.Buffer, hdst );
3502 RtlFreeUnicodeString( &subkeyW );
3503 return ret;
3507 /******************************************************************************
3508 * RegDisableReflectionKey [ADVAPI32.@]
3511 LONG WINAPI RegDisableReflectionKey(HKEY base)
3513 FIXME("%p: stub\n", base);
3514 return ERROR_SUCCESS;