advapi32: Use STATUS_BUFFER_TOO_SMALL for buffer overflows in RegQueryInfoKeyW.
[wine/multimedia.git] / dlls / advapi32 / registry.c
blob633c0c4b99346acbf63498e7e8a76a6a479bf5a1
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 <stdlib.h>
27 #include <stdarg.h>
28 #include <stdio.h>
30 #include "ntstatus.h"
31 #define WIN32_NO_STATUS
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winreg.h"
35 #include "winerror.h"
36 #include "winternl.h"
37 #include "winuser.h"
38 #include "advapi32_misc.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(reg);
45 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
46 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
48 static const WCHAR name_CLASSES_ROOT[] =
49 {'M','a','c','h','i','n','e','\\',
50 'S','o','f','t','w','a','r','e','\\',
51 'C','l','a','s','s','e','s',0};
52 static const WCHAR name_LOCAL_MACHINE[] =
53 {'M','a','c','h','i','n','e',0};
54 static const WCHAR name_USERS[] =
55 {'U','s','e','r',0};
56 static const WCHAR name_PERFORMANCE_DATA[] =
57 {'P','e','r','f','D','a','t','a',0};
58 static const WCHAR name_CURRENT_CONFIG[] =
59 {'M','a','c','h','i','n','e','\\',
60 'S','y','s','t','e','m','\\',
61 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
62 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
63 'C','u','r','r','e','n','t',0};
64 static const WCHAR name_DYN_DATA[] =
65 {'D','y','n','D','a','t','a',0};
67 static const WCHAR * const root_key_names[] =
69 name_CLASSES_ROOT,
70 NULL, /* HKEY_CURRENT_USER is determined dynamically */
71 name_LOCAL_MACHINE,
72 name_USERS,
73 name_PERFORMANCE_DATA,
74 name_CURRENT_CONFIG,
75 name_DYN_DATA
78 #define NB_SPECIAL_ROOT_KEYS (sizeof(root_key_names)/sizeof(root_key_names[0]))
80 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
81 static BOOL hkcu_cache_disabled;
83 static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
85 /* check if value type needs string conversion (Ansi<->Unicode) */
86 static inline BOOL is_string( DWORD type )
88 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
91 /* check if current version is NT or Win95 */
92 static inline BOOL is_version_nt(void)
94 return !(GetVersion() & 0x80000000);
97 static BOOL is_wow6432node( const UNICODE_STRING *name )
99 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e'};
101 return (name->Length == sizeof(wow6432nodeW) &&
102 !memicmpW( name->Buffer, wow6432nodeW, sizeof(wow6432nodeW)/sizeof(WCHAR) ));
105 /* open the Wow6432Node subkey of the specified key */
106 static HANDLE open_wow6432node( HANDLE key )
108 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
109 OBJECT_ATTRIBUTES attr;
110 UNICODE_STRING nameW;
111 HANDLE ret;
113 attr.Length = sizeof(attr);
114 attr.RootDirectory = key;
115 attr.ObjectName = &nameW;
116 attr.Attributes = 0;
117 attr.SecurityDescriptor = NULL;
118 attr.SecurityQualityOfService = NULL;
119 RtlInitUnicodeString( &nameW, wow6432nodeW );
120 if (NtOpenKey( &ret, MAXIMUM_ALLOWED, &attr )) ret = 0;
121 return ret;
124 /* wrapper for NtCreateKey that creates the key recursively if necessary */
125 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
126 const UNICODE_STRING *class, ULONG options, PULONG dispos )
128 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
129 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
130 HANDLE subkey, root = attr->RootDirectory;
132 if (!force_wow32) status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos );
134 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
136 WCHAR *buffer = attr->ObjectName->Buffer;
137 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
138 UNICODE_STRING str;
140 while (i < len && buffer[i] != '\\') i++;
141 if (i == len && !force_wow32) return status;
143 attrs = attr->Attributes;
144 attr->ObjectName = &str;
146 for (;;)
148 str.Buffer = buffer + pos;
149 str.Length = (i - pos) * sizeof(WCHAR);
150 if (force_wow32 && pos)
152 if (is_wow6432node( &str )) force_wow32 = FALSE;
153 else if ((subkey = open_wow6432node( attr->RootDirectory )))
155 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
156 attr->RootDirectory = subkey;
157 force_wow32 = FALSE;
160 if (i == len)
162 attr->Attributes = attrs;
163 status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos );
165 else
167 attr->Attributes = attrs & ~OBJ_OPENLINK;
168 status = NtCreateKey( &subkey, access, attr, 0, class,
169 options & ~REG_OPTION_CREATE_LINK, dispos );
171 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
172 if (status) return status;
173 if (i == len) break;
174 attr->RootDirectory = subkey;
175 while (i < len && buffer[i] == '\\') i++;
176 pos = i;
177 while (i < len && buffer[i] != '\\') i++;
180 attr->RootDirectory = subkey;
181 if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory )))
183 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
184 attr->RootDirectory = subkey;
186 *retkey = attr->RootDirectory;
187 return status;
190 /* wrapper for NtOpenKey to handle Wow6432 nodes */
191 static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
193 NTSTATUS status;
194 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
195 HANDLE subkey, root = attr->RootDirectory;
196 WCHAR *buffer = attr->ObjectName->Buffer;
197 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
198 UNICODE_STRING str;
200 if (!force_wow32) return NtOpenKey( (HANDLE *)retkey, access, attr );
202 if (len && buffer[0] == '\\') return STATUS_OBJECT_PATH_INVALID;
203 while (i < len && buffer[i] != '\\') i++;
204 attrs = attr->Attributes;
205 attr->ObjectName = &str;
207 for (;;)
209 str.Buffer = buffer + pos;
210 str.Length = (i - pos) * sizeof(WCHAR);
211 if (force_wow32 && pos)
213 if (is_wow6432node( &str )) force_wow32 = FALSE;
214 else if ((subkey = open_wow6432node( attr->RootDirectory )))
216 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
217 attr->RootDirectory = subkey;
218 force_wow32 = FALSE;
221 if (i == len)
223 attr->Attributes = attrs;
224 status = NtOpenKey( &subkey, access, attr );
226 else
228 attr->Attributes = attrs & ~OBJ_OPENLINK;
229 status = NtOpenKey( &subkey, access, attr );
231 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
232 if (status) return status;
233 attr->RootDirectory = subkey;
234 if (i == len) break;
235 while (i < len && buffer[i] == '\\') i++;
236 pos = i;
237 while (i < len && buffer[i] != '\\') i++;
239 if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory )))
241 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
242 attr->RootDirectory = subkey;
244 *retkey = attr->RootDirectory;
245 return status;
248 /* create one of the HKEY_* special root keys */
249 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
251 HKEY ret = 0;
252 int idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
254 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CURRENT_USER))
256 if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
257 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
259 /* don't cache the key in the table if caching is disabled */
260 if (hkcu_cache_disabled)
261 return hkey;
263 else
265 OBJECT_ATTRIBUTES attr;
266 UNICODE_STRING name;
268 attr.Length = sizeof(attr);
269 attr.RootDirectory = 0;
270 attr.ObjectName = &name;
271 attr.Attributes = 0;
272 attr.SecurityDescriptor = NULL;
273 attr.SecurityQualityOfService = NULL;
274 RtlInitUnicodeString( &name, root_key_names[idx] );
275 if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0;
276 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
279 if (!(access & (KEY_WOW64_64KEY | KEY_WOW64_32KEY)))
281 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
282 ret = hkey;
283 else
284 NtClose( hkey ); /* somebody beat us to it */
286 else
287 ret = hkey;
288 return ret;
291 /* map the hkey from special root to normal key if necessary */
292 static inline HKEY get_special_root_hkey( HKEY hkey, REGSAM access )
294 HKEY ret = hkey;
296 if ((HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST))
297 && (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
299 REGSAM mask = 0;
301 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT))
302 mask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
304 if ((access & mask) ||
305 !(ret = special_root_keys[HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)]))
306 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED | (access & mask) );
308 return ret;
312 /******************************************************************************
313 * RegOverridePredefKey [ADVAPI32.@]
315 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
317 HKEY old_key;
318 int idx;
320 TRACE("(%p %p)\n", hkey, override);
322 if ((HandleToUlong(hkey) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST))
323 || (HandleToUlong(hkey) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
324 return ERROR_INVALID_PARAMETER;
325 idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
327 if (override)
329 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
330 GetCurrentProcess(), (HANDLE *)&override,
331 0, 0, DUPLICATE_SAME_ACCESS );
332 if (status) return RtlNtStatusToDosError( status );
335 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
336 if (old_key) NtClose( old_key );
337 return ERROR_SUCCESS;
341 /******************************************************************************
342 * RegCreateKeyExW [ADVAPI32.@]
344 * See RegCreateKeyExA.
346 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
347 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
348 PHKEY retkey, LPDWORD dispos )
350 OBJECT_ATTRIBUTES attr;
351 UNICODE_STRING nameW, classW;
353 if (reserved) return ERROR_INVALID_PARAMETER;
354 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
356 attr.Length = sizeof(attr);
357 attr.RootDirectory = hkey;
358 attr.ObjectName = &nameW;
359 attr.Attributes = 0;
360 attr.SecurityDescriptor = NULL;
361 attr.SecurityQualityOfService = NULL;
362 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
363 RtlInitUnicodeString( &nameW, name );
364 RtlInitUnicodeString( &classW, class );
366 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
370 /******************************************************************************
371 * RegCreateKeyExA [ADVAPI32.@]
373 * Open a registry key, creating it if it doesn't exist.
375 * PARAMS
376 * hkey [I] Handle of the parent registry key
377 * name [I] Name of the new key to open or create
378 * reserved [I] Reserved, pass 0
379 * class [I] The object type of the new key
380 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
381 * access [I] Access level desired
382 * sa [I] Security attributes for the key
383 * retkey [O] Destination for the resulting handle
384 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
386 * RETURNS
387 * Success: ERROR_SUCCESS.
388 * Failure: A standard Win32 error code. retkey remains untouched.
390 * FIXME
391 * MAXIMUM_ALLOWED in access mask not supported by server
393 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
394 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
395 PHKEY retkey, LPDWORD dispos )
397 OBJECT_ATTRIBUTES attr;
398 UNICODE_STRING classW;
399 ANSI_STRING nameA, classA;
400 NTSTATUS status;
402 if (reserved) return ERROR_INVALID_PARAMETER;
403 if (!is_version_nt())
405 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
406 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
408 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
410 attr.Length = sizeof(attr);
411 attr.RootDirectory = hkey;
412 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
413 attr.Attributes = 0;
414 attr.SecurityDescriptor = NULL;
415 attr.SecurityQualityOfService = NULL;
416 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
417 RtlInitAnsiString( &nameA, name );
418 RtlInitAnsiString( &classA, class );
420 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
421 &nameA, FALSE )))
423 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
425 status = create_key( retkey, access, &attr, &classW, options, dispos );
426 RtlFreeUnicodeString( &classW );
429 return RtlNtStatusToDosError( status );
433 /******************************************************************************
434 * RegCreateKeyW [ADVAPI32.@]
436 * Creates the specified reg key.
438 * PARAMS
439 * hKey [I] Handle to an open key.
440 * lpSubKey [I] Name of a key that will be opened or created.
441 * phkResult [O] Receives a handle to the opened or created key.
443 * RETURNS
444 * Success: ERROR_SUCCESS
445 * Failure: nonzero error code defined in Winerror.h
447 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
449 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
450 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
451 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
452 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
456 /******************************************************************************
457 * RegCreateKeyA [ADVAPI32.@]
459 * See RegCreateKeyW.
461 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
463 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
464 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
469 /******************************************************************************
470 * RegOpenKeyExW [ADVAPI32.@]
472 * See RegOpenKeyExA.
474 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
476 OBJECT_ATTRIBUTES attr;
477 UNICODE_STRING nameW;
479 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
480 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++;
482 if (!retkey) return ERROR_INVALID_PARAMETER;
483 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
485 attr.Length = sizeof(attr);
486 attr.RootDirectory = hkey;
487 attr.ObjectName = &nameW;
488 attr.Attributes = 0;
489 attr.SecurityDescriptor = NULL;
490 attr.SecurityQualityOfService = NULL;
491 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
492 RtlInitUnicodeString( &nameW, name );
493 return RtlNtStatusToDosError( open_key( retkey, access, &attr ) );
497 /******************************************************************************
498 * RegOpenKeyExA [ADVAPI32.@]
500 * Open a registry key.
502 * PARAMS
503 * hkey [I] Handle of open key
504 * name [I] Name of subkey to open
505 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
506 * access [I] Security access mask
507 * retkey [O] Handle to open key
509 * RETURNS
510 * Success: ERROR_SUCCESS
511 * Failure: A standard Win32 error code. retkey is set to 0.
513 * NOTES
514 * Unlike RegCreateKeyExA(), this function will not create the key if it
515 * does not exist.
517 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
519 OBJECT_ATTRIBUTES attr;
520 STRING nameA;
521 NTSTATUS status;
523 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
524 else
526 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
527 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++;
530 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
532 attr.Length = sizeof(attr);
533 attr.RootDirectory = hkey;
534 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
535 attr.Attributes = 0;
536 attr.SecurityDescriptor = NULL;
537 attr.SecurityQualityOfService = NULL;
538 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
540 RtlInitAnsiString( &nameA, name );
541 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
542 &nameA, FALSE )))
544 status = open_key( retkey, access, &attr );
546 return RtlNtStatusToDosError( status );
550 /******************************************************************************
551 * RegOpenKeyW [ADVAPI32.@]
553 * See RegOpenKeyA.
555 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
557 if (!retkey)
558 return ERROR_INVALID_PARAMETER;
560 if (!name || !*name)
562 *retkey = hkey;
563 return ERROR_SUCCESS;
565 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
569 /******************************************************************************
570 * RegOpenKeyA [ADVAPI32.@]
572 * Open a registry key.
574 * PARAMS
575 * hkey [I] Handle of parent key to open the new key under
576 * name [I] Name of the key under hkey to open
577 * retkey [O] Destination for the resulting Handle
579 * RETURNS
580 * Success: ERROR_SUCCESS
581 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
583 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
585 if (!retkey)
586 return ERROR_INVALID_PARAMETER;
588 if (!name || !*name)
590 *retkey = hkey;
591 return ERROR_SUCCESS;
593 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
597 /******************************************************************************
598 * RegOpenCurrentUser [ADVAPI32.@]
600 * Get a handle to the HKEY_CURRENT_USER key for the user
601 * the current thread is impersonating.
603 * PARAMS
604 * access [I] Desired access rights to the key
605 * retkey [O] Handle to the opened key
607 * RETURNS
608 * Success: ERROR_SUCCESS
609 * Failure: nonzero error code from Winerror.h
611 * FIXME
612 * This function is supposed to retrieve a handle to the
613 * HKEY_CURRENT_USER for the user the current thread is impersonating.
614 * Since Wine does not currently allow threads to impersonate other users,
615 * this stub should work fine.
617 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
619 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
624 /******************************************************************************
625 * RegEnumKeyExW [ADVAPI32.@]
627 * Enumerate subkeys of the specified open registry key.
629 * PARAMS
630 * hkey [I] Handle to key to enumerate
631 * index [I] Index of subkey to enumerate
632 * name [O] Buffer for subkey name
633 * name_len [O] Size of subkey buffer
634 * reserved [I] Reserved
635 * class [O] Buffer for class string
636 * class_len [O] Size of class buffer
637 * ft [O] Time key last written to
639 * RETURNS
640 * Success: ERROR_SUCCESS
641 * Failure: System error code. If there are no more subkeys available, the
642 * function returns ERROR_NO_MORE_ITEMS.
644 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
645 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
647 NTSTATUS status;
648 char buffer[256], *buf_ptr = buffer;
649 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
650 DWORD total_size;
652 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
653 name_len ? *name_len : 0, reserved, class, class_len, ft );
655 if (reserved) return ERROR_INVALID_PARAMETER;
656 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
658 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
659 buffer, sizeof(buffer), &total_size );
661 while (status == STATUS_BUFFER_OVERFLOW)
663 /* retry with a dynamically allocated buffer */
664 if (buf_ptr != buffer) heap_free( buf_ptr );
665 if (!(buf_ptr = heap_alloc( total_size )))
666 return ERROR_NOT_ENOUGH_MEMORY;
667 info = (KEY_NODE_INFORMATION *)buf_ptr;
668 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
669 buf_ptr, total_size, &total_size );
672 if (!status)
674 DWORD len = info->NameLength / sizeof(WCHAR);
675 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
677 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
679 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
680 status = STATUS_BUFFER_OVERFLOW;
681 else
683 *name_len = len;
684 memcpy( name, info->Name, info->NameLength );
685 name[len] = 0;
686 if (class_len)
688 *class_len = cls_len;
689 if (class)
691 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
692 class[cls_len] = 0;
698 if (buf_ptr != buffer) heap_free( buf_ptr );
699 return RtlNtStatusToDosError( status );
703 /******************************************************************************
704 * RegEnumKeyExA [ADVAPI32.@]
706 * See RegEnumKeyExW.
708 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
709 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
711 NTSTATUS status;
712 char buffer[256], *buf_ptr = buffer;
713 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
714 DWORD total_size;
716 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
717 name_len ? *name_len : 0, reserved, class, class_len, ft );
719 if (reserved) return ERROR_INVALID_PARAMETER;
720 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
722 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
723 buffer, sizeof(buffer), &total_size );
725 while (status == STATUS_BUFFER_OVERFLOW)
727 /* retry with a dynamically allocated buffer */
728 if (buf_ptr != buffer) heap_free( buf_ptr );
729 if (!(buf_ptr = heap_alloc( total_size )))
730 return ERROR_NOT_ENOUGH_MEMORY;
731 info = (KEY_NODE_INFORMATION *)buf_ptr;
732 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
733 buf_ptr, total_size, &total_size );
736 if (!status)
738 DWORD len, cls_len;
740 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
741 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
742 info->ClassLength );
743 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
745 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
746 status = STATUS_BUFFER_OVERFLOW;
747 else
749 *name_len = len;
750 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
751 name[len] = 0;
752 if (class_len)
754 *class_len = cls_len;
755 if (class)
757 RtlUnicodeToMultiByteN( class, cls_len, NULL,
758 (WCHAR *)(buf_ptr + info->ClassOffset),
759 info->ClassLength );
760 class[cls_len] = 0;
766 if (buf_ptr != buffer) heap_free( buf_ptr );
767 return RtlNtStatusToDosError( status );
771 /******************************************************************************
772 * RegEnumKeyW [ADVAPI32.@]
774 * Enumerates subkeys of the specified open reg key.
776 * PARAMS
777 * hKey [I] Handle to an open key.
778 * dwIndex [I] Index of the subkey of hKey to retrieve.
779 * lpName [O] Name of the subkey.
780 * cchName [I] Size of lpName in TCHARS.
782 * RETURNS
783 * Success: ERROR_SUCCESS
784 * Failure: system error code. If there are no more subkeys available, the
785 * function returns ERROR_NO_MORE_ITEMS.
787 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
789 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
793 /******************************************************************************
794 * RegEnumKeyA [ADVAPI32.@]
796 * See RegEnumKeyW.
798 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
800 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
804 /******************************************************************************
805 * RegQueryInfoKeyW [ADVAPI32.@]
807 * Retrieves information about the specified registry key.
809 * PARAMS
810 * hkey [I] Handle to key to query
811 * class [O] Buffer for class string
812 * class_len [O] Size of class string buffer
813 * reserved [I] Reserved
814 * subkeys [O] Buffer for number of subkeys
815 * max_subkey [O] Buffer for longest subkey name length
816 * max_class [O] Buffer for longest class string length
817 * values [O] Buffer for number of value entries
818 * max_value [O] Buffer for longest value name length
819 * max_data [O] Buffer for longest value data length
820 * security [O] Buffer for security descriptor length
821 * modif [O] Modification time
823 * RETURNS
824 * Success: ERROR_SUCCESS
825 * Failure: system error code.
827 * NOTES
828 * - win95 allows class to be valid and class_len to be NULL
829 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
830 * - both allow class to be NULL and class_len to be NULL
831 * (it's hard to test validity, so test !NULL instead)
833 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
834 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
835 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
836 LPDWORD security, FILETIME *modif )
838 NTSTATUS status;
839 char buffer[256], *buf_ptr = buffer;
840 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
841 DWORD total_size;
843 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
844 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
846 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
847 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
849 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
850 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
852 if (class)
854 /* retry with a dynamically allocated buffer */
855 while (status == STATUS_BUFFER_OVERFLOW)
857 if (buf_ptr != buffer) heap_free( buf_ptr );
858 if (!(buf_ptr = heap_alloc( total_size )))
859 return ERROR_NOT_ENOUGH_MEMORY;
860 info = (KEY_FULL_INFORMATION *)buf_ptr;
861 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
864 if (status) goto done;
866 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
868 status = STATUS_BUFFER_TOO_SMALL;
870 else
872 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
873 class[info->ClassLength/sizeof(WCHAR)] = 0;
876 else status = STATUS_SUCCESS;
878 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
879 if (subkeys) *subkeys = info->SubKeys;
880 if (max_subkey) *max_subkey = info->MaxNameLen;
881 if (max_class) *max_class = info->MaxClassLen;
882 if (values) *values = info->Values;
883 if (max_value) *max_value = info->MaxValueNameLen;
884 if (max_data) *max_data = info->MaxValueDataLen;
885 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
887 done:
888 if (buf_ptr != buffer) heap_free( buf_ptr );
889 return RtlNtStatusToDosError( status );
893 /******************************************************************************
894 * RegQueryMultipleValuesA [ADVAPI32.@]
896 * Retrieves the type and data for a list of value names associated with a key.
898 * PARAMS
899 * hKey [I] Handle to an open key.
900 * val_list [O] Array of VALENT structures that describes the entries.
901 * num_vals [I] Number of elements in val_list.
902 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
903 * ldwTotsize [I/O] Size of lpValueBuf.
905 * RETURNS
906 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
907 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
908 * bytes.
910 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
911 LPSTR lpValueBuf, LPDWORD ldwTotsize )
913 unsigned int i;
914 DWORD maxBytes = *ldwTotsize;
915 HRESULT status;
916 LPSTR bufptr = lpValueBuf;
917 *ldwTotsize = 0;
919 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
921 for(i=0; i < num_vals; ++i)
924 val_list[i].ve_valuelen=0;
925 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
926 if(status != ERROR_SUCCESS)
928 return status;
931 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
933 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
934 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
935 if(status != ERROR_SUCCESS)
937 return status;
940 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
942 bufptr += val_list[i].ve_valuelen;
945 *ldwTotsize += val_list[i].ve_valuelen;
947 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
951 /******************************************************************************
952 * RegQueryMultipleValuesW [ADVAPI32.@]
954 * See RegQueryMultipleValuesA.
956 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
957 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
959 unsigned int i;
960 DWORD maxBytes = *ldwTotsize;
961 HRESULT status;
962 LPSTR bufptr = (LPSTR)lpValueBuf;
963 *ldwTotsize = 0;
965 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
967 for(i=0; i < num_vals; ++i)
969 val_list[i].ve_valuelen=0;
970 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
971 if(status != ERROR_SUCCESS)
973 return status;
976 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
978 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
979 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
980 if(status != ERROR_SUCCESS)
982 return status;
985 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
987 bufptr += val_list[i].ve_valuelen;
990 *ldwTotsize += val_list[i].ve_valuelen;
992 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
995 /******************************************************************************
996 * RegQueryInfoKeyA [ADVAPI32.@]
998 * Retrieves information about a registry key.
1000 * PARAMS
1001 * hKey [I] Handle to an open key.
1002 * lpClass [O] Class string of the key.
1003 * lpcClass [I/O] size of lpClass.
1004 * lpReserved [I] Reserved; must be NULL.
1005 * lpcSubKeys [O] Number of subkeys contained by the key.
1006 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
1007 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
1008 * class in TCHARS.
1009 * lpcValues [O] Number of values associated with the key.
1010 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
1011 * lpcMaxValueLen [O] Longest data component among the key's values
1012 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
1013 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
1015 * RETURNS
1016 * Success: ERROR_SUCCESS
1017 * Failure: nonzero error code from Winerror.h
1019 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
1020 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
1021 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
1022 LPDWORD security, FILETIME *modif )
1024 NTSTATUS status;
1025 char buffer[256], *buf_ptr = buffer;
1026 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
1027 DWORD total_size, len;
1029 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
1030 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
1032 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
1033 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1035 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
1036 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1038 if (class || class_len)
1040 /* retry with a dynamically allocated buffer */
1041 while (status == STATUS_BUFFER_OVERFLOW)
1043 if (buf_ptr != buffer) heap_free( buf_ptr );
1044 if (!(buf_ptr = heap_alloc( total_size )))
1045 return ERROR_NOT_ENOUGH_MEMORY;
1046 info = (KEY_FULL_INFORMATION *)buf_ptr;
1047 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
1050 if (status) goto done;
1052 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
1053 if (class_len)
1055 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
1056 *class_len = len;
1058 if (class && !status)
1060 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
1061 info->ClassLength );
1062 class[len] = 0;
1065 else status = STATUS_SUCCESS;
1067 if (subkeys) *subkeys = info->SubKeys;
1068 if (max_subkey) *max_subkey = info->MaxNameLen;
1069 if (max_class) *max_class = info->MaxClassLen;
1070 if (values) *values = info->Values;
1071 if (max_value) *max_value = info->MaxValueNameLen;
1072 if (max_data) *max_data = info->MaxValueDataLen;
1073 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
1075 done:
1076 if (buf_ptr != buffer) heap_free( buf_ptr );
1077 return RtlNtStatusToDosError( status );
1081 /******************************************************************************
1082 * RegCloseKey [ADVAPI32.@]
1084 * Close an open registry key.
1086 * PARAMS
1087 * hkey [I] Handle of key to close
1089 * RETURNS
1090 * Success: ERROR_SUCCESS
1091 * Failure: Error code
1093 LSTATUS WINAPI RegCloseKey( HKEY hkey )
1095 if (!hkey) return ERROR_INVALID_HANDLE;
1096 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
1097 return RtlNtStatusToDosError( NtClose( hkey ) );
1101 /******************************************************************************
1102 * RegDeleteKeyExW [ADVAPI32.@]
1104 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
1106 DWORD ret;
1107 HKEY tmp;
1109 if (!name) return ERROR_INVALID_PARAMETER;
1111 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
1113 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1114 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
1116 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1117 RegCloseKey( tmp );
1119 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
1120 return ret;
1124 /******************************************************************************
1125 * RegDeleteKeyW [ADVAPI32.@]
1127 * See RegDeleteKeyA.
1129 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
1131 return RegDeleteKeyExW( hkey, name, 0, 0 );
1135 /******************************************************************************
1136 * RegDeleteKeyExA [ADVAPI32.@]
1138 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1140 DWORD ret;
1141 HKEY tmp;
1143 if (!name) return ERROR_INVALID_PARAMETER;
1145 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
1147 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1148 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1150 if (!is_version_nt()) /* win95 does recursive key deletes */
1152 CHAR sub[MAX_PATH];
1154 while(!RegEnumKeyA(tmp, 0, sub, sizeof(sub)))
1156 if(RegDeleteKeyExA(tmp, sub, access, reserved)) /* recurse */
1157 break;
1160 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1161 RegCloseKey( tmp );
1163 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1164 return ret;
1168 /******************************************************************************
1169 * RegDeleteKeyA [ADVAPI32.@]
1171 * Delete a registry key.
1173 * PARAMS
1174 * hkey [I] Handle to parent key containing the key to delete
1175 * name [I] Name of the key user hkey to delete
1177 * NOTES
1179 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1180 * right. In reality, it opens a new handle with DELETE access.
1182 * RETURNS
1183 * Success: ERROR_SUCCESS
1184 * Failure: Error code
1186 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1188 return RegDeleteKeyExA( hkey, name, 0, 0 );
1193 /******************************************************************************
1194 * RegSetValueExW [ADVAPI32.@]
1196 * Set the data and contents of a registry value.
1198 * PARAMS
1199 * hkey [I] Handle of key to set value for
1200 * name [I] Name of value to set
1201 * reserved [I] Reserved, must be zero
1202 * type [I] Type of the value being set
1203 * data [I] The new contents of the value to set
1204 * count [I] Size of data
1206 * RETURNS
1207 * Success: ERROR_SUCCESS
1208 * Failure: Error code
1210 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1211 DWORD type, const BYTE *data, DWORD count )
1213 UNICODE_STRING nameW;
1215 /* no need for version check, not implemented on win9x anyway */
1217 if ((data && ((ULONG_PTR)data >> 16) == 0) || (!data && count)) return ERROR_NOACCESS;
1219 if (count && is_string(type))
1221 LPCWSTR str = (LPCWSTR)data;
1222 /* if user forgot to count terminating null, add it (yes NT does this) */
1223 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1224 count += sizeof(WCHAR);
1226 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1228 RtlInitUnicodeString( &nameW, name );
1229 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1233 /******************************************************************************
1234 * RegSetValueExA [ADVAPI32.@]
1236 * See RegSetValueExW.
1238 * NOTES
1239 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1240 * NT does definitely care (aj)
1242 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1243 const BYTE *data, DWORD count )
1245 ANSI_STRING nameA;
1246 UNICODE_STRING nameW;
1247 WCHAR *dataW = NULL;
1248 NTSTATUS status;
1250 if (!is_version_nt()) /* win95 */
1252 if (type == REG_SZ)
1254 if (!data) return ERROR_INVALID_PARAMETER;
1255 count = strlen((const char *)data) + 1;
1258 else if (count && is_string(type))
1260 /* if user forgot to count terminating null, add it (yes NT does this) */
1261 if (data[count-1] && !data[count]) count++;
1264 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1266 if (is_string( type )) /* need to convert to Unicode */
1268 DWORD lenW;
1269 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1270 if (!(dataW = heap_alloc( lenW ))) return ERROR_OUTOFMEMORY;
1271 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1272 count = lenW;
1273 data = (BYTE *)dataW;
1276 RtlInitAnsiString( &nameA, name );
1277 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1279 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1280 RtlFreeUnicodeString( &nameW );
1282 heap_free( dataW );
1283 return RtlNtStatusToDosError( status );
1287 /******************************************************************************
1288 * RegSetValueW [ADVAPI32.@]
1290 * Sets the data for the default or unnamed value of a reg key.
1292 * PARAMS
1293 * hkey [I] Handle to an open key.
1294 * subkey [I] Name of a subkey of hKey.
1295 * type [I] Type of information to store.
1296 * data [I] String that contains the data to set for the default value.
1297 * count [I] Ignored.
1299 * RETURNS
1300 * Success: ERROR_SUCCESS
1301 * Failure: nonzero error code from Winerror.h
1303 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR subkey, DWORD type, LPCWSTR data, DWORD count )
1305 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(subkey), type, debugstr_w(data), count );
1307 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1309 return RegSetKeyValueW( hkey, subkey, NULL, type, data, (strlenW(data) + 1)*sizeof(WCHAR) );
1312 /******************************************************************************
1313 * RegSetValueA [ADVAPI32.@]
1315 * See RegSetValueW.
1317 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR subkey, DWORD type, LPCSTR data, DWORD count )
1319 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(subkey), type, debugstr_a(data), count );
1321 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1323 return RegSetKeyValueA( hkey, subkey, NULL, type, data, strlen(data) + 1 );
1326 /******************************************************************************
1327 * RegSetKeyValueW [ADVAPI32.@]
1329 LONG WINAPI RegSetKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name, DWORD type, const void *data, DWORD len )
1331 HKEY hsubkey = NULL;
1332 DWORD ret;
1334 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey, debugstr_w(subkey), debugstr_w(name), type, data, len );
1336 if (subkey && subkey[0]) /* need to create the subkey */
1338 if ((ret = RegCreateKeyW( hkey, subkey, &hsubkey )) != ERROR_SUCCESS) return ret;
1339 hkey = hsubkey;
1342 ret = RegSetValueExW( hkey, name, 0, type, (const BYTE*)data, len );
1343 if (hsubkey) RegCloseKey( hsubkey );
1344 return ret;
1347 /******************************************************************************
1348 * RegSetKeyValueA [ADVAPI32.@]
1350 LONG WINAPI RegSetKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name, DWORD type, const void *data, DWORD len )
1352 HKEY hsubkey = NULL;
1353 DWORD ret;
1355 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey, debugstr_a(subkey), debugstr_a(name), type, data, len );
1357 if (subkey && subkey[0]) /* need to create the subkey */
1359 if ((ret = RegCreateKeyA( hkey, subkey, &hsubkey )) != ERROR_SUCCESS) return ret;
1360 hkey = hsubkey;
1363 ret = RegSetValueExA( hkey, name, 0, type, (const BYTE*)data, len );
1364 if (hsubkey) RegCloseKey( hsubkey );
1365 return ret;
1368 /******************************************************************************
1369 * RegQueryValueExW [ADVAPI32.@]
1371 * See RegQueryValueExA.
1373 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1374 LPBYTE data, LPDWORD count )
1376 NTSTATUS status;
1377 UNICODE_STRING name_str;
1378 DWORD total_size;
1379 char buffer[256], *buf_ptr = buffer;
1380 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1381 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1383 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1384 hkey, debugstr_w(name), reserved, type, data, count,
1385 (count && data) ? *count : 0 );
1387 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1388 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1390 RtlInitUnicodeString( &name_str, name );
1392 if (data) total_size = min( sizeof(buffer), *count + info_size );
1393 else
1395 total_size = info_size;
1396 if (count) *count = 0;
1399 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1400 buffer, total_size, &total_size );
1401 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1403 if (data)
1405 /* retry with a dynamically allocated buffer */
1406 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1408 if (buf_ptr != buffer) heap_free( buf_ptr );
1409 if (!(buf_ptr = heap_alloc( total_size )))
1410 return ERROR_NOT_ENOUGH_MEMORY;
1411 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1412 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1413 buf_ptr, total_size, &total_size );
1416 if (!status)
1418 memcpy( data, buf_ptr + info_size, total_size - info_size );
1419 /* if the type is REG_SZ and data is not 0-terminated
1420 * and there is enough space in the buffer NT appends a \0 */
1421 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1423 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1424 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1427 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1429 else status = STATUS_SUCCESS;
1431 if (type) *type = info->Type;
1432 if (count) *count = total_size - info_size;
1434 done:
1435 if (buf_ptr != buffer) heap_free( buf_ptr );
1436 return RtlNtStatusToDosError(status);
1440 /******************************************************************************
1441 * RegQueryValueExA [ADVAPI32.@]
1443 * Get the type and contents of a specified value under with a key.
1445 * PARAMS
1446 * hkey [I] Handle of the key to query
1447 * name [I] Name of value under hkey to query
1448 * reserved [I] Reserved - must be NULL
1449 * type [O] Destination for the value type, or NULL if not required
1450 * data [O] Destination for the values contents, or NULL if not required
1451 * count [I/O] Size of data, updated with the number of bytes returned
1453 * RETURNS
1454 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1455 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1456 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1457 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1459 * NOTES
1460 * MSDN states that if data is too small it is partially filled. In reality
1461 * it remains untouched.
1463 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1464 LPBYTE data, LPDWORD count )
1466 NTSTATUS status;
1467 ANSI_STRING nameA;
1468 UNICODE_STRING nameW;
1469 DWORD total_size, datalen = 0;
1470 char buffer[256], *buf_ptr = buffer;
1471 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1472 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1474 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1475 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1477 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1478 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1480 if (count) datalen = *count;
1481 if (!data && count) *count = 0;
1483 /* this matches Win9x behaviour - NT sets *type to a random value */
1484 if (type) *type = REG_NONE;
1486 RtlInitAnsiString( &nameA, name );
1487 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1488 return RtlNtStatusToDosError(status);
1490 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1491 buffer, sizeof(buffer), &total_size );
1492 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1494 /* we need to fetch the contents for a string type even if not requested,
1495 * because we need to compute the length of the ASCII string. */
1496 if (data || is_string(info->Type))
1498 /* retry with a dynamically allocated buffer */
1499 while (status == STATUS_BUFFER_OVERFLOW)
1501 if (buf_ptr != buffer) heap_free( buf_ptr );
1502 if (!(buf_ptr = heap_alloc( total_size )))
1504 status = STATUS_NO_MEMORY;
1505 goto done;
1507 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1508 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1509 buf_ptr, total_size, &total_size );
1512 if (status) goto done;
1514 if (is_string(info->Type))
1516 DWORD len;
1518 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1519 total_size - info_size );
1520 if (data && len)
1522 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1523 else
1525 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1526 total_size - info_size );
1527 /* if the type is REG_SZ and data is not 0-terminated
1528 * and there is enough space in the buffer NT appends a \0 */
1529 if (len < datalen && data[len-1]) data[len] = 0;
1532 total_size = len + info_size;
1534 else if (data)
1536 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1537 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1540 else status = STATUS_SUCCESS;
1542 if (type) *type = info->Type;
1543 if (count) *count = total_size - info_size;
1545 done:
1546 if (buf_ptr != buffer) heap_free( buf_ptr );
1547 RtlFreeUnicodeString( &nameW );
1548 return RtlNtStatusToDosError(status);
1552 /******************************************************************************
1553 * RegQueryValueW [ADVAPI32.@]
1555 * Retrieves the data associated with the default or unnamed value of a key.
1557 * PARAMS
1558 * hkey [I] Handle to an open key.
1559 * name [I] Name of the subkey of hKey.
1560 * data [O] Receives the string associated with the default value
1561 * of the key.
1562 * count [I/O] Size of lpValue in bytes.
1564 * RETURNS
1565 * Success: ERROR_SUCCESS
1566 * Failure: nonzero error code from Winerror.h
1568 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1570 DWORD ret;
1571 HKEY subkey = hkey;
1573 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1575 if (name && name[0])
1577 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1579 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1580 if (subkey != hkey) RegCloseKey( subkey );
1581 if (ret == ERROR_FILE_NOT_FOUND)
1583 /* return empty string if default value not found */
1584 if (data) *data = 0;
1585 if (count) *count = sizeof(WCHAR);
1586 ret = ERROR_SUCCESS;
1588 return ret;
1592 /******************************************************************************
1593 * RegQueryValueA [ADVAPI32.@]
1595 * See RegQueryValueW.
1597 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1599 DWORD ret;
1600 HKEY subkey = hkey;
1602 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1604 if (name && name[0])
1606 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1608 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1609 if (subkey != hkey) RegCloseKey( subkey );
1610 if (ret == ERROR_FILE_NOT_FOUND)
1612 /* return empty string if default value not found */
1613 if (data) *data = 0;
1614 if (count) *count = 1;
1615 ret = ERROR_SUCCESS;
1617 return ret;
1621 /******************************************************************************
1622 * ADVAPI_ApplyRestrictions [internal]
1624 * Helper function for RegGetValueA/W.
1626 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1627 DWORD cbData, PLONG ret )
1629 /* Check if the type is restricted by the passed flags */
1630 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1632 DWORD dwMask = 0;
1634 switch (dwType)
1636 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1637 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1638 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1639 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1640 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1641 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1642 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1645 if (dwFlags & dwMask)
1647 /* Type is not restricted, check for size mismatch */
1648 if (dwType == REG_BINARY)
1650 DWORD cbExpect = 0;
1652 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1653 cbExpect = 4;
1654 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1655 cbExpect = 8;
1657 if (cbExpect && cbData != cbExpect)
1658 *ret = ERROR_DATATYPE_MISMATCH;
1661 else *ret = ERROR_UNSUPPORTED_TYPE;
1666 /******************************************************************************
1667 * RegGetValueW [ADVAPI32.@]
1669 * Retrieves the type and data for a value name associated with a key,
1670 * optionally expanding its content and restricting its type.
1672 * PARAMS
1673 * hKey [I] Handle to an open key.
1674 * pszSubKey [I] Name of the subkey of hKey.
1675 * pszValue [I] Name of value under hKey/szSubKey to query.
1676 * dwFlags [I] Flags restricting the value type to retrieve.
1677 * pdwType [O] Destination for the values type, may be NULL.
1678 * pvData [O] Destination for the values content, may be NULL.
1679 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1680 * retrieve the whole content, including the trailing '\0'
1681 * for strings.
1683 * RETURNS
1684 * Success: ERROR_SUCCESS
1685 * Failure: nonzero error code from Winerror.h
1687 * NOTES
1688 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1689 * expanded and pdwType is set to REG_SZ instead.
1690 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1691 * without RRF_NOEXPAND is thus not allowed.
1692 * An exception is the case where RRF_RT_ANY is specified, because then
1693 * RRF_NOEXPAND is allowed.
1695 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1696 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1697 LPDWORD pcbData )
1699 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1700 PVOID pvBuf = NULL;
1701 LONG ret;
1703 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1704 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1705 pvData, pcbData, cbData);
1707 if (pvData && !pcbData)
1708 return ERROR_INVALID_PARAMETER;
1709 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1710 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1711 return ERROR_INVALID_PARAMETER;
1713 if (pszSubKey && pszSubKey[0])
1715 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1716 if (ret != ERROR_SUCCESS) return ret;
1719 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1721 /* If we are going to expand we need to read in the whole the value even
1722 * if the passed buffer was too small as the expanded string might be
1723 * smaller than the unexpanded one and could fit into cbData bytes. */
1724 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1725 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1727 do {
1728 heap_free(pvBuf);
1730 pvBuf = heap_alloc(cbData);
1731 if (!pvBuf)
1733 ret = ERROR_NOT_ENOUGH_MEMORY;
1734 break;
1737 if (ret == ERROR_MORE_DATA || !pvData)
1738 ret = RegQueryValueExW(hKey, pszValue, NULL,
1739 &dwType, pvBuf, &cbData);
1740 else
1742 /* Even if cbData was large enough we have to copy the
1743 * string since ExpandEnvironmentStrings can't handle
1744 * overlapping buffers. */
1745 CopyMemory(pvBuf, pvData, cbData);
1748 /* Both the type or the value itself could have been modified in
1749 * between so we have to keep retrying until the buffer is large
1750 * enough or we no longer have to expand the value. */
1751 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1753 if (ret == ERROR_SUCCESS)
1755 /* Recheck dwType in case it changed since the first call */
1756 if (dwType == REG_EXPAND_SZ)
1758 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1759 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1760 dwType = REG_SZ;
1761 if(pvData && pcbData && cbData > *pcbData)
1762 ret = ERROR_MORE_DATA;
1764 else if (pvData)
1765 CopyMemory(pvData, pvBuf, *pcbData);
1768 heap_free(pvBuf);
1771 if (pszSubKey && pszSubKey[0])
1772 RegCloseKey(hKey);
1774 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1776 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1777 ZeroMemory(pvData, *pcbData);
1779 if (pdwType) *pdwType = dwType;
1780 if (pcbData) *pcbData = cbData;
1782 return ret;
1786 /******************************************************************************
1787 * RegGetValueA [ADVAPI32.@]
1789 * See RegGetValueW.
1791 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1792 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1793 LPDWORD pcbData )
1795 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1796 PVOID pvBuf = NULL;
1797 LONG ret;
1799 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1800 hKey, debugstr_a(pszSubKey), debugstr_a(pszValue), dwFlags,
1801 pdwType, pvData, pcbData, cbData);
1803 if (pvData && !pcbData)
1804 return ERROR_INVALID_PARAMETER;
1805 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1806 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1807 return ERROR_INVALID_PARAMETER;
1809 if (pszSubKey && pszSubKey[0])
1811 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1812 if (ret != ERROR_SUCCESS) return ret;
1815 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1817 /* If we are going to expand we need to read in the whole the value even
1818 * if the passed buffer was too small as the expanded string might be
1819 * smaller than the unexpanded one and could fit into cbData bytes. */
1820 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1821 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1823 do {
1824 heap_free(pvBuf);
1826 pvBuf = heap_alloc(cbData);
1827 if (!pvBuf)
1829 ret = ERROR_NOT_ENOUGH_MEMORY;
1830 break;
1833 if (ret == ERROR_MORE_DATA || !pvData)
1834 ret = RegQueryValueExA(hKey, pszValue, NULL,
1835 &dwType, pvBuf, &cbData);
1836 else
1838 /* Even if cbData was large enough we have to copy the
1839 * string since ExpandEnvironmentStrings can't handle
1840 * overlapping buffers. */
1841 CopyMemory(pvBuf, pvData, cbData);
1844 /* Both the type or the value itself could have been modified in
1845 * between so we have to keep retrying until the buffer is large
1846 * enough or we no longer have to expand the value. */
1847 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1849 if (ret == ERROR_SUCCESS)
1851 /* Recheck dwType in case it changed since the first call */
1852 if (dwType == REG_EXPAND_SZ)
1854 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1855 pcbData ? *pcbData : 0);
1856 dwType = REG_SZ;
1857 if(pvData && pcbData && cbData > *pcbData)
1858 ret = ERROR_MORE_DATA;
1860 else if (pvData)
1861 CopyMemory(pvData, pvBuf, *pcbData);
1864 heap_free(pvBuf);
1867 if (pszSubKey && pszSubKey[0])
1868 RegCloseKey(hKey);
1870 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1872 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1873 ZeroMemory(pvData, *pcbData);
1875 if (pdwType) *pdwType = dwType;
1876 if (pcbData) *pcbData = cbData;
1878 return ret;
1882 /******************************************************************************
1883 * RegEnumValueW [ADVAPI32.@]
1885 * Enumerates the values for the specified open registry key.
1887 * PARAMS
1888 * hkey [I] Handle to key to query
1889 * index [I] Index of value to query
1890 * value [O] Value string
1891 * val_count [I/O] Size of value buffer (in wchars)
1892 * reserved [I] Reserved
1893 * type [O] Type code
1894 * data [O] Value data
1895 * count [I/O] Size of data buffer (in bytes)
1897 * RETURNS
1898 * Success: ERROR_SUCCESS
1899 * Failure: nonzero error code from Winerror.h
1902 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1903 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1905 NTSTATUS status;
1906 DWORD total_size;
1907 char buffer[256], *buf_ptr = buffer;
1908 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1909 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1911 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1912 hkey, index, value, val_count, reserved, type, data, count );
1914 /* NT only checks count, not val_count */
1915 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1916 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1918 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1919 if (data) total_size += *count;
1920 total_size = min( sizeof(buffer), total_size );
1922 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1923 buffer, total_size, &total_size );
1924 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1926 if (value || data)
1928 /* retry with a dynamically allocated buffer */
1929 while (status == STATUS_BUFFER_OVERFLOW)
1931 if (buf_ptr != buffer) heap_free( buf_ptr );
1932 if (!(buf_ptr = heap_alloc( total_size )))
1933 return ERROR_NOT_ENOUGH_MEMORY;
1934 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1935 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1936 buf_ptr, total_size, &total_size );
1939 if (status) goto done;
1941 if (value)
1943 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1945 status = STATUS_BUFFER_OVERFLOW;
1946 goto overflow;
1948 memcpy( value, info->Name, info->NameLength );
1949 *val_count = info->NameLength / sizeof(WCHAR);
1950 value[*val_count] = 0;
1953 if (data)
1955 if (total_size - info->DataOffset > *count)
1957 status = STATUS_BUFFER_OVERFLOW;
1958 goto overflow;
1960 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1961 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1963 /* if the type is REG_SZ and data is not 0-terminated
1964 * and there is enough space in the buffer NT appends a \0 */
1965 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1966 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1970 else status = STATUS_SUCCESS;
1972 overflow:
1973 if (type) *type = info->Type;
1974 if (count) *count = info->DataLength;
1976 done:
1977 if (buf_ptr != buffer) heap_free( buf_ptr );
1978 return RtlNtStatusToDosError(status);
1982 /******************************************************************************
1983 * RegEnumValueA [ADVAPI32.@]
1985 * See RegEnumValueW.
1987 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1988 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1990 NTSTATUS status;
1991 DWORD total_size;
1992 char buffer[256], *buf_ptr = buffer;
1993 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1994 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1996 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1997 hkey, index, value, val_count, reserved, type, data, count );
1999 /* NT only checks count, not val_count */
2000 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
2001 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2003 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2004 if (data) total_size += *count;
2005 total_size = min( sizeof(buffer), total_size );
2007 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
2008 buffer, total_size, &total_size );
2009 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
2011 /* we need to fetch the contents for a string type even if not requested,
2012 * because we need to compute the length of the ASCII string. */
2013 if (value || data || is_string(info->Type))
2015 /* retry with a dynamically allocated buffer */
2016 while (status == STATUS_BUFFER_OVERFLOW)
2018 if (buf_ptr != buffer) heap_free( buf_ptr );
2019 if (!(buf_ptr = heap_alloc( total_size )))
2020 return ERROR_NOT_ENOUGH_MEMORY;
2021 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2022 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
2023 buf_ptr, total_size, &total_size );
2026 if (status) goto done;
2028 if (is_string(info->Type))
2030 DWORD len;
2031 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
2032 total_size - info->DataOffset );
2033 if (data && len)
2035 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
2036 else
2038 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
2039 total_size - info->DataOffset );
2040 /* if the type is REG_SZ and data is not 0-terminated
2041 * and there is enough space in the buffer NT appends a \0 */
2042 if (len < *count && data[len-1]) data[len] = 0;
2045 info->DataLength = len;
2047 else if (data)
2049 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
2050 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2053 if (value && !status)
2055 DWORD len;
2057 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2058 if (len >= *val_count)
2060 status = STATUS_BUFFER_OVERFLOW;
2061 if (*val_count)
2063 len = *val_count - 1;
2064 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2065 value[len] = 0;
2068 else
2070 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2071 value[len] = 0;
2072 *val_count = len;
2076 else status = STATUS_SUCCESS;
2078 if (type) *type = info->Type;
2079 if (count) *count = info->DataLength;
2081 done:
2082 if (buf_ptr != buffer) heap_free( buf_ptr );
2083 return RtlNtStatusToDosError(status);
2086 /******************************************************************************
2087 * RegDeleteValueW [ADVAPI32.@]
2089 * See RegDeleteValueA.
2091 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2093 return RegDeleteKeyValueW( hkey, NULL, name );
2096 /******************************************************************************
2097 * RegDeleteValueA [ADVAPI32.@]
2099 * Delete a value from the registry.
2101 * PARAMS
2102 * hkey [I] Registry handle of the key holding the value
2103 * name [I] Name of the value under hkey to delete
2105 * RETURNS
2106 * Success: ERROR_SUCCESS
2107 * Failure: nonzero error code from Winerror.h
2109 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2111 return RegDeleteKeyValueA( hkey, NULL, name );
2114 /******************************************************************************
2115 * RegDeleteKeyValueW [ADVAPI32.@]
2117 LONG WINAPI RegDeleteKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name )
2119 UNICODE_STRING nameW;
2120 HKEY hsubkey = 0;
2121 LONG ret;
2123 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2125 if (subkey)
2127 if ((ret = RegOpenKeyExW( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey )))
2128 return ret;
2129 hkey = hsubkey;
2132 RtlInitUnicodeString( &nameW, name );
2133 ret = RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2134 if (hsubkey) RegCloseKey( hsubkey );
2135 return ret;
2138 /******************************************************************************
2139 * RegDeleteKeyValueA [ADVAPI32.@]
2141 LONG WINAPI RegDeleteKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name )
2143 UNICODE_STRING nameW;
2144 HKEY hsubkey = 0;
2145 ANSI_STRING nameA;
2146 NTSTATUS status;
2148 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2150 if (subkey)
2152 LONG ret = RegOpenKeyExA( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey );
2153 if (ret)
2154 return ret;
2155 hkey = hsubkey;
2158 RtlInitAnsiString( &nameA, name );
2159 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2161 status = NtDeleteValueKey( hkey, &nameW );
2162 RtlFreeUnicodeString( &nameW );
2165 if (hsubkey) RegCloseKey( hsubkey );
2166 return RtlNtStatusToDosError( status );
2169 /******************************************************************************
2170 * RegLoadKeyW [ADVAPI32.@]
2172 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2173 * registration information from a specified file into that subkey.
2175 * PARAMS
2176 * hkey [I] Handle of open key
2177 * subkey [I] Address of name of subkey
2178 * filename [I] Address of filename for registry information
2180 * RETURNS
2181 * Success: ERROR_SUCCESS
2182 * Failure: nonzero error code from Winerror.h
2184 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2186 OBJECT_ATTRIBUTES destkey, file;
2187 UNICODE_STRING subkeyW, filenameW;
2188 NTSTATUS status;
2190 if (!(hkey = get_special_root_hkey(hkey, 0))) return ERROR_INVALID_HANDLE;
2192 destkey.Length = sizeof(destkey);
2193 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2194 destkey.ObjectName = &subkeyW; /* name of the key */
2195 destkey.Attributes = 0;
2196 destkey.SecurityDescriptor = NULL;
2197 destkey.SecurityQualityOfService = NULL;
2198 RtlInitUnicodeString(&subkeyW, subkey);
2200 file.Length = sizeof(file);
2201 file.RootDirectory = NULL;
2202 file.ObjectName = &filenameW; /* file containing the hive */
2203 file.Attributes = OBJ_CASE_INSENSITIVE;
2204 file.SecurityDescriptor = NULL;
2205 file.SecurityQualityOfService = NULL;
2206 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2208 status = NtLoadKey(&destkey, &file);
2209 RtlFreeUnicodeString(&filenameW);
2210 return RtlNtStatusToDosError( status );
2214 /******************************************************************************
2215 * RegLoadKeyA [ADVAPI32.@]
2217 * See RegLoadKeyW.
2219 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2221 UNICODE_STRING subkeyW, filenameW;
2222 STRING subkeyA, filenameA;
2223 NTSTATUS status;
2224 LONG ret;
2226 RtlInitAnsiString(&subkeyA, subkey);
2227 RtlInitAnsiString(&filenameA, filename);
2229 RtlInitUnicodeString(&subkeyW, NULL);
2230 RtlInitUnicodeString(&filenameW, NULL);
2231 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2232 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2234 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2236 else ret = RtlNtStatusToDosError(status);
2237 RtlFreeUnicodeString(&subkeyW);
2238 RtlFreeUnicodeString(&filenameW);
2239 return ret;
2243 /******************************************************************************
2244 * RegSaveKeyW [ADVAPI32.@]
2246 * Save a key and all of its subkeys and values to a new file in the standard format.
2248 * PARAMS
2249 * hkey [I] Handle of key where save begins
2250 * lpFile [I] Address of filename to save to
2251 * sa [I] Address of security structure
2253 * RETURNS
2254 * Success: ERROR_SUCCESS
2255 * Failure: nonzero error code from Winerror.h
2257 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2259 static const WCHAR format[] =
2260 {'r','e','g','%','0','4','x','.','t','m','p',0};
2261 WCHAR buffer[MAX_PATH];
2262 int count = 0;
2263 LPWSTR nameW;
2264 DWORD ret, err;
2265 HANDLE handle;
2267 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2269 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2270 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2272 err = GetLastError();
2273 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2275 for (;;)
2277 snprintfW( nameW, 16, format, count++ );
2278 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2279 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2280 if (handle != INVALID_HANDLE_VALUE) break;
2281 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2283 /* Something gone haywire ? Please report if this happens abnormally */
2284 if (count >= 100)
2285 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);
2288 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2290 CloseHandle( handle );
2291 if (!ret)
2293 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2295 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2296 debugstr_w(file) );
2297 ret = GetLastError();
2300 if (ret) DeleteFileW( buffer );
2302 done:
2303 SetLastError( err ); /* restore last error code */
2304 return ret;
2308 /******************************************************************************
2309 * RegSaveKeyA [ADVAPI32.@]
2311 * See RegSaveKeyW.
2313 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2315 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2316 NTSTATUS status;
2317 STRING fileA;
2319 RtlInitAnsiString(&fileA, file);
2320 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2321 return RtlNtStatusToDosError( status );
2322 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2326 /******************************************************************************
2327 * RegRestoreKeyW [ADVAPI32.@]
2329 * Read the registry information from a file and copy it over a key.
2331 * PARAMS
2332 * hkey [I] Handle of key where restore begins
2333 * lpFile [I] Address of filename containing saved tree
2334 * dwFlags [I] Optional flags
2336 * RETURNS
2337 * Success: ERROR_SUCCESS
2338 * Failure: nonzero error code from Winerror.h
2340 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2342 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2344 /* It seems to do this check before the hkey check */
2345 if (!lpFile || !*lpFile)
2346 return ERROR_INVALID_PARAMETER;
2348 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2350 /* Check for file existence */
2352 return ERROR_SUCCESS;
2356 /******************************************************************************
2357 * RegRestoreKeyA [ADVAPI32.@]
2359 * See RegRestoreKeyW.
2361 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2363 UNICODE_STRING lpFileW;
2364 LONG ret;
2366 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2367 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2368 RtlFreeUnicodeString( &lpFileW );
2369 return ret;
2373 /******************************************************************************
2374 * RegUnLoadKeyW [ADVAPI32.@]
2376 * Unload a registry key and its subkeys from the registry.
2378 * PARAMS
2379 * hkey [I] Handle of open key
2380 * lpSubKey [I] Address of name of subkey to unload
2382 * RETURNS
2383 * Success: ERROR_SUCCESS
2384 * Failure: nonzero error code from Winerror.h
2386 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2388 DWORD ret;
2389 HKEY shkey;
2390 OBJECT_ATTRIBUTES attr;
2391 UNICODE_STRING subkey;
2393 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2395 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2396 if( ret )
2397 return ERROR_INVALID_PARAMETER;
2399 RtlInitUnicodeString(&subkey, lpSubKey);
2400 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2401 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2403 RegCloseKey(shkey);
2405 return ret;
2409 /******************************************************************************
2410 * RegUnLoadKeyA [ADVAPI32.@]
2412 * See RegUnLoadKeyW.
2414 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2416 UNICODE_STRING lpSubKeyW;
2417 LONG ret;
2419 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2420 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2421 RtlFreeUnicodeString( &lpSubKeyW );
2422 return ret;
2426 /******************************************************************************
2427 * RegReplaceKeyW [ADVAPI32.@]
2429 * Replace the file backing a registry key and all its subkeys with another file.
2431 * PARAMS
2432 * hkey [I] Handle of open key
2433 * lpSubKey [I] Address of name of subkey
2434 * lpNewFile [I] Address of filename for file with new data
2435 * lpOldFile [I] Address of filename for backup file
2437 * RETURNS
2438 * Success: ERROR_SUCCESS
2439 * Failure: nonzero error code from Winerror.h
2441 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2442 LPCWSTR lpOldFile )
2444 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2445 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2446 return ERROR_SUCCESS;
2450 /******************************************************************************
2451 * RegReplaceKeyA [ADVAPI32.@]
2453 * See RegReplaceKeyW.
2455 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2456 LPCSTR lpOldFile )
2458 UNICODE_STRING lpSubKeyW;
2459 UNICODE_STRING lpNewFileW;
2460 UNICODE_STRING lpOldFileW;
2461 LONG ret;
2463 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2464 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2465 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2466 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2467 RtlFreeUnicodeString( &lpOldFileW );
2468 RtlFreeUnicodeString( &lpNewFileW );
2469 RtlFreeUnicodeString( &lpSubKeyW );
2470 return ret;
2474 /******************************************************************************
2475 * RegSetKeySecurity [ADVAPI32.@]
2477 * Set the security of an open registry key.
2479 * PARAMS
2480 * hkey [I] Open handle of key to set
2481 * SecurityInfo [I] Descriptor contents
2482 * pSecurityDesc [I] Address of descriptor for key
2484 * RETURNS
2485 * Success: ERROR_SUCCESS
2486 * Failure: nonzero error code from Winerror.h
2488 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2489 PSECURITY_DESCRIPTOR pSecurityDesc )
2491 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2493 /* It seems to perform this check before the hkey check */
2494 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2495 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2496 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2497 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2498 /* Param OK */
2499 } else
2500 return ERROR_INVALID_PARAMETER;
2502 if (!pSecurityDesc)
2503 return ERROR_INVALID_PARAMETER;
2505 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2507 return RtlNtStatusToDosError( NtSetSecurityObject( hkey, SecurityInfo, pSecurityDesc ) );
2511 /******************************************************************************
2512 * RegGetKeySecurity [ADVAPI32.@]
2514 * Get a copy of the security descriptor for a given registry key.
2516 * PARAMS
2517 * hkey [I] Open handle of key to set
2518 * SecurityInformation [I] Descriptor contents
2519 * pSecurityDescriptor [O] Address of descriptor for key
2520 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2522 * RETURNS
2523 * Success: ERROR_SUCCESS
2524 * Failure: Error code
2526 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2527 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2528 LPDWORD lpcbSecurityDescriptor )
2530 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2531 *lpcbSecurityDescriptor);
2533 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2535 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2536 SecurityInformation, pSecurityDescriptor,
2537 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2541 /******************************************************************************
2542 * RegFlushKey [ADVAPI32.@]
2544 * Immediately write a registry key to registry.
2546 * PARAMS
2547 * hkey [I] Handle of key to write
2549 * RETURNS
2550 * Success: ERROR_SUCCESS
2551 * Failure: Error code
2553 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2555 hkey = get_special_root_hkey( hkey, 0 );
2556 if (!hkey) return ERROR_INVALID_HANDLE;
2558 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2562 /******************************************************************************
2563 * RegConnectRegistryW [ADVAPI32.@]
2565 * Establish a connection to a predefined registry key on another computer.
2567 * PARAMS
2568 * lpMachineName [I] Address of name of remote computer
2569 * hHey [I] Predefined registry handle
2570 * phkResult [I] Address of buffer for remote registry handle
2572 * RETURNS
2573 * Success: ERROR_SUCCESS
2574 * Failure: nonzero error code from Winerror.h
2576 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2577 PHKEY phkResult )
2579 LONG ret;
2581 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName), hKey, phkResult);
2583 if (!lpMachineName || !*lpMachineName) {
2584 /* Use the local machine name */
2585 ret = RegOpenKeyW( hKey, NULL, phkResult );
2587 else {
2588 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2589 DWORD len = sizeof(compName) / sizeof(WCHAR);
2591 /* MSDN says lpMachineName must start with \\ : not so */
2592 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2593 lpMachineName += 2;
2594 if (GetComputerNameW(compName, &len))
2596 if (!strcmpiW(lpMachineName, compName))
2597 ret = RegOpenKeyW(hKey, NULL, phkResult);
2598 else
2600 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2601 ret = ERROR_BAD_NETPATH;
2604 else
2605 ret = GetLastError();
2607 return ret;
2611 /******************************************************************************
2612 * RegConnectRegistryA [ADVAPI32.@]
2614 * See RegConnectRegistryW.
2616 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2618 UNICODE_STRING machineW;
2619 LONG ret;
2621 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2622 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2623 RtlFreeUnicodeString( &machineW );
2624 return ret;
2628 /******************************************************************************
2629 * RegNotifyChangeKeyValue [ADVAPI32.@]
2631 * Notify the caller about changes to the attributes or contents of a registry key.
2633 * PARAMS
2634 * hkey [I] Handle of key to watch
2635 * fWatchSubTree [I] Flag for subkey notification
2636 * fdwNotifyFilter [I] Changes to be reported
2637 * hEvent [I] Handle of signaled event
2638 * fAsync [I] Flag for asynchronous reporting
2640 * RETURNS
2641 * Success: ERROR_SUCCESS
2642 * Failure: nonzero error code from Winerror.h
2644 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2645 DWORD fdwNotifyFilter, HANDLE hEvent,
2646 BOOL fAsync )
2648 NTSTATUS status;
2649 IO_STATUS_BLOCK iosb;
2651 hkey = get_special_root_hkey( hkey, 0 );
2652 if (!hkey) return ERROR_INVALID_HANDLE;
2654 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2655 hEvent, fAsync);
2657 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2658 fdwNotifyFilter, fAsync, NULL, 0,
2659 fWatchSubTree);
2661 if (status && status != STATUS_TIMEOUT)
2662 return RtlNtStatusToDosError( status );
2664 return ERROR_SUCCESS;
2667 /******************************************************************************
2668 * RegOpenUserClassesRoot [ADVAPI32.@]
2670 * Open the HKEY_CLASSES_ROOT key for a user.
2672 * PARAMS
2673 * hToken [I] Handle of token representing the user
2674 * dwOptions [I] Reserved, must be 0
2675 * samDesired [I] Desired access rights
2676 * phkResult [O] Destination for the resulting key handle
2678 * RETURNS
2679 * Success: ERROR_SUCCESS
2680 * Failure: nonzero error code from Winerror.h
2682 * NOTES
2683 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2684 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2685 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2687 LSTATUS WINAPI RegOpenUserClassesRoot(
2688 HANDLE hToken,
2689 DWORD dwOptions,
2690 REGSAM samDesired,
2691 PHKEY phkResult
2694 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2696 *phkResult = HKEY_CLASSES_ROOT;
2697 return ERROR_SUCCESS;
2700 /******************************************************************************
2701 * load_string [Internal]
2703 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2704 * avoid importing user32, which is higher level than advapi32. Helper for
2705 * RegLoadMUIString.
2707 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2709 HGLOBAL hMemory;
2710 HRSRC hResource;
2711 WCHAR *pString;
2712 int idxString;
2714 /* Negative values have to be inverted. */
2715 if (HIWORD(resId) == 0xffff)
2716 resId = (UINT)(-((INT)resId));
2718 /* Load the resource into memory and get a pointer to it. */
2719 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2720 if (!hResource) return 0;
2721 hMemory = LoadResource(hModule, hResource);
2722 if (!hMemory) return 0;
2723 pString = LockResource(hMemory);
2725 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2726 idxString = resId & 0xf;
2727 while (idxString--) pString += *pString + 1;
2729 /* If no buffer is given, return length of the string. */
2730 if (!pwszBuffer) return *pString;
2732 /* Else copy over the string, respecting the buffer size. */
2733 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2734 if (cMaxChars >= 0) {
2735 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2736 pwszBuffer[cMaxChars] = '\0';
2739 return cMaxChars;
2742 /******************************************************************************
2743 * RegLoadMUIStringW [ADVAPI32.@]
2745 * Load the localized version of a string resource from some PE, respective
2746 * id and path of which are given in the registry value in the format
2747 * @[path]\dllname,-resourceId
2749 * PARAMS
2750 * hKey [I] Key, of which to load the string value from.
2751 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2752 * pszBuffer [O] Buffer to store the localized string in.
2753 * cbBuffer [I] Size of the destination buffer in bytes.
2754 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2755 * dwFlags [I] None supported yet.
2756 * pszBaseDir [I] Not supported yet.
2758 * RETURNS
2759 * Success: ERROR_SUCCESS,
2760 * Failure: nonzero error code from winerror.h
2762 * NOTES
2763 * This is an API of Windows Vista, which wasn't available at the time this code
2764 * was written. We have to check for the correct behaviour once it's available.
2766 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2767 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2769 DWORD dwValueType, cbData;
2770 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2771 LONG result;
2773 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2774 "dwFlags = %d, pwszBaseDir = %s)\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2775 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2777 /* Parameter sanity checks. */
2778 if (!hKey || !pwszBuffer)
2779 return ERROR_INVALID_PARAMETER;
2781 if (pwszBaseDir && *pwszBaseDir) {
2782 FIXME("BaseDir parameter not yet supported!\n");
2783 return ERROR_INVALID_PARAMETER;
2786 /* Check for value existence and correctness of its type, allocate a buffer and load it. */
2787 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2788 if (result != ERROR_SUCCESS) goto cleanup;
2789 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2790 result = ERROR_FILE_NOT_FOUND;
2791 goto cleanup;
2793 pwszTempBuffer = heap_alloc(cbData);
2794 if (!pwszTempBuffer) {
2795 result = ERROR_NOT_ENOUGH_MEMORY;
2796 goto cleanup;
2798 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2799 if (result != ERROR_SUCCESS) goto cleanup;
2801 /* Expand environment variables, if appropriate, or copy the original string over. */
2802 if (dwValueType == REG_EXPAND_SZ) {
2803 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2804 if (!cbData) goto cleanup;
2805 pwszExpandedBuffer = heap_alloc(cbData);
2806 if (!pwszExpandedBuffer) {
2807 result = ERROR_NOT_ENOUGH_MEMORY;
2808 goto cleanup;
2810 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2811 } else {
2812 pwszExpandedBuffer = heap_alloc(cbData);
2813 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2816 /* If the value references a resource based string, parse the value and load the string.
2817 * Else just copy over the original value. */
2818 result = ERROR_SUCCESS;
2819 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2820 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2821 } else {
2822 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2823 UINT uiStringId;
2824 HMODULE hModule;
2826 /* Format of the expanded value is 'path_to_dll,-resId' */
2827 if (!pComma || pComma[1] != '-') {
2828 result = ERROR_BADKEY;
2829 goto cleanup;
2832 uiStringId = atoiW(pComma+2);
2833 *pComma = '\0';
2835 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2836 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2837 result = ERROR_BADKEY;
2838 FreeLibrary(hModule);
2841 cleanup:
2842 heap_free(pwszTempBuffer);
2843 heap_free(pwszExpandedBuffer);
2844 return result;
2847 /******************************************************************************
2848 * RegLoadMUIStringA [ADVAPI32.@]
2850 * See RegLoadMUIStringW
2852 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2853 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2855 UNICODE_STRING valueW, baseDirW;
2856 WCHAR *pwszBuffer;
2857 DWORD cbData = cbBuffer * sizeof(WCHAR);
2858 LONG result;
2860 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2861 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2862 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2863 !(pwszBuffer = heap_alloc(cbData)))
2865 result = ERROR_NOT_ENOUGH_MEMORY;
2866 goto cleanup;
2869 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2870 baseDirW.Buffer);
2872 if (result == ERROR_SUCCESS) {
2873 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2874 if (pcbData)
2875 *pcbData = cbData;
2878 cleanup:
2879 heap_free(pwszBuffer);
2880 RtlFreeUnicodeString(&baseDirW);
2881 RtlFreeUnicodeString(&valueW);
2883 return result;
2886 /******************************************************************************
2887 * RegDisablePredefinedCache [ADVAPI32.@]
2889 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2891 * PARAMS
2892 * None.
2894 * RETURNS
2895 * Success: ERROR_SUCCESS
2896 * Failure: nonzero error code from Winerror.h
2898 * NOTES
2899 * This is useful for services that use impersonation.
2901 LSTATUS WINAPI RegDisablePredefinedCache(void)
2903 HKEY hkey_current_user;
2904 int idx = HandleToUlong(HKEY_CURRENT_USER) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
2906 /* prevent caching of future requests */
2907 hkcu_cache_disabled = TRUE;
2909 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2911 if (hkey_current_user)
2912 NtClose( hkey_current_user );
2914 return ERROR_SUCCESS;
2917 /******************************************************************************
2918 * RegDeleteTreeW [ADVAPI32.@]
2921 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2923 LONG ret;
2924 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2925 DWORD dwMaxLen, dwSize;
2926 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2927 HKEY hSubKey = hKey;
2929 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2931 if(lpszSubKey)
2933 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2934 if (ret) return ret;
2937 /* Get highest length for keys, values */
2938 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2939 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2940 if (ret) goto cleanup;
2942 dwMaxSubkeyLen++;
2943 dwMaxValueLen++;
2944 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2945 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2947 /* Name too big: alloc a buffer for it */
2948 if (!(lpszName = heap_alloc( dwMaxLen*sizeof(WCHAR))))
2950 ret = ERROR_NOT_ENOUGH_MEMORY;
2951 goto cleanup;
2956 /* Recursively delete all the subkeys */
2957 while (TRUE)
2959 dwSize = dwMaxLen;
2960 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2961 NULL, NULL, NULL)) break;
2963 ret = RegDeleteTreeW(hSubKey, lpszName);
2964 if (ret) goto cleanup;
2967 if (lpszSubKey)
2968 ret = RegDeleteKeyW(hKey, lpszSubKey);
2969 else
2970 while (TRUE)
2972 dwSize = dwMaxLen;
2973 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2974 NULL, NULL, NULL, NULL)) break;
2976 ret = RegDeleteValueW(hKey, lpszName);
2977 if (ret) goto cleanup;
2980 cleanup:
2981 /* Free buffer if allocated */
2982 if (lpszName != szNameBuf)
2983 heap_free( lpszName);
2984 if(lpszSubKey)
2985 RegCloseKey(hSubKey);
2986 return ret;
2989 /******************************************************************************
2990 * RegDeleteTreeA [ADVAPI32.@]
2993 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2995 LONG ret;
2996 UNICODE_STRING lpszSubKeyW;
2998 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2999 else lpszSubKeyW.Buffer = NULL;
3000 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
3001 RtlFreeUnicodeString( &lpszSubKeyW );
3002 return ret;
3005 /******************************************************************************
3006 * RegDisableReflectionKey [ADVAPI32.@]
3009 LONG WINAPI RegDisableReflectionKey(HKEY base)
3011 FIXME("%p: stub\n", base);
3012 return ERROR_SUCCESS;