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