advapi32: Added FIXME about an unsupported argument and initialize its value.
[wine/multimedia.git] / dlls / advapi32 / registry.c
blob8d97af95e9fa0549d721663d9216ba90914ed7bd
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 {'M','a','c','h','i','n','e','\\',
52 'S','o','f','t','w','a','r','e','\\',
53 'C','l','a','s','s','e','s',0};
54 static const WCHAR name_LOCAL_MACHINE[] =
55 {'M','a','c','h','i','n','e',0};
56 static const WCHAR name_USERS[] =
57 {'U','s','e','r',0};
58 static const WCHAR name_PERFORMANCE_DATA[] =
59 {'P','e','r','f','D','a','t','a',0};
60 static const WCHAR name_CURRENT_CONFIG[] =
61 {'M','a','c','h','i','n','e','\\',
62 'S','y','s','t','e','m','\\',
63 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
64 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
65 'C','u','r','r','e','n','t',0};
66 static const WCHAR name_DYN_DATA[] =
67 {'D','y','n','D','a','t','a',0};
69 static const WCHAR * const root_key_names[] =
71 name_CLASSES_ROOT,
72 NULL, /* HKEY_CURRENT_USER is determined dynamically */
73 name_LOCAL_MACHINE,
74 name_USERS,
75 name_PERFORMANCE_DATA,
76 name_CURRENT_CONFIG,
77 name_DYN_DATA
80 #define NB_SPECIAL_ROOT_KEYS (sizeof(root_key_names)/sizeof(root_key_names[0]))
82 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
83 static BOOL hkcu_cache_disabled;
85 static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
87 /* check if value type needs string conversion (Ansi<->Unicode) */
88 static inline BOOL is_string( DWORD type )
90 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
93 /* check if current version is NT or Win95 */
94 static inline BOOL is_version_nt(void)
96 return !(GetVersion() & 0x80000000);
99 static BOOL is_wow6432node( const UNICODE_STRING *name )
101 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e'};
103 return (name->Length == sizeof(wow6432nodeW) &&
104 !memicmpW( name->Buffer, wow6432nodeW, sizeof(wow6432nodeW)/sizeof(WCHAR) ));
107 /* open the Wow6432Node subkey of the specified key */
108 static HANDLE open_wow6432node( HANDLE key )
110 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
111 OBJECT_ATTRIBUTES attr;
112 UNICODE_STRING nameW;
113 HANDLE ret;
115 attr.Length = sizeof(attr);
116 attr.RootDirectory = key;
117 attr.ObjectName = &nameW;
118 attr.Attributes = 0;
119 attr.SecurityDescriptor = NULL;
120 attr.SecurityQualityOfService = NULL;
121 RtlInitUnicodeString( &nameW, wow6432nodeW );
122 if (NtOpenKey( &ret, MAXIMUM_ALLOWED, &attr )) ret = 0;
123 return ret;
126 /* wrapper for NtCreateKey that creates the key recursively if necessary */
127 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
128 const UNICODE_STRING *class, ULONG options, PULONG dispos )
130 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
131 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
132 HANDLE subkey, root = attr->RootDirectory;
134 if (!force_wow32) status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos );
136 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
138 WCHAR *buffer = attr->ObjectName->Buffer;
139 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
140 UNICODE_STRING str;
142 while (i < len && buffer[i] != '\\') i++;
143 if (i == len && !force_wow32) return status;
145 attrs = attr->Attributes;
146 attr->ObjectName = &str;
148 for (;;)
150 str.Buffer = buffer + pos;
151 str.Length = (i - pos) * sizeof(WCHAR);
152 if (force_wow32 && pos)
154 if (is_wow6432node( &str )) force_wow32 = FALSE;
155 else if ((subkey = open_wow6432node( attr->RootDirectory )))
157 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
158 attr->RootDirectory = subkey;
159 force_wow32 = FALSE;
162 if (i == len)
164 attr->Attributes = attrs;
165 status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos );
167 else
169 attr->Attributes = attrs & ~OBJ_OPENLINK;
170 status = NtCreateKey( &subkey, access, attr, 0, class,
171 options & ~REG_OPTION_CREATE_LINK, dispos );
173 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
174 if (status) return status;
175 if (i == len) break;
176 attr->RootDirectory = subkey;
177 while (i < len && buffer[i] == '\\') i++;
178 pos = i;
179 while (i < len && buffer[i] != '\\') i++;
182 attr->RootDirectory = subkey;
183 if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory )))
185 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
186 attr->RootDirectory = subkey;
188 *retkey = attr->RootDirectory;
189 return status;
192 /* wrapper for NtOpenKey to handle Wow6432 nodes */
193 static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
195 NTSTATUS status;
196 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
197 HANDLE subkey, root = attr->RootDirectory;
198 WCHAR *buffer = attr->ObjectName->Buffer;
199 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
200 UNICODE_STRING str;
202 if (!force_wow32) return NtOpenKey( (HANDLE *)retkey, access, attr );
204 if (len && buffer[0] == '\\') return STATUS_OBJECT_PATH_INVALID;
205 while (i < len && buffer[i] != '\\') i++;
206 attrs = attr->Attributes;
207 attr->ObjectName = &str;
209 for (;;)
211 str.Buffer = buffer + pos;
212 str.Length = (i - pos) * sizeof(WCHAR);
213 if (force_wow32 && pos)
215 if (is_wow6432node( &str )) force_wow32 = FALSE;
216 else if ((subkey = open_wow6432node( attr->RootDirectory )))
218 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
219 attr->RootDirectory = subkey;
220 force_wow32 = FALSE;
223 if (i == len)
225 attr->Attributes = attrs;
226 status = NtOpenKey( &subkey, access, attr );
228 else
230 attr->Attributes = attrs & ~OBJ_OPENLINK;
231 status = NtOpenKey( &subkey, access, attr );
233 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
234 if (status) return status;
235 attr->RootDirectory = subkey;
236 if (i == len) break;
237 while (i < len && buffer[i] == '\\') i++;
238 pos = i;
239 while (i < len && buffer[i] != '\\') i++;
241 if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory )))
243 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
244 attr->RootDirectory = subkey;
246 *retkey = attr->RootDirectory;
247 return status;
250 /* create one of the HKEY_* special root keys */
251 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
253 HKEY ret = 0;
254 int idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
256 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CURRENT_USER))
258 if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
259 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
261 /* don't cache the key in the table if caching is disabled */
262 if (hkcu_cache_disabled)
263 return hkey;
265 else
267 OBJECT_ATTRIBUTES attr;
268 UNICODE_STRING name;
270 attr.Length = sizeof(attr);
271 attr.RootDirectory = 0;
272 attr.ObjectName = &name;
273 attr.Attributes = 0;
274 attr.SecurityDescriptor = NULL;
275 attr.SecurityQualityOfService = NULL;
276 RtlInitUnicodeString( &name, root_key_names[idx] );
277 if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0;
278 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
281 if (!(access & (KEY_WOW64_64KEY | KEY_WOW64_32KEY)))
283 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
284 ret = hkey;
285 else
286 NtClose( hkey ); /* somebody beat us to it */
288 else
289 ret = hkey;
290 return ret;
293 /* map the hkey from special root to normal key if necessary */
294 static inline HKEY get_special_root_hkey( HKEY hkey, REGSAM access )
296 HKEY ret = hkey;
298 if ((HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST))
299 && (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
301 REGSAM mask = 0;
303 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT))
304 mask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
306 if ((access & mask) ||
307 !(ret = special_root_keys[HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)]))
308 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED | (access & mask) );
310 return ret;
314 /******************************************************************************
315 * RegOverridePredefKey [ADVAPI32.@]
317 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
319 HKEY old_key;
320 int idx;
322 TRACE("(%p %p)\n", hkey, override);
324 if ((HandleToUlong(hkey) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST))
325 || (HandleToUlong(hkey) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
326 return ERROR_INVALID_PARAMETER;
327 idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
329 if (override)
331 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
332 GetCurrentProcess(), (HANDLE *)&override,
333 0, 0, DUPLICATE_SAME_ACCESS );
334 if (status) return RtlNtStatusToDosError( status );
337 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
338 if (old_key) NtClose( old_key );
339 return ERROR_SUCCESS;
343 /******************************************************************************
344 * RegCreateKeyExW [ADVAPI32.@]
346 * See RegCreateKeyExA.
348 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
349 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
350 PHKEY retkey, LPDWORD dispos )
352 OBJECT_ATTRIBUTES attr;
353 UNICODE_STRING nameW, classW;
355 if (reserved) return ERROR_INVALID_PARAMETER;
356 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
358 attr.Length = sizeof(attr);
359 attr.RootDirectory = hkey;
360 attr.ObjectName = &nameW;
361 attr.Attributes = 0;
362 attr.SecurityDescriptor = NULL;
363 attr.SecurityQualityOfService = NULL;
364 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
365 RtlInitUnicodeString( &nameW, name );
366 RtlInitUnicodeString( &classW, class );
368 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
372 /******************************************************************************
373 * RegCreateKeyExA [ADVAPI32.@]
375 * Open a registry key, creating it if it doesn't exist.
377 * PARAMS
378 * hkey [I] Handle of the parent registry key
379 * name [I] Name of the new key to open or create
380 * reserved [I] Reserved, pass 0
381 * class [I] The object type of the new key
382 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
383 * access [I] Access level desired
384 * sa [I] Security attributes for the key
385 * retkey [O] Destination for the resulting handle
386 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
388 * RETURNS
389 * Success: ERROR_SUCCESS.
390 * Failure: A standard Win32 error code. retkey remains untouched.
392 * FIXME
393 * MAXIMUM_ALLOWED in access mask not supported by server
395 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
396 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
397 PHKEY retkey, LPDWORD dispos )
399 OBJECT_ATTRIBUTES attr;
400 UNICODE_STRING classW;
401 ANSI_STRING nameA, classA;
402 NTSTATUS status;
404 if (reserved) return ERROR_INVALID_PARAMETER;
405 if (!is_version_nt())
407 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
408 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
410 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
412 attr.Length = sizeof(attr);
413 attr.RootDirectory = hkey;
414 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
415 attr.Attributes = 0;
416 attr.SecurityDescriptor = NULL;
417 attr.SecurityQualityOfService = NULL;
418 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
419 RtlInitAnsiString( &nameA, name );
420 RtlInitAnsiString( &classA, class );
422 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
423 &nameA, FALSE )))
425 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
427 status = create_key( retkey, access, &attr, &classW, options, dispos );
428 RtlFreeUnicodeString( &classW );
431 return RtlNtStatusToDosError( status );
435 /******************************************************************************
436 * RegCreateKeyW [ADVAPI32.@]
438 * Creates the specified reg key.
440 * PARAMS
441 * hKey [I] Handle to an open key.
442 * lpSubKey [I] Name of a key that will be opened or created.
443 * phkResult [O] Receives a handle to the opened or created key.
445 * RETURNS
446 * Success: ERROR_SUCCESS
447 * Failure: nonzero error code defined in Winerror.h
449 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
451 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
452 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
453 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
454 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
458 /******************************************************************************
459 * RegCreateKeyA [ADVAPI32.@]
461 * See RegCreateKeyW.
463 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
465 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
466 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
471 /******************************************************************************
472 * RegOpenKeyExW [ADVAPI32.@]
474 * See RegOpenKeyExA.
476 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
478 OBJECT_ATTRIBUTES attr;
479 UNICODE_STRING nameW;
481 if (retkey && (!name || !name[0]) &&
482 (HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) &&
483 (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
485 *retkey = hkey;
486 return ERROR_SUCCESS;
489 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
490 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++;
492 if (!retkey) return ERROR_INVALID_PARAMETER;
493 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
495 attr.Length = sizeof(attr);
496 attr.RootDirectory = hkey;
497 attr.ObjectName = &nameW;
498 attr.Attributes = 0;
499 attr.SecurityDescriptor = NULL;
500 attr.SecurityQualityOfService = NULL;
501 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
502 RtlInitUnicodeString( &nameW, name );
503 return RtlNtStatusToDosError( open_key( retkey, access, &attr ) );
507 /******************************************************************************
508 * RegOpenKeyExA [ADVAPI32.@]
510 * Open a registry key.
512 * PARAMS
513 * hkey [I] Handle of open key
514 * name [I] Name of subkey to open
515 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
516 * access [I] Security access mask
517 * retkey [O] Handle to open key
519 * RETURNS
520 * Success: ERROR_SUCCESS
521 * Failure: A standard Win32 error code. retkey is set to 0.
523 * NOTES
524 * Unlike RegCreateKeyExA(), this function will not create the key if it
525 * does not exist.
527 LSTATUS WINAPI DECLSPEC_HOTPATCH RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
529 OBJECT_ATTRIBUTES attr;
530 STRING nameA;
531 NTSTATUS status;
533 if (retkey && (!name || !name[0]) &&
534 (HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)) &&
535 (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
537 *retkey = hkey;
538 return ERROR_SUCCESS;
541 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
542 else
544 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
545 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++;
548 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
550 attr.Length = sizeof(attr);
551 attr.RootDirectory = hkey;
552 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
553 attr.Attributes = 0;
554 attr.SecurityDescriptor = NULL;
555 attr.SecurityQualityOfService = NULL;
556 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
558 RtlInitAnsiString( &nameA, name );
559 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
560 &nameA, FALSE )))
562 status = open_key( retkey, access, &attr );
564 return RtlNtStatusToDosError( status );
568 /******************************************************************************
569 * RegOpenKeyW [ADVAPI32.@]
571 * See RegOpenKeyA.
573 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
575 if (!retkey)
576 return ERROR_INVALID_PARAMETER;
578 if (!name || !*name)
580 *retkey = hkey;
581 return ERROR_SUCCESS;
583 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
587 /******************************************************************************
588 * RegOpenKeyA [ADVAPI32.@]
590 * Open a registry key.
592 * PARAMS
593 * hkey [I] Handle of parent key to open the new key under
594 * name [I] Name of the key under hkey to open
595 * retkey [O] Destination for the resulting Handle
597 * RETURNS
598 * Success: ERROR_SUCCESS
599 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
601 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
603 if (!retkey)
604 return ERROR_INVALID_PARAMETER;
606 if (!name || !*name)
608 *retkey = hkey;
609 return ERROR_SUCCESS;
611 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
615 /******************************************************************************
616 * RegOpenCurrentUser [ADVAPI32.@]
618 * Get a handle to the HKEY_CURRENT_USER key for the user
619 * the current thread is impersonating.
621 * PARAMS
622 * access [I] Desired access rights to the key
623 * retkey [O] Handle to the opened key
625 * RETURNS
626 * Success: ERROR_SUCCESS
627 * Failure: nonzero error code from Winerror.h
629 * FIXME
630 * This function is supposed to retrieve a handle to the
631 * HKEY_CURRENT_USER for the user the current thread is impersonating.
632 * Since Wine does not currently allow threads to impersonate other users,
633 * this stub should work fine.
635 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
637 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
642 /******************************************************************************
643 * RegEnumKeyExW [ADVAPI32.@]
645 * Enumerate subkeys of the specified open registry key.
647 * PARAMS
648 * hkey [I] Handle to key to enumerate
649 * index [I] Index of subkey to enumerate
650 * name [O] Buffer for subkey name
651 * name_len [O] Size of subkey buffer
652 * reserved [I] Reserved
653 * class [O] Buffer for class string
654 * class_len [O] Size of class buffer
655 * ft [O] Time key last written to
657 * RETURNS
658 * Success: ERROR_SUCCESS
659 * Failure: System error code. If there are no more subkeys available, the
660 * function returns ERROR_NO_MORE_ITEMS.
662 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
663 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
665 NTSTATUS status;
666 char buffer[256], *buf_ptr = buffer;
667 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
668 DWORD total_size;
670 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
671 name_len ? *name_len : 0, reserved, class, class_len, ft );
673 if (reserved) return ERROR_INVALID_PARAMETER;
674 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
676 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
677 buffer, sizeof(buffer), &total_size );
679 while (status == STATUS_BUFFER_OVERFLOW)
681 /* retry with a dynamically allocated buffer */
682 if (buf_ptr != buffer) heap_free( buf_ptr );
683 if (!(buf_ptr = heap_alloc( total_size )))
684 return ERROR_NOT_ENOUGH_MEMORY;
685 info = (KEY_NODE_INFORMATION *)buf_ptr;
686 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
687 buf_ptr, total_size, &total_size );
690 if (!status)
692 DWORD len = info->NameLength / sizeof(WCHAR);
693 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
695 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
697 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
698 status = STATUS_BUFFER_OVERFLOW;
699 else
701 *name_len = len;
702 memcpy( name, info->Name, info->NameLength );
703 name[len] = 0;
704 if (class_len)
706 *class_len = cls_len;
707 if (class)
709 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
710 class[cls_len] = 0;
716 if (buf_ptr != buffer) heap_free( buf_ptr );
717 return RtlNtStatusToDosError( status );
721 /******************************************************************************
722 * RegEnumKeyExA [ADVAPI32.@]
724 * See RegEnumKeyExW.
726 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
727 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
729 NTSTATUS status;
730 char buffer[256], *buf_ptr = buffer;
731 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
732 DWORD total_size;
734 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
735 name_len ? *name_len : 0, reserved, class, class_len, ft );
737 if (reserved) return ERROR_INVALID_PARAMETER;
738 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
740 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
741 buffer, sizeof(buffer), &total_size );
743 while (status == STATUS_BUFFER_OVERFLOW)
745 /* retry with a dynamically allocated buffer */
746 if (buf_ptr != buffer) heap_free( buf_ptr );
747 if (!(buf_ptr = heap_alloc( total_size )))
748 return ERROR_NOT_ENOUGH_MEMORY;
749 info = (KEY_NODE_INFORMATION *)buf_ptr;
750 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
751 buf_ptr, total_size, &total_size );
754 if (!status)
756 DWORD len, cls_len;
758 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
759 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
760 info->ClassLength );
761 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
763 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
764 status = STATUS_BUFFER_OVERFLOW;
765 else
767 *name_len = len;
768 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
769 name[len] = 0;
770 if (class_len)
772 *class_len = cls_len;
773 if (class)
775 RtlUnicodeToMultiByteN( class, cls_len, NULL,
776 (WCHAR *)(buf_ptr + info->ClassOffset),
777 info->ClassLength );
778 class[cls_len] = 0;
784 if (buf_ptr != buffer) heap_free( buf_ptr );
785 return RtlNtStatusToDosError( status );
789 /******************************************************************************
790 * RegEnumKeyW [ADVAPI32.@]
792 * Enumerates subkeys of the specified open reg key.
794 * PARAMS
795 * hKey [I] Handle to an open key.
796 * dwIndex [I] Index of the subkey of hKey to retrieve.
797 * lpName [O] Name of the subkey.
798 * cchName [I] Size of lpName in TCHARS.
800 * RETURNS
801 * Success: ERROR_SUCCESS
802 * Failure: system error code. If there are no more subkeys available, the
803 * function returns ERROR_NO_MORE_ITEMS.
805 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
807 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
811 /******************************************************************************
812 * RegEnumKeyA [ADVAPI32.@]
814 * See RegEnumKeyW.
816 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
818 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
822 /******************************************************************************
823 * RegQueryInfoKeyW [ADVAPI32.@]
825 * Retrieves information about the specified registry key.
827 * PARAMS
828 * hkey [I] Handle to key to query
829 * class [O] Buffer for class string
830 * class_len [O] Size of class string buffer
831 * reserved [I] Reserved
832 * subkeys [O] Buffer for number of subkeys
833 * max_subkey [O] Buffer for longest subkey name length
834 * max_class [O] Buffer for longest class string length
835 * values [O] Buffer for number of value entries
836 * max_value [O] Buffer for longest value name length
837 * max_data [O] Buffer for longest value data length
838 * security [O] Buffer for security descriptor length
839 * modif [O] Modification time
841 * RETURNS
842 * Success: ERROR_SUCCESS
843 * Failure: system error code.
845 * NOTES
846 * - win95 allows class to be valid and class_len to be NULL
847 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
848 * - both allow class to be NULL and class_len to be NULL
849 * (it's hard to test validity, so test !NULL instead)
851 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
852 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
853 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
854 LPDWORD security, FILETIME *modif )
856 NTSTATUS status;
857 char buffer[256], *buf_ptr = buffer;
858 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
859 DWORD total_size;
861 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
862 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
864 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
865 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
867 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
868 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
870 if (class && class_len && *class_len)
872 /* retry with a dynamically allocated buffer */
873 while (status == STATUS_BUFFER_OVERFLOW)
875 if (buf_ptr != buffer) heap_free( buf_ptr );
876 if (!(buf_ptr = heap_alloc( total_size )))
877 return ERROR_NOT_ENOUGH_MEMORY;
878 info = (KEY_FULL_INFORMATION *)buf_ptr;
879 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
882 if (status) goto done;
884 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
886 status = STATUS_BUFFER_TOO_SMALL;
888 else
890 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
891 class[info->ClassLength/sizeof(WCHAR)] = 0;
894 else status = STATUS_SUCCESS;
896 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
897 if (subkeys) *subkeys = info->SubKeys;
898 if (max_subkey) *max_subkey = info->MaxNameLen;
899 if (max_class) *max_class = info->MaxClassLen;
900 if (values) *values = info->Values;
901 if (max_value) *max_value = info->MaxValueNameLen;
902 if (max_data) *max_data = info->MaxValueDataLen;
903 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
905 if (security)
907 FIXME( "security argument not supported.\n");
908 *security = 0;
911 done:
912 if (buf_ptr != buffer) heap_free( buf_ptr );
913 return RtlNtStatusToDosError( status );
917 /******************************************************************************
918 * RegQueryMultipleValuesA [ADVAPI32.@]
920 * Retrieves the type and data for a list of value names associated with a key.
922 * PARAMS
923 * hKey [I] Handle to an open key.
924 * val_list [O] Array of VALENT structures that describes the entries.
925 * num_vals [I] Number of elements in val_list.
926 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
927 * ldwTotsize [I/O] Size of lpValueBuf.
929 * RETURNS
930 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
931 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
932 * bytes.
934 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
935 LPSTR lpValueBuf, LPDWORD ldwTotsize )
937 unsigned int i;
938 DWORD maxBytes = *ldwTotsize;
939 HRESULT status;
940 LPSTR bufptr = lpValueBuf;
941 *ldwTotsize = 0;
943 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
945 for(i=0; i < num_vals; ++i)
948 val_list[i].ve_valuelen=0;
949 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
950 if(status != ERROR_SUCCESS)
952 return status;
955 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
957 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
958 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
959 if(status != ERROR_SUCCESS)
961 return status;
964 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
966 bufptr += val_list[i].ve_valuelen;
969 *ldwTotsize += val_list[i].ve_valuelen;
971 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
975 /******************************************************************************
976 * RegQueryMultipleValuesW [ADVAPI32.@]
978 * See RegQueryMultipleValuesA.
980 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
981 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
983 unsigned int i;
984 DWORD maxBytes = *ldwTotsize;
985 HRESULT status;
986 LPSTR bufptr = (LPSTR)lpValueBuf;
987 *ldwTotsize = 0;
989 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
991 for(i=0; i < num_vals; ++i)
993 val_list[i].ve_valuelen=0;
994 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
995 if(status != ERROR_SUCCESS)
997 return status;
1000 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
1002 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
1003 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
1004 if(status != ERROR_SUCCESS)
1006 return status;
1009 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
1011 bufptr += val_list[i].ve_valuelen;
1014 *ldwTotsize += val_list[i].ve_valuelen;
1016 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
1019 /******************************************************************************
1020 * RegQueryInfoKeyA [ADVAPI32.@]
1022 * Retrieves information about a registry key.
1024 * PARAMS
1025 * hKey [I] Handle to an open key.
1026 * lpClass [O] Class string of the key.
1027 * lpcClass [I/O] size of lpClass.
1028 * lpReserved [I] Reserved; must be NULL.
1029 * lpcSubKeys [O] Number of subkeys contained by the key.
1030 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
1031 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
1032 * class in TCHARS.
1033 * lpcValues [O] Number of values associated with the key.
1034 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
1035 * lpcMaxValueLen [O] Longest data component among the key's values
1036 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
1037 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
1039 * RETURNS
1040 * Success: ERROR_SUCCESS
1041 * Failure: nonzero error code from Winerror.h
1043 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
1044 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
1045 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
1046 LPDWORD security, FILETIME *modif )
1048 NTSTATUS status;
1049 char buffer[256], *buf_ptr = buffer;
1050 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
1051 DWORD total_size, len;
1053 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
1054 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
1056 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
1057 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1059 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
1060 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1062 if (class || class_len)
1064 /* retry with a dynamically allocated buffer */
1065 while (status == STATUS_BUFFER_OVERFLOW)
1067 if (buf_ptr != buffer) heap_free( buf_ptr );
1068 if (!(buf_ptr = heap_alloc( total_size )))
1069 return ERROR_NOT_ENOUGH_MEMORY;
1070 info = (KEY_FULL_INFORMATION *)buf_ptr;
1071 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
1074 if (status) goto done;
1076 len = 0;
1077 if (class && class_len) len = *class_len;
1078 RtlUnicodeToMultiByteN( class, len, class_len,
1079 (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength );
1080 if (len)
1082 class[len - 1] = 0;
1083 if (*class_len + 1 > len)
1085 status = STATUS_BUFFER_OVERFLOW;
1086 *class_len -= 1;
1090 else status = STATUS_SUCCESS;
1092 if (subkeys) *subkeys = info->SubKeys;
1093 if (max_subkey) *max_subkey = info->MaxNameLen;
1094 if (max_class) *max_class = info->MaxClassLen;
1095 if (values) *values = info->Values;
1096 if (max_value) *max_value = info->MaxValueNameLen;
1097 if (max_data) *max_data = info->MaxValueDataLen;
1098 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
1100 if (security)
1102 FIXME( "security argument not supported.\n");
1103 *security = 0;
1106 done:
1107 if (buf_ptr != buffer) heap_free( buf_ptr );
1108 return RtlNtStatusToDosError( status );
1112 /******************************************************************************
1113 * RegCloseKey [ADVAPI32.@]
1115 * Close an open registry key.
1117 * PARAMS
1118 * hkey [I] Handle of key to close
1120 * RETURNS
1121 * Success: ERROR_SUCCESS
1122 * Failure: Error code
1124 LSTATUS WINAPI DECLSPEC_HOTPATCH RegCloseKey( HKEY hkey )
1126 if (!hkey) return ERROR_INVALID_HANDLE;
1127 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
1128 return RtlNtStatusToDosError( NtClose( hkey ) );
1132 /******************************************************************************
1133 * RegDeleteKeyExW [ADVAPI32.@]
1135 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
1137 DWORD ret;
1138 HKEY tmp;
1140 if (!name) return ERROR_INVALID_PARAMETER;
1142 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
1144 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1145 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
1147 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1148 RegCloseKey( tmp );
1150 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
1151 return ret;
1155 /******************************************************************************
1156 * RegDeleteKeyW [ADVAPI32.@]
1158 * See RegDeleteKeyA.
1160 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
1162 return RegDeleteKeyExW( hkey, name, 0, 0 );
1166 /******************************************************************************
1167 * RegDeleteKeyExA [ADVAPI32.@]
1169 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1171 DWORD ret;
1172 HKEY tmp;
1174 if (!name) return ERROR_INVALID_PARAMETER;
1176 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
1178 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1179 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1181 if (!is_version_nt()) /* win95 does recursive key deletes */
1183 CHAR sub[MAX_PATH];
1185 while(!RegEnumKeyA(tmp, 0, sub, sizeof(sub)))
1187 if(RegDeleteKeyExA(tmp, sub, access, reserved)) /* recurse */
1188 break;
1191 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1192 RegCloseKey( tmp );
1194 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1195 return ret;
1199 /******************************************************************************
1200 * RegDeleteKeyA [ADVAPI32.@]
1202 * Delete a registry key.
1204 * PARAMS
1205 * hkey [I] Handle to parent key containing the key to delete
1206 * name [I] Name of the key user hkey to delete
1208 * NOTES
1210 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1211 * right. In reality, it opens a new handle with DELETE access.
1213 * RETURNS
1214 * Success: ERROR_SUCCESS
1215 * Failure: Error code
1217 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1219 return RegDeleteKeyExA( hkey, name, 0, 0 );
1224 /******************************************************************************
1225 * RegSetValueExW [ADVAPI32.@]
1227 * Set the data and contents of a registry value.
1229 * PARAMS
1230 * hkey [I] Handle of key to set value for
1231 * name [I] Name of value to set
1232 * reserved [I] Reserved, must be zero
1233 * type [I] Type of the value being set
1234 * data [I] The new contents of the value to set
1235 * count [I] Size of data
1237 * RETURNS
1238 * Success: ERROR_SUCCESS
1239 * Failure: Error code
1241 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1242 DWORD type, const BYTE *data, DWORD count )
1244 UNICODE_STRING nameW;
1246 /* no need for version check, not implemented on win9x anyway */
1248 if ((data && ((ULONG_PTR)data >> 16) == 0) || (!data && count)) return ERROR_NOACCESS;
1250 if (count && is_string(type))
1252 LPCWSTR str = (LPCWSTR)data;
1253 /* if user forgot to count terminating null, add it (yes NT does this) */
1254 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1255 count += sizeof(WCHAR);
1257 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1259 RtlInitUnicodeString( &nameW, name );
1260 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1264 /******************************************************************************
1265 * RegSetValueExA [ADVAPI32.@]
1267 * See RegSetValueExW.
1269 * NOTES
1270 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1271 * NT does definitely care (aj)
1273 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1274 const BYTE *data, DWORD count )
1276 ANSI_STRING nameA;
1277 UNICODE_STRING nameW;
1278 WCHAR *dataW = NULL;
1279 NTSTATUS status;
1281 if (!is_version_nt()) /* win95 */
1283 if (type == REG_SZ)
1285 if (!data) return ERROR_INVALID_PARAMETER;
1286 count = strlen((const char *)data) + 1;
1289 else if (count && is_string(type))
1291 /* if user forgot to count terminating null, add it (yes NT does this) */
1292 if (data[count-1] && !data[count]) count++;
1295 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1297 if (is_string( type )) /* need to convert to Unicode */
1299 DWORD lenW;
1300 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1301 if (!(dataW = heap_alloc( lenW ))) return ERROR_OUTOFMEMORY;
1302 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1303 count = lenW;
1304 data = (BYTE *)dataW;
1307 RtlInitAnsiString( &nameA, name );
1308 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1310 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1311 RtlFreeUnicodeString( &nameW );
1313 heap_free( dataW );
1314 return RtlNtStatusToDosError( status );
1318 /******************************************************************************
1319 * RegSetValueW [ADVAPI32.@]
1321 * Sets the data for the default or unnamed value of a reg key.
1323 * PARAMS
1324 * hkey [I] Handle to an open key.
1325 * subkey [I] Name of a subkey of hKey.
1326 * type [I] Type of information to store.
1327 * data [I] String that contains the data to set for the default value.
1328 * count [I] Ignored.
1330 * RETURNS
1331 * Success: ERROR_SUCCESS
1332 * Failure: nonzero error code from Winerror.h
1334 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR subkey, DWORD type, LPCWSTR data, DWORD count )
1336 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(subkey), type, debugstr_w(data), count );
1338 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1340 return RegSetKeyValueW( hkey, subkey, NULL, type, data, (strlenW(data) + 1)*sizeof(WCHAR) );
1343 /******************************************************************************
1344 * RegSetValueA [ADVAPI32.@]
1346 * See RegSetValueW.
1348 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR subkey, DWORD type, LPCSTR data, DWORD count )
1350 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(subkey), type, debugstr_a(data), count );
1352 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1354 return RegSetKeyValueA( hkey, subkey, NULL, type, data, strlen(data) + 1 );
1357 /******************************************************************************
1358 * RegSetKeyValueW [ADVAPI32.@]
1360 LONG WINAPI RegSetKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name, DWORD type, const void *data, DWORD len )
1362 HKEY hsubkey = NULL;
1363 DWORD ret;
1365 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey, debugstr_w(subkey), debugstr_w(name), type, data, len );
1367 if (subkey && subkey[0]) /* need to create the subkey */
1369 if ((ret = RegCreateKeyW( hkey, subkey, &hsubkey )) != ERROR_SUCCESS) return ret;
1370 hkey = hsubkey;
1373 ret = RegSetValueExW( hkey, name, 0, type, (const BYTE*)data, len );
1374 if (hsubkey) RegCloseKey( hsubkey );
1375 return ret;
1378 /******************************************************************************
1379 * RegSetKeyValueA [ADVAPI32.@]
1381 LONG WINAPI RegSetKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name, DWORD type, const void *data, DWORD len )
1383 HKEY hsubkey = NULL;
1384 DWORD ret;
1386 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey, debugstr_a(subkey), debugstr_a(name), type, data, len );
1388 if (subkey && subkey[0]) /* need to create the subkey */
1390 if ((ret = RegCreateKeyA( hkey, subkey, &hsubkey )) != ERROR_SUCCESS) return ret;
1391 hkey = hsubkey;
1394 ret = RegSetValueExA( hkey, name, 0, type, (const BYTE*)data, len );
1395 if (hsubkey) RegCloseKey( hsubkey );
1396 return ret;
1399 /******************************************************************************
1400 * RegQueryValueExW [ADVAPI32.@]
1402 * See RegQueryValueExA.
1404 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1405 LPBYTE data, LPDWORD count )
1407 NTSTATUS status;
1408 UNICODE_STRING name_str;
1409 DWORD total_size;
1410 char buffer[256], *buf_ptr = buffer;
1411 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1412 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1414 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1415 hkey, debugstr_w(name), reserved, type, data, count,
1416 (count && data) ? *count : 0 );
1418 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1419 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1421 RtlInitUnicodeString( &name_str, name );
1423 if (data) total_size = min( sizeof(buffer), *count + info_size );
1424 else
1426 total_size = info_size;
1427 if (count) *count = 0;
1430 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1431 buffer, total_size, &total_size );
1432 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1434 if (data)
1436 /* retry with a dynamically allocated buffer */
1437 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1439 if (buf_ptr != buffer) heap_free( buf_ptr );
1440 if (!(buf_ptr = heap_alloc( total_size )))
1441 return ERROR_NOT_ENOUGH_MEMORY;
1442 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1443 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1444 buf_ptr, total_size, &total_size );
1447 if (!status)
1449 memcpy( data, buf_ptr + info_size, total_size - info_size );
1450 /* if the type is REG_SZ and data is not 0-terminated
1451 * and there is enough space in the buffer NT appends a \0 */
1452 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1454 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1455 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1458 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1460 else status = STATUS_SUCCESS;
1462 if (type) *type = info->Type;
1463 if (count) *count = total_size - info_size;
1465 done:
1466 if (buf_ptr != buffer) heap_free( buf_ptr );
1467 return RtlNtStatusToDosError(status);
1471 /******************************************************************************
1472 * RegQueryValueExA [ADVAPI32.@]
1474 * Get the type and contents of a specified value under with a key.
1476 * PARAMS
1477 * hkey [I] Handle of the key to query
1478 * name [I] Name of value under hkey to query
1479 * reserved [I] Reserved - must be NULL
1480 * type [O] Destination for the value type, or NULL if not required
1481 * data [O] Destination for the values contents, or NULL if not required
1482 * count [I/O] Size of data, updated with the number of bytes returned
1484 * RETURNS
1485 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1486 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1487 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1488 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1490 * NOTES
1491 * MSDN states that if data is too small it is partially filled. In reality
1492 * it remains untouched.
1494 LSTATUS WINAPI DECLSPEC_HOTPATCH RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved,
1495 LPDWORD type, LPBYTE data, LPDWORD count )
1497 NTSTATUS status;
1498 ANSI_STRING nameA;
1499 UNICODE_STRING nameW;
1500 DWORD total_size, datalen = 0;
1501 char buffer[256], *buf_ptr = buffer;
1502 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1503 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1505 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1506 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1508 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1509 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1511 if (count) datalen = *count;
1512 if (!data && count) *count = 0;
1514 /* this matches Win9x behaviour - NT sets *type to a random value */
1515 if (type) *type = REG_NONE;
1517 RtlInitAnsiString( &nameA, name );
1518 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1519 return RtlNtStatusToDosError(status);
1521 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1522 buffer, sizeof(buffer), &total_size );
1523 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1525 /* we need to fetch the contents for a string type even if not requested,
1526 * because we need to compute the length of the ASCII string. */
1527 if (data || is_string(info->Type))
1529 /* retry with a dynamically allocated buffer */
1530 while (status == STATUS_BUFFER_OVERFLOW)
1532 if (buf_ptr != buffer) heap_free( buf_ptr );
1533 if (!(buf_ptr = heap_alloc( total_size )))
1535 status = STATUS_NO_MEMORY;
1536 goto done;
1538 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1539 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1540 buf_ptr, total_size, &total_size );
1543 if (status) goto done;
1545 if (is_string(info->Type))
1547 DWORD len;
1549 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1550 total_size - info_size );
1551 if (data && len)
1553 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1554 else
1556 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1557 total_size - info_size );
1558 /* if the type is REG_SZ and data is not 0-terminated
1559 * and there is enough space in the buffer NT appends a \0 */
1560 if (len < datalen && data[len-1]) data[len] = 0;
1563 total_size = len + info_size;
1565 else if (data)
1567 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1568 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1571 else status = STATUS_SUCCESS;
1573 if (type) *type = info->Type;
1574 if (count) *count = total_size - info_size;
1576 done:
1577 if (buf_ptr != buffer) heap_free( buf_ptr );
1578 RtlFreeUnicodeString( &nameW );
1579 return RtlNtStatusToDosError(status);
1583 /******************************************************************************
1584 * RegQueryValueW [ADVAPI32.@]
1586 * Retrieves the data associated with the default or unnamed value of a key.
1588 * PARAMS
1589 * hkey [I] Handle to an open key.
1590 * name [I] Name of the subkey of hKey.
1591 * data [O] Receives the string associated with the default value
1592 * of the key.
1593 * count [I/O] Size of lpValue in bytes.
1595 * RETURNS
1596 * Success: ERROR_SUCCESS
1597 * Failure: nonzero error code from Winerror.h
1599 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1601 DWORD ret;
1602 HKEY subkey = hkey;
1604 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1606 if (name && name[0])
1608 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1610 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1611 if (subkey != hkey) RegCloseKey( subkey );
1612 if (ret == ERROR_FILE_NOT_FOUND)
1614 /* return empty string if default value not found */
1615 if (data) *data = 0;
1616 if (count) *count = sizeof(WCHAR);
1617 ret = ERROR_SUCCESS;
1619 return ret;
1623 /******************************************************************************
1624 * RegQueryValueA [ADVAPI32.@]
1626 * See RegQueryValueW.
1628 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1630 DWORD ret;
1631 HKEY subkey = hkey;
1633 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1635 if (name && name[0])
1637 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1639 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1640 if (subkey != hkey) RegCloseKey( subkey );
1641 if (ret == ERROR_FILE_NOT_FOUND)
1643 /* return empty string if default value not found */
1644 if (data) *data = 0;
1645 if (count) *count = 1;
1646 ret = ERROR_SUCCESS;
1648 return ret;
1652 /******************************************************************************
1653 * ADVAPI_ApplyRestrictions [internal]
1655 * Helper function for RegGetValueA/W.
1657 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1658 DWORD cbData, PLONG ret )
1660 /* Check if the type is restricted by the passed flags */
1661 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1663 DWORD dwMask = 0;
1665 switch (dwType)
1667 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1668 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1669 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1670 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1671 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1672 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1673 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1676 if (dwFlags & dwMask)
1678 /* Type is not restricted, check for size mismatch */
1679 if (dwType == REG_BINARY)
1681 DWORD cbExpect = 0;
1683 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1684 cbExpect = 4;
1685 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1686 cbExpect = 8;
1688 if (cbExpect && cbData != cbExpect)
1689 *ret = ERROR_DATATYPE_MISMATCH;
1692 else *ret = ERROR_UNSUPPORTED_TYPE;
1697 /******************************************************************************
1698 * RegGetValueW [ADVAPI32.@]
1700 * Retrieves the type and data for a value name associated with a key,
1701 * optionally expanding its content and restricting its type.
1703 * PARAMS
1704 * hKey [I] Handle to an open key.
1705 * pszSubKey [I] Name of the subkey of hKey.
1706 * pszValue [I] Name of value under hKey/szSubKey to query.
1707 * dwFlags [I] Flags restricting the value type to retrieve.
1708 * pdwType [O] Destination for the values type, may be NULL.
1709 * pvData [O] Destination for the values content, may be NULL.
1710 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1711 * retrieve the whole content, including the trailing '\0'
1712 * for strings.
1714 * RETURNS
1715 * Success: ERROR_SUCCESS
1716 * Failure: nonzero error code from Winerror.h
1718 * NOTES
1719 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1720 * expanded and pdwType is set to REG_SZ instead.
1721 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1722 * without RRF_NOEXPAND is thus not allowed.
1723 * An exception is the case where RRF_RT_ANY is specified, because then
1724 * RRF_NOEXPAND is allowed.
1726 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1727 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1728 LPDWORD pcbData )
1730 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1731 PVOID pvBuf = NULL;
1732 LONG ret;
1734 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1735 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1736 pvData, pcbData, cbData);
1738 if (pvData && !pcbData)
1739 return ERROR_INVALID_PARAMETER;
1740 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1741 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1742 return ERROR_INVALID_PARAMETER;
1744 if (pszSubKey && pszSubKey[0])
1746 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1747 if (ret != ERROR_SUCCESS) return ret;
1750 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1752 /* If we are going to expand we need to read in the whole the value even
1753 * if the passed buffer was too small as the expanded string might be
1754 * smaller than the unexpanded one and could fit into cbData bytes. */
1755 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1756 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1758 do {
1759 heap_free(pvBuf);
1761 pvBuf = heap_alloc(cbData);
1762 if (!pvBuf)
1764 ret = ERROR_NOT_ENOUGH_MEMORY;
1765 break;
1768 if (ret == ERROR_MORE_DATA || !pvData)
1769 ret = RegQueryValueExW(hKey, pszValue, NULL,
1770 &dwType, pvBuf, &cbData);
1771 else
1773 /* Even if cbData was large enough we have to copy the
1774 * string since ExpandEnvironmentStrings can't handle
1775 * overlapping buffers. */
1776 CopyMemory(pvBuf, pvData, cbData);
1779 /* Both the type or the value itself could have been modified in
1780 * between so we have to keep retrying until the buffer is large
1781 * enough or we no longer have to expand the value. */
1782 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1784 if (ret == ERROR_SUCCESS)
1786 /* Recheck dwType in case it changed since the first call */
1787 if (dwType == REG_EXPAND_SZ)
1789 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1790 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1791 dwType = REG_SZ;
1792 if(pvData && pcbData && cbData > *pcbData)
1793 ret = ERROR_MORE_DATA;
1795 else if (pvData)
1796 CopyMemory(pvData, pvBuf, *pcbData);
1799 heap_free(pvBuf);
1802 if (pszSubKey && pszSubKey[0])
1803 RegCloseKey(hKey);
1805 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1807 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1808 ZeroMemory(pvData, *pcbData);
1810 if (pdwType) *pdwType = dwType;
1811 if (pcbData) *pcbData = cbData;
1813 return ret;
1817 /******************************************************************************
1818 * RegGetValueA [ADVAPI32.@]
1820 * See RegGetValueW.
1822 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1823 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1824 LPDWORD pcbData )
1826 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1827 PVOID pvBuf = NULL;
1828 LONG ret;
1830 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1831 hKey, debugstr_a(pszSubKey), debugstr_a(pszValue), dwFlags,
1832 pdwType, pvData, pcbData, cbData);
1834 if (pvData && !pcbData)
1835 return ERROR_INVALID_PARAMETER;
1836 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1837 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1838 return ERROR_INVALID_PARAMETER;
1840 if (pszSubKey && pszSubKey[0])
1842 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1843 if (ret != ERROR_SUCCESS) return ret;
1846 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1848 /* If we are going to expand we need to read in the whole the value even
1849 * if the passed buffer was too small as the expanded string might be
1850 * smaller than the unexpanded one and could fit into cbData bytes. */
1851 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1852 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1854 do {
1855 heap_free(pvBuf);
1857 pvBuf = heap_alloc(cbData);
1858 if (!pvBuf)
1860 ret = ERROR_NOT_ENOUGH_MEMORY;
1861 break;
1864 if (ret == ERROR_MORE_DATA || !pvData)
1865 ret = RegQueryValueExA(hKey, pszValue, NULL,
1866 &dwType, pvBuf, &cbData);
1867 else
1869 /* Even if cbData was large enough we have to copy the
1870 * string since ExpandEnvironmentStrings can't handle
1871 * overlapping buffers. */
1872 CopyMemory(pvBuf, pvData, cbData);
1875 /* Both the type or the value itself could have been modified in
1876 * between so we have to keep retrying until the buffer is large
1877 * enough or we no longer have to expand the value. */
1878 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1880 if (ret == ERROR_SUCCESS)
1882 /* Recheck dwType in case it changed since the first call */
1883 if (dwType == REG_EXPAND_SZ)
1885 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1886 pcbData ? *pcbData : 0);
1887 dwType = REG_SZ;
1888 if(pvData && pcbData && cbData > *pcbData)
1889 ret = ERROR_MORE_DATA;
1891 else if (pvData)
1892 CopyMemory(pvData, pvBuf, *pcbData);
1895 heap_free(pvBuf);
1898 if (pszSubKey && pszSubKey[0])
1899 RegCloseKey(hKey);
1901 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1903 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1904 ZeroMemory(pvData, *pcbData);
1906 if (pdwType) *pdwType = dwType;
1907 if (pcbData) *pcbData = cbData;
1909 return ret;
1913 /******************************************************************************
1914 * RegEnumValueW [ADVAPI32.@]
1916 * Enumerates the values for the specified open registry key.
1918 * PARAMS
1919 * hkey [I] Handle to key to query
1920 * index [I] Index of value to query
1921 * value [O] Value string
1922 * val_count [I/O] Size of value buffer (in wchars)
1923 * reserved [I] Reserved
1924 * type [O] Type code
1925 * data [O] Value data
1926 * count [I/O] Size of data buffer (in bytes)
1928 * RETURNS
1929 * Success: ERROR_SUCCESS
1930 * Failure: nonzero error code from Winerror.h
1933 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1934 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1936 NTSTATUS status;
1937 DWORD total_size;
1938 char buffer[256], *buf_ptr = buffer;
1939 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1940 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1942 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1943 hkey, index, value, val_count, reserved, type, data, count );
1945 if ((data && !count) || reserved || !value || !val_count)
1946 return ERROR_INVALID_PARAMETER;
1947 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1949 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1950 if (data) total_size += *count;
1951 total_size = min( sizeof(buffer), total_size );
1953 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1954 buffer, total_size, &total_size );
1956 /* retry with a dynamically allocated buffer */
1957 while (status == STATUS_BUFFER_OVERFLOW)
1959 if (buf_ptr != buffer) heap_free( buf_ptr );
1960 if (!(buf_ptr = heap_alloc( total_size )))
1961 return ERROR_NOT_ENOUGH_MEMORY;
1962 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1963 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1964 buf_ptr, total_size, &total_size );
1967 if (status) goto done;
1969 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1971 status = STATUS_BUFFER_OVERFLOW;
1972 goto overflow;
1974 memcpy( value, info->Name, info->NameLength );
1975 *val_count = info->NameLength / sizeof(WCHAR);
1976 value[*val_count] = 0;
1978 if (data)
1980 if (total_size - info->DataOffset > *count)
1982 status = STATUS_BUFFER_OVERFLOW;
1983 goto overflow;
1985 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1986 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1988 /* if the type is REG_SZ and data is not 0-terminated
1989 * and there is enough space in the buffer NT appends a \0 */
1990 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1991 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1995 overflow:
1996 if (type) *type = info->Type;
1997 if (count) *count = info->DataLength;
1999 done:
2000 if (buf_ptr != buffer) heap_free( buf_ptr );
2001 return RtlNtStatusToDosError(status);
2005 /******************************************************************************
2006 * RegEnumValueA [ADVAPI32.@]
2008 * See RegEnumValueW.
2010 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
2011 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
2013 NTSTATUS status;
2014 DWORD total_size;
2015 char buffer[256], *buf_ptr = buffer;
2016 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
2017 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
2019 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
2020 hkey, index, value, val_count, reserved, type, data, count );
2022 if ((data && !count) || reserved || !value || !val_count)
2023 return ERROR_INVALID_PARAMETER;
2024 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2026 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2027 if (data) total_size += *count;
2028 total_size = min( sizeof(buffer), total_size );
2030 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
2031 buffer, total_size, &total_size );
2033 /* we need to fetch the contents for a string type even if not requested,
2034 * because we need to compute the length of the ASCII string. */
2036 /* retry with a dynamically allocated buffer */
2037 while (status == STATUS_BUFFER_OVERFLOW)
2039 if (buf_ptr != buffer) heap_free( buf_ptr );
2040 if (!(buf_ptr = heap_alloc( total_size )))
2041 return ERROR_NOT_ENOUGH_MEMORY;
2042 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2043 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
2044 buf_ptr, total_size, &total_size );
2047 if (status) goto done;
2049 if (is_string(info->Type))
2051 DWORD len;
2052 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
2053 total_size - info->DataOffset );
2054 if (data && len)
2056 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
2057 else
2059 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
2060 total_size - info->DataOffset );
2061 /* if the type is REG_SZ and data is not 0-terminated
2062 * and there is enough space in the buffer NT appends a \0 */
2063 if (len < *count && data[len-1]) data[len] = 0;
2066 info->DataLength = len;
2068 else if (data)
2070 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
2071 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2074 if (!status)
2076 DWORD len;
2078 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2079 if (len >= *val_count)
2081 status = STATUS_BUFFER_OVERFLOW;
2082 if (*val_count)
2084 len = *val_count - 1;
2085 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2086 value[len] = 0;
2089 else
2091 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2092 value[len] = 0;
2093 *val_count = len;
2097 if (type) *type = info->Type;
2098 if (count) *count = info->DataLength;
2100 done:
2101 if (buf_ptr != buffer) heap_free( buf_ptr );
2102 return RtlNtStatusToDosError(status);
2105 /******************************************************************************
2106 * RegDeleteValueW [ADVAPI32.@]
2108 * See RegDeleteValueA.
2110 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2112 return RegDeleteKeyValueW( hkey, NULL, name );
2115 /******************************************************************************
2116 * RegDeleteValueA [ADVAPI32.@]
2118 * Delete a value from the registry.
2120 * PARAMS
2121 * hkey [I] Registry handle of the key holding the value
2122 * name [I] Name of the value under hkey to delete
2124 * RETURNS
2125 * Success: ERROR_SUCCESS
2126 * Failure: nonzero error code from Winerror.h
2128 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2130 return RegDeleteKeyValueA( hkey, NULL, name );
2133 /******************************************************************************
2134 * RegDeleteKeyValueW [ADVAPI32.@]
2136 LONG WINAPI RegDeleteKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name )
2138 UNICODE_STRING nameW;
2139 HKEY hsubkey = 0;
2140 LONG ret;
2142 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2144 if (subkey)
2146 if ((ret = RegOpenKeyExW( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey )))
2147 return ret;
2148 hkey = hsubkey;
2151 RtlInitUnicodeString( &nameW, name );
2152 ret = RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2153 if (hsubkey) RegCloseKey( hsubkey );
2154 return ret;
2157 /******************************************************************************
2158 * RegDeleteKeyValueA [ADVAPI32.@]
2160 LONG WINAPI RegDeleteKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name )
2162 UNICODE_STRING nameW;
2163 HKEY hsubkey = 0;
2164 ANSI_STRING nameA;
2165 NTSTATUS status;
2167 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2169 if (subkey)
2171 LONG ret = RegOpenKeyExA( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey );
2172 if (ret)
2173 return ret;
2174 hkey = hsubkey;
2177 RtlInitAnsiString( &nameA, name );
2178 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2180 status = NtDeleteValueKey( hkey, &nameW );
2181 RtlFreeUnicodeString( &nameW );
2184 if (hsubkey) RegCloseKey( hsubkey );
2185 return RtlNtStatusToDosError( status );
2188 /******************************************************************************
2189 * RegLoadKeyW [ADVAPI32.@]
2191 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2192 * registration information from a specified file into that subkey.
2194 * PARAMS
2195 * hkey [I] Handle of open key
2196 * subkey [I] Address of name of subkey
2197 * filename [I] Address of filename for registry information
2199 * RETURNS
2200 * Success: ERROR_SUCCESS
2201 * Failure: nonzero error code from Winerror.h
2203 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2205 OBJECT_ATTRIBUTES destkey, file;
2206 UNICODE_STRING subkeyW, filenameW;
2207 NTSTATUS status;
2209 if (!(hkey = get_special_root_hkey(hkey, 0))) return ERROR_INVALID_HANDLE;
2211 destkey.Length = sizeof(destkey);
2212 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2213 destkey.ObjectName = &subkeyW; /* name of the key */
2214 destkey.Attributes = 0;
2215 destkey.SecurityDescriptor = NULL;
2216 destkey.SecurityQualityOfService = NULL;
2217 RtlInitUnicodeString(&subkeyW, subkey);
2219 file.Length = sizeof(file);
2220 file.RootDirectory = NULL;
2221 file.ObjectName = &filenameW; /* file containing the hive */
2222 file.Attributes = OBJ_CASE_INSENSITIVE;
2223 file.SecurityDescriptor = NULL;
2224 file.SecurityQualityOfService = NULL;
2225 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2227 status = NtLoadKey(&destkey, &file);
2228 RtlFreeUnicodeString(&filenameW);
2229 return RtlNtStatusToDosError( status );
2233 /******************************************************************************
2234 * RegLoadKeyA [ADVAPI32.@]
2236 * See RegLoadKeyW.
2238 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2240 UNICODE_STRING subkeyW, filenameW;
2241 STRING subkeyA, filenameA;
2242 NTSTATUS status;
2243 LONG ret;
2245 RtlInitAnsiString(&subkeyA, subkey);
2246 RtlInitAnsiString(&filenameA, filename);
2248 RtlInitUnicodeString(&subkeyW, NULL);
2249 RtlInitUnicodeString(&filenameW, NULL);
2250 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2251 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2253 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2255 else ret = RtlNtStatusToDosError(status);
2256 RtlFreeUnicodeString(&subkeyW);
2257 RtlFreeUnicodeString(&filenameW);
2258 return ret;
2262 /******************************************************************************
2263 * RegSaveKeyW [ADVAPI32.@]
2265 * Save a key and all of its subkeys and values to a new file in the standard format.
2267 * PARAMS
2268 * hkey [I] Handle of key where save begins
2269 * lpFile [I] Address of filename to save to
2270 * sa [I] Address of security structure
2272 * RETURNS
2273 * Success: ERROR_SUCCESS
2274 * Failure: nonzero error code from Winerror.h
2276 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2278 static const WCHAR format[] =
2279 {'r','e','g','%','0','4','x','.','t','m','p',0};
2280 WCHAR buffer[MAX_PATH];
2281 int count = 0;
2282 LPWSTR nameW;
2283 DWORD ret, err;
2284 HANDLE handle;
2286 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2288 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2289 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2291 err = GetLastError();
2292 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2294 for (;;)
2296 snprintfW( nameW, 16, format, count++ );
2297 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2298 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2299 if (handle != INVALID_HANDLE_VALUE) break;
2300 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2302 /* Something gone haywire ? Please report if this happens abnormally */
2303 if (count >= 100)
2304 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);
2307 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2309 CloseHandle( handle );
2310 if (!ret)
2312 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2314 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2315 debugstr_w(file) );
2316 ret = GetLastError();
2319 if (ret) DeleteFileW( buffer );
2321 done:
2322 SetLastError( err ); /* restore last error code */
2323 return ret;
2327 /******************************************************************************
2328 * RegSaveKeyA [ADVAPI32.@]
2330 * See RegSaveKeyW.
2332 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2334 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2335 NTSTATUS status;
2336 STRING fileA;
2338 RtlInitAnsiString(&fileA, file);
2339 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2340 return RtlNtStatusToDosError( status );
2341 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2345 /******************************************************************************
2346 * RegRestoreKeyW [ADVAPI32.@]
2348 * Read the registry information from a file and copy it over a key.
2350 * PARAMS
2351 * hkey [I] Handle of key where restore begins
2352 * lpFile [I] Address of filename containing saved tree
2353 * dwFlags [I] Optional flags
2355 * RETURNS
2356 * Success: ERROR_SUCCESS
2357 * Failure: nonzero error code from Winerror.h
2359 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2361 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2363 /* It seems to do this check before the hkey check */
2364 if (!lpFile || !*lpFile)
2365 return ERROR_INVALID_PARAMETER;
2367 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2369 /* Check for file existence */
2371 return ERROR_SUCCESS;
2375 /******************************************************************************
2376 * RegRestoreKeyA [ADVAPI32.@]
2378 * See RegRestoreKeyW.
2380 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2382 UNICODE_STRING lpFileW;
2383 LONG ret;
2385 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2386 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2387 RtlFreeUnicodeString( &lpFileW );
2388 return ret;
2392 /******************************************************************************
2393 * RegUnLoadKeyW [ADVAPI32.@]
2395 * Unload a registry key and its subkeys from the registry.
2397 * PARAMS
2398 * hkey [I] Handle of open key
2399 * lpSubKey [I] Address of name of subkey to unload
2401 * RETURNS
2402 * Success: ERROR_SUCCESS
2403 * Failure: nonzero error code from Winerror.h
2405 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2407 DWORD ret;
2408 HKEY shkey;
2409 OBJECT_ATTRIBUTES attr;
2410 UNICODE_STRING subkey;
2412 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2414 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2415 if( ret )
2416 return ERROR_INVALID_PARAMETER;
2418 RtlInitUnicodeString(&subkey, lpSubKey);
2419 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2420 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2422 RegCloseKey(shkey);
2424 return ret;
2428 /******************************************************************************
2429 * RegUnLoadKeyA [ADVAPI32.@]
2431 * See RegUnLoadKeyW.
2433 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2435 UNICODE_STRING lpSubKeyW;
2436 LONG ret;
2438 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2439 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2440 RtlFreeUnicodeString( &lpSubKeyW );
2441 return ret;
2445 /******************************************************************************
2446 * RegReplaceKeyW [ADVAPI32.@]
2448 * Replace the file backing a registry key and all its subkeys with another file.
2450 * PARAMS
2451 * hkey [I] Handle of open key
2452 * lpSubKey [I] Address of name of subkey
2453 * lpNewFile [I] Address of filename for file with new data
2454 * lpOldFile [I] Address of filename for backup file
2456 * RETURNS
2457 * Success: ERROR_SUCCESS
2458 * Failure: nonzero error code from Winerror.h
2460 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2461 LPCWSTR lpOldFile )
2463 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2464 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2465 return ERROR_SUCCESS;
2469 /******************************************************************************
2470 * RegReplaceKeyA [ADVAPI32.@]
2472 * See RegReplaceKeyW.
2474 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2475 LPCSTR lpOldFile )
2477 UNICODE_STRING lpSubKeyW;
2478 UNICODE_STRING lpNewFileW;
2479 UNICODE_STRING lpOldFileW;
2480 LONG ret;
2482 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2483 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2484 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2485 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2486 RtlFreeUnicodeString( &lpOldFileW );
2487 RtlFreeUnicodeString( &lpNewFileW );
2488 RtlFreeUnicodeString( &lpSubKeyW );
2489 return ret;
2493 /******************************************************************************
2494 * RegSetKeySecurity [ADVAPI32.@]
2496 * Set the security of an open registry key.
2498 * PARAMS
2499 * hkey [I] Open handle of key to set
2500 * SecurityInfo [I] Descriptor contents
2501 * pSecurityDesc [I] Address of descriptor for key
2503 * RETURNS
2504 * Success: ERROR_SUCCESS
2505 * Failure: nonzero error code from Winerror.h
2507 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2508 PSECURITY_DESCRIPTOR pSecurityDesc )
2510 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2512 /* It seems to perform this check before the hkey check */
2513 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2514 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2515 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2516 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2517 /* Param OK */
2518 } else
2519 return ERROR_INVALID_PARAMETER;
2521 if (!pSecurityDesc)
2522 return ERROR_INVALID_PARAMETER;
2524 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2526 return RtlNtStatusToDosError( NtSetSecurityObject( hkey, SecurityInfo, pSecurityDesc ) );
2530 /******************************************************************************
2531 * RegGetKeySecurity [ADVAPI32.@]
2533 * Get a copy of the security descriptor for a given registry key.
2535 * PARAMS
2536 * hkey [I] Open handle of key to set
2537 * SecurityInformation [I] Descriptor contents
2538 * pSecurityDescriptor [O] Address of descriptor for key
2539 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2541 * RETURNS
2542 * Success: ERROR_SUCCESS
2543 * Failure: Error code
2545 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2546 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2547 LPDWORD lpcbSecurityDescriptor )
2549 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2550 *lpcbSecurityDescriptor);
2552 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2554 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2555 SecurityInformation, pSecurityDescriptor,
2556 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2560 /******************************************************************************
2561 * RegFlushKey [ADVAPI32.@]
2563 * Immediately write a registry key to registry.
2565 * PARAMS
2566 * hkey [I] Handle of key to write
2568 * RETURNS
2569 * Success: ERROR_SUCCESS
2570 * Failure: Error code
2572 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2574 hkey = get_special_root_hkey( hkey, 0 );
2575 if (!hkey) return ERROR_INVALID_HANDLE;
2577 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2581 /******************************************************************************
2582 * RegConnectRegistryW [ADVAPI32.@]
2584 * Establish a connection to a predefined registry key on another computer.
2586 * PARAMS
2587 * lpMachineName [I] Address of name of remote computer
2588 * hHey [I] Predefined registry handle
2589 * phkResult [I] Address of buffer for remote registry handle
2591 * RETURNS
2592 * Success: ERROR_SUCCESS
2593 * Failure: nonzero error code from Winerror.h
2595 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2596 PHKEY phkResult )
2598 LONG ret;
2600 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName), hKey, phkResult);
2602 if (!lpMachineName || !*lpMachineName) {
2603 /* Use the local machine name */
2604 ret = RegOpenKeyW( hKey, NULL, phkResult );
2606 else {
2607 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2608 DWORD len = sizeof(compName) / sizeof(WCHAR);
2610 /* MSDN says lpMachineName must start with \\ : not so */
2611 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2612 lpMachineName += 2;
2613 if (GetComputerNameW(compName, &len))
2615 if (!strcmpiW(lpMachineName, compName))
2616 ret = RegOpenKeyW(hKey, NULL, phkResult);
2617 else
2619 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2620 ret = ERROR_BAD_NETPATH;
2623 else
2624 ret = GetLastError();
2626 return ret;
2630 /******************************************************************************
2631 * RegConnectRegistryA [ADVAPI32.@]
2633 * See RegConnectRegistryW.
2635 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2637 UNICODE_STRING machineW;
2638 LONG ret;
2640 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2641 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2642 RtlFreeUnicodeString( &machineW );
2643 return ret;
2647 /******************************************************************************
2648 * RegNotifyChangeKeyValue [ADVAPI32.@]
2650 * Notify the caller about changes to the attributes or contents of a registry key.
2652 * PARAMS
2653 * hkey [I] Handle of key to watch
2654 * fWatchSubTree [I] Flag for subkey notification
2655 * fdwNotifyFilter [I] Changes to be reported
2656 * hEvent [I] Handle of signaled event
2657 * fAsync [I] Flag for asynchronous reporting
2659 * RETURNS
2660 * Success: ERROR_SUCCESS
2661 * Failure: nonzero error code from Winerror.h
2663 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2664 DWORD fdwNotifyFilter, HANDLE hEvent,
2665 BOOL fAsync )
2667 NTSTATUS status;
2668 IO_STATUS_BLOCK iosb;
2670 hkey = get_special_root_hkey( hkey, 0 );
2671 if (!hkey) return ERROR_INVALID_HANDLE;
2673 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2674 hEvent, fAsync);
2676 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2677 fdwNotifyFilter, fAsync, NULL, 0,
2678 fWatchSubTree);
2680 if (status && status != STATUS_TIMEOUT)
2681 return RtlNtStatusToDosError( status );
2683 return ERROR_SUCCESS;
2686 /******************************************************************************
2687 * RegOpenUserClassesRoot [ADVAPI32.@]
2689 * Open the HKEY_CLASSES_ROOT key for a user.
2691 * PARAMS
2692 * hToken [I] Handle of token representing the user
2693 * dwOptions [I] Reserved, must be 0
2694 * samDesired [I] Desired access rights
2695 * phkResult [O] Destination for the resulting key handle
2697 * RETURNS
2698 * Success: ERROR_SUCCESS
2699 * Failure: nonzero error code from Winerror.h
2701 * NOTES
2702 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2703 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2704 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2706 LSTATUS WINAPI RegOpenUserClassesRoot(
2707 HANDLE hToken,
2708 DWORD dwOptions,
2709 REGSAM samDesired,
2710 PHKEY phkResult
2713 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2715 *phkResult = HKEY_CLASSES_ROOT;
2716 return ERROR_SUCCESS;
2719 /******************************************************************************
2720 * load_string [Internal]
2722 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2723 * avoid importing user32, which is higher level than advapi32. Helper for
2724 * RegLoadMUIString.
2726 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2728 HGLOBAL hMemory;
2729 HRSRC hResource;
2730 WCHAR *pString;
2731 int idxString;
2733 /* Negative values have to be inverted. */
2734 if (HIWORD(resId) == 0xffff)
2735 resId = (UINT)(-((INT)resId));
2737 /* Load the resource into memory and get a pointer to it. */
2738 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2739 if (!hResource) return 0;
2740 hMemory = LoadResource(hModule, hResource);
2741 if (!hMemory) return 0;
2742 pString = LockResource(hMemory);
2744 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2745 idxString = resId & 0xf;
2746 while (idxString--) pString += *pString + 1;
2748 /* If no buffer is given, return length of the string. */
2749 if (!pwszBuffer) return *pString;
2751 /* Else copy over the string, respecting the buffer size. */
2752 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2753 if (cMaxChars >= 0) {
2754 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2755 pwszBuffer[cMaxChars] = '\0';
2758 return cMaxChars;
2761 /******************************************************************************
2762 * RegLoadMUIStringW [ADVAPI32.@]
2764 * Load the localized version of a string resource from some PE, respective
2765 * id and path of which are given in the registry value in the format
2766 * @[path]\dllname,-resourceId
2768 * PARAMS
2769 * hKey [I] Key, of which to load the string value from.
2770 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2771 * pszBuffer [O] Buffer to store the localized string in.
2772 * cbBuffer [I] Size of the destination buffer in bytes.
2773 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2774 * dwFlags [I] None supported yet.
2775 * pszBaseDir [I] Not supported yet.
2777 * RETURNS
2778 * Success: ERROR_SUCCESS,
2779 * Failure: nonzero error code from winerror.h
2781 * NOTES
2782 * This is an API of Windows Vista, which wasn't available at the time this code
2783 * was written. We have to check for the correct behaviour once it's available.
2785 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2786 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2788 DWORD dwValueType, cbData;
2789 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2790 LONG result;
2792 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2793 "dwFlags = %d, pwszBaseDir = %s)\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2794 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2796 /* Parameter sanity checks. */
2797 if (!hKey || !pwszBuffer)
2798 return ERROR_INVALID_PARAMETER;
2800 if (pwszBaseDir && *pwszBaseDir) {
2801 FIXME("BaseDir parameter not yet supported!\n");
2802 return ERROR_INVALID_PARAMETER;
2805 /* Check for value existence and correctness of its type, allocate a buffer and load it. */
2806 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2807 if (result != ERROR_SUCCESS) goto cleanup;
2808 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2809 result = ERROR_FILE_NOT_FOUND;
2810 goto cleanup;
2812 pwszTempBuffer = heap_alloc(cbData);
2813 if (!pwszTempBuffer) {
2814 result = ERROR_NOT_ENOUGH_MEMORY;
2815 goto cleanup;
2817 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2818 if (result != ERROR_SUCCESS) goto cleanup;
2820 /* Expand environment variables, if appropriate, or copy the original string over. */
2821 if (dwValueType == REG_EXPAND_SZ) {
2822 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2823 if (!cbData) goto cleanup;
2824 pwszExpandedBuffer = heap_alloc(cbData);
2825 if (!pwszExpandedBuffer) {
2826 result = ERROR_NOT_ENOUGH_MEMORY;
2827 goto cleanup;
2829 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2830 } else {
2831 pwszExpandedBuffer = heap_alloc(cbData);
2832 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2835 /* If the value references a resource based string, parse the value and load the string.
2836 * Else just copy over the original value. */
2837 result = ERROR_SUCCESS;
2838 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2839 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2840 } else {
2841 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2842 UINT uiStringId;
2843 HMODULE hModule;
2845 /* Format of the expanded value is 'path_to_dll,-resId' */
2846 if (!pComma || pComma[1] != '-') {
2847 result = ERROR_BADKEY;
2848 goto cleanup;
2851 uiStringId = atoiW(pComma+2);
2852 *pComma = '\0';
2854 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2855 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2856 result = ERROR_BADKEY;
2857 FreeLibrary(hModule);
2860 cleanup:
2861 heap_free(pwszTempBuffer);
2862 heap_free(pwszExpandedBuffer);
2863 return result;
2866 /******************************************************************************
2867 * RegLoadMUIStringA [ADVAPI32.@]
2869 * See RegLoadMUIStringW
2871 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2872 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2874 UNICODE_STRING valueW, baseDirW;
2875 WCHAR *pwszBuffer;
2876 DWORD cbData = cbBuffer * sizeof(WCHAR);
2877 LONG result;
2879 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2880 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2881 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2882 !(pwszBuffer = heap_alloc(cbData)))
2884 result = ERROR_NOT_ENOUGH_MEMORY;
2885 goto cleanup;
2888 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2889 baseDirW.Buffer);
2891 if (result == ERROR_SUCCESS) {
2892 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2893 if (pcbData)
2894 *pcbData = cbData;
2897 cleanup:
2898 heap_free(pwszBuffer);
2899 RtlFreeUnicodeString(&baseDirW);
2900 RtlFreeUnicodeString(&valueW);
2902 return result;
2905 /******************************************************************************
2906 * RegDisablePredefinedCache [ADVAPI32.@]
2908 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2910 * PARAMS
2911 * None.
2913 * RETURNS
2914 * Success: ERROR_SUCCESS
2915 * Failure: nonzero error code from Winerror.h
2917 * NOTES
2918 * This is useful for services that use impersonation.
2920 LSTATUS WINAPI RegDisablePredefinedCache(void)
2922 HKEY hkey_current_user;
2923 int idx = HandleToUlong(HKEY_CURRENT_USER) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
2925 /* prevent caching of future requests */
2926 hkcu_cache_disabled = TRUE;
2928 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2930 if (hkey_current_user)
2931 NtClose( hkey_current_user );
2933 return ERROR_SUCCESS;
2936 /******************************************************************************
2937 * RegDeleteTreeW [ADVAPI32.@]
2940 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2942 LONG ret;
2943 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2944 DWORD dwMaxLen, dwSize;
2945 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2946 HKEY hSubKey = hKey;
2948 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2950 if(lpszSubKey)
2952 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2953 if (ret) return ret;
2956 /* Get highest length for keys, values */
2957 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2958 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2959 if (ret) goto cleanup;
2961 dwMaxSubkeyLen++;
2962 dwMaxValueLen++;
2963 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2964 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2966 /* Name too big: alloc a buffer for it */
2967 if (!(lpszName = heap_alloc( dwMaxLen*sizeof(WCHAR))))
2969 ret = ERROR_NOT_ENOUGH_MEMORY;
2970 goto cleanup;
2975 /* Recursively delete all the subkeys */
2976 while (TRUE)
2978 dwSize = dwMaxLen;
2979 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2980 NULL, NULL, NULL)) break;
2982 ret = RegDeleteTreeW(hSubKey, lpszName);
2983 if (ret) goto cleanup;
2986 if (lpszSubKey)
2987 ret = RegDeleteKeyW(hKey, lpszSubKey);
2988 else
2989 while (TRUE)
2991 dwSize = dwMaxLen;
2992 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2993 NULL, NULL, NULL, NULL)) break;
2995 ret = RegDeleteValueW(hKey, lpszName);
2996 if (ret) goto cleanup;
2999 cleanup:
3000 /* Free buffer if allocated */
3001 if (lpszName != szNameBuf)
3002 heap_free( lpszName);
3003 if(lpszSubKey)
3004 RegCloseKey(hSubKey);
3005 return ret;
3008 /******************************************************************************
3009 * RegDeleteTreeA [ADVAPI32.@]
3012 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
3014 LONG ret;
3015 UNICODE_STRING lpszSubKeyW;
3017 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
3018 else lpszSubKeyW.Buffer = NULL;
3019 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
3020 RtlFreeUnicodeString( &lpszSubKeyW );
3021 return ret;
3024 /******************************************************************************
3025 * RegDisableReflectionKey [ADVAPI32.@]
3028 LONG WINAPI RegDisableReflectionKey(HKEY base)
3030 FIXME("%p: stub\n", base);
3031 return ERROR_SUCCESS;