d3d8/tests: Test presentation parameter combinations.
[wine.git] / dlls / advapi32 / registry.c
blobcf5a1acb08c1b3e3b879be8c729f6ff15c5613c5
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 && class_len && *class_len)
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 len = 0;
1053 if (class && class_len) len = *class_len;
1054 RtlUnicodeToMultiByteN( class, len, class_len,
1055 (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength );
1056 if (len)
1058 class[len - 1] = 0;
1059 if (*class_len + 1 > len)
1061 status = STATUS_BUFFER_OVERFLOW;
1062 *class_len -= 1;
1066 else status = STATUS_SUCCESS;
1068 if (subkeys) *subkeys = info->SubKeys;
1069 if (max_subkey) *max_subkey = info->MaxNameLen;
1070 if (max_class) *max_class = info->MaxClassLen;
1071 if (values) *values = info->Values;
1072 if (max_value) *max_value = info->MaxValueNameLen;
1073 if (max_data) *max_data = info->MaxValueDataLen;
1074 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
1076 done:
1077 if (buf_ptr != buffer) heap_free( buf_ptr );
1078 return RtlNtStatusToDosError( status );
1082 /******************************************************************************
1083 * RegCloseKey [ADVAPI32.@]
1085 * Close an open registry key.
1087 * PARAMS
1088 * hkey [I] Handle of key to close
1090 * RETURNS
1091 * Success: ERROR_SUCCESS
1092 * Failure: Error code
1094 LSTATUS WINAPI RegCloseKey( HKEY hkey )
1096 if (!hkey) return ERROR_INVALID_HANDLE;
1097 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
1098 return RtlNtStatusToDosError( NtClose( hkey ) );
1102 /******************************************************************************
1103 * RegDeleteKeyExW [ADVAPI32.@]
1105 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
1107 DWORD ret;
1108 HKEY tmp;
1110 if (!name) return ERROR_INVALID_PARAMETER;
1112 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
1114 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1115 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
1117 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1118 RegCloseKey( tmp );
1120 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
1121 return ret;
1125 /******************************************************************************
1126 * RegDeleteKeyW [ADVAPI32.@]
1128 * See RegDeleteKeyA.
1130 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
1132 return RegDeleteKeyExW( hkey, name, 0, 0 );
1136 /******************************************************************************
1137 * RegDeleteKeyExA [ADVAPI32.@]
1139 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1141 DWORD ret;
1142 HKEY tmp;
1144 if (!name) return ERROR_INVALID_PARAMETER;
1146 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
1148 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1149 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1151 if (!is_version_nt()) /* win95 does recursive key deletes */
1153 CHAR sub[MAX_PATH];
1155 while(!RegEnumKeyA(tmp, 0, sub, sizeof(sub)))
1157 if(RegDeleteKeyExA(tmp, sub, access, reserved)) /* recurse */
1158 break;
1161 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1162 RegCloseKey( tmp );
1164 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1165 return ret;
1169 /******************************************************************************
1170 * RegDeleteKeyA [ADVAPI32.@]
1172 * Delete a registry key.
1174 * PARAMS
1175 * hkey [I] Handle to parent key containing the key to delete
1176 * name [I] Name of the key user hkey to delete
1178 * NOTES
1180 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1181 * right. In reality, it opens a new handle with DELETE access.
1183 * RETURNS
1184 * Success: ERROR_SUCCESS
1185 * Failure: Error code
1187 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1189 return RegDeleteKeyExA( hkey, name, 0, 0 );
1194 /******************************************************************************
1195 * RegSetValueExW [ADVAPI32.@]
1197 * Set the data and contents of a registry value.
1199 * PARAMS
1200 * hkey [I] Handle of key to set value for
1201 * name [I] Name of value to set
1202 * reserved [I] Reserved, must be zero
1203 * type [I] Type of the value being set
1204 * data [I] The new contents of the value to set
1205 * count [I] Size of data
1207 * RETURNS
1208 * Success: ERROR_SUCCESS
1209 * Failure: Error code
1211 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1212 DWORD type, const BYTE *data, DWORD count )
1214 UNICODE_STRING nameW;
1216 /* no need for version check, not implemented on win9x anyway */
1218 if ((data && ((ULONG_PTR)data >> 16) == 0) || (!data && count)) return ERROR_NOACCESS;
1220 if (count && is_string(type))
1222 LPCWSTR str = (LPCWSTR)data;
1223 /* if user forgot to count terminating null, add it (yes NT does this) */
1224 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1225 count += sizeof(WCHAR);
1227 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1229 RtlInitUnicodeString( &nameW, name );
1230 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1234 /******************************************************************************
1235 * RegSetValueExA [ADVAPI32.@]
1237 * See RegSetValueExW.
1239 * NOTES
1240 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1241 * NT does definitely care (aj)
1243 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1244 const BYTE *data, DWORD count )
1246 ANSI_STRING nameA;
1247 UNICODE_STRING nameW;
1248 WCHAR *dataW = NULL;
1249 NTSTATUS status;
1251 if (!is_version_nt()) /* win95 */
1253 if (type == REG_SZ)
1255 if (!data) return ERROR_INVALID_PARAMETER;
1256 count = strlen((const char *)data) + 1;
1259 else if (count && is_string(type))
1261 /* if user forgot to count terminating null, add it (yes NT does this) */
1262 if (data[count-1] && !data[count]) count++;
1265 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1267 if (is_string( type )) /* need to convert to Unicode */
1269 DWORD lenW;
1270 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1271 if (!(dataW = heap_alloc( lenW ))) return ERROR_OUTOFMEMORY;
1272 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1273 count = lenW;
1274 data = (BYTE *)dataW;
1277 RtlInitAnsiString( &nameA, name );
1278 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1280 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1281 RtlFreeUnicodeString( &nameW );
1283 heap_free( dataW );
1284 return RtlNtStatusToDosError( status );
1288 /******************************************************************************
1289 * RegSetValueW [ADVAPI32.@]
1291 * Sets the data for the default or unnamed value of a reg key.
1293 * PARAMS
1294 * hkey [I] Handle to an open key.
1295 * subkey [I] Name of a subkey of hKey.
1296 * type [I] Type of information to store.
1297 * data [I] String that contains the data to set for the default value.
1298 * count [I] Ignored.
1300 * RETURNS
1301 * Success: ERROR_SUCCESS
1302 * Failure: nonzero error code from Winerror.h
1304 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR subkey, DWORD type, LPCWSTR data, DWORD count )
1306 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(subkey), type, debugstr_w(data), count );
1308 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1310 return RegSetKeyValueW( hkey, subkey, NULL, type, data, (strlenW(data) + 1)*sizeof(WCHAR) );
1313 /******************************************************************************
1314 * RegSetValueA [ADVAPI32.@]
1316 * See RegSetValueW.
1318 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR subkey, DWORD type, LPCSTR data, DWORD count )
1320 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(subkey), type, debugstr_a(data), count );
1322 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1324 return RegSetKeyValueA( hkey, subkey, NULL, type, data, strlen(data) + 1 );
1327 /******************************************************************************
1328 * RegSetKeyValueW [ADVAPI32.@]
1330 LONG WINAPI RegSetKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name, DWORD type, const void *data, DWORD len )
1332 HKEY hsubkey = NULL;
1333 DWORD ret;
1335 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey, debugstr_w(subkey), debugstr_w(name), type, data, len );
1337 if (subkey && subkey[0]) /* need to create the subkey */
1339 if ((ret = RegCreateKeyW( hkey, subkey, &hsubkey )) != ERROR_SUCCESS) return ret;
1340 hkey = hsubkey;
1343 ret = RegSetValueExW( hkey, name, 0, type, (const BYTE*)data, len );
1344 if (hsubkey) RegCloseKey( hsubkey );
1345 return ret;
1348 /******************************************************************************
1349 * RegSetKeyValueA [ADVAPI32.@]
1351 LONG WINAPI RegSetKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name, DWORD type, const void *data, DWORD len )
1353 HKEY hsubkey = NULL;
1354 DWORD ret;
1356 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey, debugstr_a(subkey), debugstr_a(name), type, data, len );
1358 if (subkey && subkey[0]) /* need to create the subkey */
1360 if ((ret = RegCreateKeyA( hkey, subkey, &hsubkey )) != ERROR_SUCCESS) return ret;
1361 hkey = hsubkey;
1364 ret = RegSetValueExA( hkey, name, 0, type, (const BYTE*)data, len );
1365 if (hsubkey) RegCloseKey( hsubkey );
1366 return ret;
1369 /******************************************************************************
1370 * RegQueryValueExW [ADVAPI32.@]
1372 * See RegQueryValueExA.
1374 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1375 LPBYTE data, LPDWORD count )
1377 NTSTATUS status;
1378 UNICODE_STRING name_str;
1379 DWORD total_size;
1380 char buffer[256], *buf_ptr = buffer;
1381 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1382 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1384 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1385 hkey, debugstr_w(name), reserved, type, data, count,
1386 (count && data) ? *count : 0 );
1388 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1389 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1391 RtlInitUnicodeString( &name_str, name );
1393 if (data) total_size = min( sizeof(buffer), *count + info_size );
1394 else
1396 total_size = info_size;
1397 if (count) *count = 0;
1400 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1401 buffer, total_size, &total_size );
1402 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1404 if (data)
1406 /* retry with a dynamically allocated buffer */
1407 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1409 if (buf_ptr != buffer) heap_free( buf_ptr );
1410 if (!(buf_ptr = heap_alloc( total_size )))
1411 return ERROR_NOT_ENOUGH_MEMORY;
1412 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1413 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1414 buf_ptr, total_size, &total_size );
1417 if (!status)
1419 memcpy( data, buf_ptr + info_size, total_size - info_size );
1420 /* if the type is REG_SZ and data is not 0-terminated
1421 * and there is enough space in the buffer NT appends a \0 */
1422 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1424 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1425 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1428 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1430 else status = STATUS_SUCCESS;
1432 if (type) *type = info->Type;
1433 if (count) *count = total_size - info_size;
1435 done:
1436 if (buf_ptr != buffer) heap_free( buf_ptr );
1437 return RtlNtStatusToDosError(status);
1441 /******************************************************************************
1442 * RegQueryValueExA [ADVAPI32.@]
1444 * Get the type and contents of a specified value under with a key.
1446 * PARAMS
1447 * hkey [I] Handle of the key to query
1448 * name [I] Name of value under hkey to query
1449 * reserved [I] Reserved - must be NULL
1450 * type [O] Destination for the value type, or NULL if not required
1451 * data [O] Destination for the values contents, or NULL if not required
1452 * count [I/O] Size of data, updated with the number of bytes returned
1454 * RETURNS
1455 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1456 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1457 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1458 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1460 * NOTES
1461 * MSDN states that if data is too small it is partially filled. In reality
1462 * it remains untouched.
1464 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1465 LPBYTE data, LPDWORD count )
1467 NTSTATUS status;
1468 ANSI_STRING nameA;
1469 UNICODE_STRING nameW;
1470 DWORD total_size, datalen = 0;
1471 char buffer[256], *buf_ptr = buffer;
1472 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1473 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1475 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1476 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1478 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1479 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1481 if (count) datalen = *count;
1482 if (!data && count) *count = 0;
1484 /* this matches Win9x behaviour - NT sets *type to a random value */
1485 if (type) *type = REG_NONE;
1487 RtlInitAnsiString( &nameA, name );
1488 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1489 return RtlNtStatusToDosError(status);
1491 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1492 buffer, sizeof(buffer), &total_size );
1493 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1495 /* we need to fetch the contents for a string type even if not requested,
1496 * because we need to compute the length of the ASCII string. */
1497 if (data || is_string(info->Type))
1499 /* retry with a dynamically allocated buffer */
1500 while (status == STATUS_BUFFER_OVERFLOW)
1502 if (buf_ptr != buffer) heap_free( buf_ptr );
1503 if (!(buf_ptr = heap_alloc( total_size )))
1505 status = STATUS_NO_MEMORY;
1506 goto done;
1508 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1509 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1510 buf_ptr, total_size, &total_size );
1513 if (status) goto done;
1515 if (is_string(info->Type))
1517 DWORD len;
1519 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1520 total_size - info_size );
1521 if (data && len)
1523 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1524 else
1526 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1527 total_size - info_size );
1528 /* if the type is REG_SZ and data is not 0-terminated
1529 * and there is enough space in the buffer NT appends a \0 */
1530 if (len < datalen && data[len-1]) data[len] = 0;
1533 total_size = len + info_size;
1535 else if (data)
1537 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1538 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1541 else status = STATUS_SUCCESS;
1543 if (type) *type = info->Type;
1544 if (count) *count = total_size - info_size;
1546 done:
1547 if (buf_ptr != buffer) heap_free( buf_ptr );
1548 RtlFreeUnicodeString( &nameW );
1549 return RtlNtStatusToDosError(status);
1553 /******************************************************************************
1554 * RegQueryValueW [ADVAPI32.@]
1556 * Retrieves the data associated with the default or unnamed value of a key.
1558 * PARAMS
1559 * hkey [I] Handle to an open key.
1560 * name [I] Name of the subkey of hKey.
1561 * data [O] Receives the string associated with the default value
1562 * of the key.
1563 * count [I/O] Size of lpValue in bytes.
1565 * RETURNS
1566 * Success: ERROR_SUCCESS
1567 * Failure: nonzero error code from Winerror.h
1569 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1571 DWORD ret;
1572 HKEY subkey = hkey;
1574 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1576 if (name && name[0])
1578 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1580 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1581 if (subkey != hkey) RegCloseKey( subkey );
1582 if (ret == ERROR_FILE_NOT_FOUND)
1584 /* return empty string if default value not found */
1585 if (data) *data = 0;
1586 if (count) *count = sizeof(WCHAR);
1587 ret = ERROR_SUCCESS;
1589 return ret;
1593 /******************************************************************************
1594 * RegQueryValueA [ADVAPI32.@]
1596 * See RegQueryValueW.
1598 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1600 DWORD ret;
1601 HKEY subkey = hkey;
1603 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1605 if (name && name[0])
1607 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1609 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1610 if (subkey != hkey) RegCloseKey( subkey );
1611 if (ret == ERROR_FILE_NOT_FOUND)
1613 /* return empty string if default value not found */
1614 if (data) *data = 0;
1615 if (count) *count = 1;
1616 ret = ERROR_SUCCESS;
1618 return ret;
1622 /******************************************************************************
1623 * ADVAPI_ApplyRestrictions [internal]
1625 * Helper function for RegGetValueA/W.
1627 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1628 DWORD cbData, PLONG ret )
1630 /* Check if the type is restricted by the passed flags */
1631 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1633 DWORD dwMask = 0;
1635 switch (dwType)
1637 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1638 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1639 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1640 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1641 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1642 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1643 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1646 if (dwFlags & dwMask)
1648 /* Type is not restricted, check for size mismatch */
1649 if (dwType == REG_BINARY)
1651 DWORD cbExpect = 0;
1653 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1654 cbExpect = 4;
1655 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1656 cbExpect = 8;
1658 if (cbExpect && cbData != cbExpect)
1659 *ret = ERROR_DATATYPE_MISMATCH;
1662 else *ret = ERROR_UNSUPPORTED_TYPE;
1667 /******************************************************************************
1668 * RegGetValueW [ADVAPI32.@]
1670 * Retrieves the type and data for a value name associated with a key,
1671 * optionally expanding its content and restricting its type.
1673 * PARAMS
1674 * hKey [I] Handle to an open key.
1675 * pszSubKey [I] Name of the subkey of hKey.
1676 * pszValue [I] Name of value under hKey/szSubKey to query.
1677 * dwFlags [I] Flags restricting the value type to retrieve.
1678 * pdwType [O] Destination for the values type, may be NULL.
1679 * pvData [O] Destination for the values content, may be NULL.
1680 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1681 * retrieve the whole content, including the trailing '\0'
1682 * for strings.
1684 * RETURNS
1685 * Success: ERROR_SUCCESS
1686 * Failure: nonzero error code from Winerror.h
1688 * NOTES
1689 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1690 * expanded and pdwType is set to REG_SZ instead.
1691 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1692 * without RRF_NOEXPAND is thus not allowed.
1693 * An exception is the case where RRF_RT_ANY is specified, because then
1694 * RRF_NOEXPAND is allowed.
1696 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1697 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1698 LPDWORD pcbData )
1700 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1701 PVOID pvBuf = NULL;
1702 LONG ret;
1704 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1705 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1706 pvData, pcbData, cbData);
1708 if (pvData && !pcbData)
1709 return ERROR_INVALID_PARAMETER;
1710 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1711 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1712 return ERROR_INVALID_PARAMETER;
1714 if (pszSubKey && pszSubKey[0])
1716 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1717 if (ret != ERROR_SUCCESS) return ret;
1720 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1722 /* If we are going to expand we need to read in the whole the value even
1723 * if the passed buffer was too small as the expanded string might be
1724 * smaller than the unexpanded one and could fit into cbData bytes. */
1725 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1726 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1728 do {
1729 heap_free(pvBuf);
1731 pvBuf = heap_alloc(cbData);
1732 if (!pvBuf)
1734 ret = ERROR_NOT_ENOUGH_MEMORY;
1735 break;
1738 if (ret == ERROR_MORE_DATA || !pvData)
1739 ret = RegQueryValueExW(hKey, pszValue, NULL,
1740 &dwType, pvBuf, &cbData);
1741 else
1743 /* Even if cbData was large enough we have to copy the
1744 * string since ExpandEnvironmentStrings can't handle
1745 * overlapping buffers. */
1746 CopyMemory(pvBuf, pvData, cbData);
1749 /* Both the type or the value itself could have been modified in
1750 * between so we have to keep retrying until the buffer is large
1751 * enough or we no longer have to expand the value. */
1752 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1754 if (ret == ERROR_SUCCESS)
1756 /* Recheck dwType in case it changed since the first call */
1757 if (dwType == REG_EXPAND_SZ)
1759 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1760 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1761 dwType = REG_SZ;
1762 if(pvData && pcbData && cbData > *pcbData)
1763 ret = ERROR_MORE_DATA;
1765 else if (pvData)
1766 CopyMemory(pvData, pvBuf, *pcbData);
1769 heap_free(pvBuf);
1772 if (pszSubKey && pszSubKey[0])
1773 RegCloseKey(hKey);
1775 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1777 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1778 ZeroMemory(pvData, *pcbData);
1780 if (pdwType) *pdwType = dwType;
1781 if (pcbData) *pcbData = cbData;
1783 return ret;
1787 /******************************************************************************
1788 * RegGetValueA [ADVAPI32.@]
1790 * See RegGetValueW.
1792 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1793 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1794 LPDWORD pcbData )
1796 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1797 PVOID pvBuf = NULL;
1798 LONG ret;
1800 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1801 hKey, debugstr_a(pszSubKey), debugstr_a(pszValue), dwFlags,
1802 pdwType, pvData, pcbData, cbData);
1804 if (pvData && !pcbData)
1805 return ERROR_INVALID_PARAMETER;
1806 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1807 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1808 return ERROR_INVALID_PARAMETER;
1810 if (pszSubKey && pszSubKey[0])
1812 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1813 if (ret != ERROR_SUCCESS) return ret;
1816 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1818 /* If we are going to expand we need to read in the whole the value even
1819 * if the passed buffer was too small as the expanded string might be
1820 * smaller than the unexpanded one and could fit into cbData bytes. */
1821 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1822 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1824 do {
1825 heap_free(pvBuf);
1827 pvBuf = heap_alloc(cbData);
1828 if (!pvBuf)
1830 ret = ERROR_NOT_ENOUGH_MEMORY;
1831 break;
1834 if (ret == ERROR_MORE_DATA || !pvData)
1835 ret = RegQueryValueExA(hKey, pszValue, NULL,
1836 &dwType, pvBuf, &cbData);
1837 else
1839 /* Even if cbData was large enough we have to copy the
1840 * string since ExpandEnvironmentStrings can't handle
1841 * overlapping buffers. */
1842 CopyMemory(pvBuf, pvData, cbData);
1845 /* Both the type or the value itself could have been modified in
1846 * between so we have to keep retrying until the buffer is large
1847 * enough or we no longer have to expand the value. */
1848 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1850 if (ret == ERROR_SUCCESS)
1852 /* Recheck dwType in case it changed since the first call */
1853 if (dwType == REG_EXPAND_SZ)
1855 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1856 pcbData ? *pcbData : 0);
1857 dwType = REG_SZ;
1858 if(pvData && pcbData && cbData > *pcbData)
1859 ret = ERROR_MORE_DATA;
1861 else if (pvData)
1862 CopyMemory(pvData, pvBuf, *pcbData);
1865 heap_free(pvBuf);
1868 if (pszSubKey && pszSubKey[0])
1869 RegCloseKey(hKey);
1871 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1873 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1874 ZeroMemory(pvData, *pcbData);
1876 if (pdwType) *pdwType = dwType;
1877 if (pcbData) *pcbData = cbData;
1879 return ret;
1883 /******************************************************************************
1884 * RegEnumValueW [ADVAPI32.@]
1886 * Enumerates the values for the specified open registry key.
1888 * PARAMS
1889 * hkey [I] Handle to key to query
1890 * index [I] Index of value to query
1891 * value [O] Value string
1892 * val_count [I/O] Size of value buffer (in wchars)
1893 * reserved [I] Reserved
1894 * type [O] Type code
1895 * data [O] Value data
1896 * count [I/O] Size of data buffer (in bytes)
1898 * RETURNS
1899 * Success: ERROR_SUCCESS
1900 * Failure: nonzero error code from Winerror.h
1903 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1904 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1906 NTSTATUS status;
1907 DWORD total_size;
1908 char buffer[256], *buf_ptr = buffer;
1909 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1910 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1912 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1913 hkey, index, value, val_count, reserved, type, data, count );
1915 if ((data && !count) || reserved || !value || !val_count)
1916 return ERROR_INVALID_PARAMETER;
1917 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1919 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1920 if (data) total_size += *count;
1921 total_size = min( sizeof(buffer), total_size );
1923 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1924 buffer, total_size, &total_size );
1925 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1927 if (value || data)
1929 /* retry with a dynamically allocated buffer */
1930 while (status == STATUS_BUFFER_OVERFLOW)
1932 if (buf_ptr != buffer) heap_free( buf_ptr );
1933 if (!(buf_ptr = heap_alloc( total_size )))
1934 return ERROR_NOT_ENOUGH_MEMORY;
1935 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1936 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1937 buf_ptr, total_size, &total_size );
1940 if (status) goto done;
1942 if (value)
1944 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1946 status = STATUS_BUFFER_OVERFLOW;
1947 goto overflow;
1949 memcpy( value, info->Name, info->NameLength );
1950 *val_count = info->NameLength / sizeof(WCHAR);
1951 value[*val_count] = 0;
1954 if (data)
1956 if (total_size - info->DataOffset > *count)
1958 status = STATUS_BUFFER_OVERFLOW;
1959 goto overflow;
1961 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1962 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1964 /* if the type is REG_SZ and data is not 0-terminated
1965 * and there is enough space in the buffer NT appends a \0 */
1966 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1967 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1971 else status = STATUS_SUCCESS;
1973 overflow:
1974 if (type) *type = info->Type;
1975 if (count) *count = info->DataLength;
1977 done:
1978 if (buf_ptr != buffer) heap_free( buf_ptr );
1979 return RtlNtStatusToDosError(status);
1983 /******************************************************************************
1984 * RegEnumValueA [ADVAPI32.@]
1986 * See RegEnumValueW.
1988 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1989 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1991 NTSTATUS status;
1992 DWORD total_size;
1993 char buffer[256], *buf_ptr = buffer;
1994 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1995 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1997 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1998 hkey, index, value, val_count, reserved, type, data, count );
2000 if ((data && !count) || reserved || !value || !val_count)
2001 return ERROR_INVALID_PARAMETER;
2002 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2004 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
2005 if (data) total_size += *count;
2006 total_size = min( sizeof(buffer), total_size );
2008 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
2009 buffer, total_size, &total_size );
2010 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
2012 /* we need to fetch the contents for a string type even if not requested,
2013 * because we need to compute the length of the ASCII string. */
2014 if (value || data || is_string(info->Type))
2016 /* retry with a dynamically allocated buffer */
2017 while (status == STATUS_BUFFER_OVERFLOW)
2019 if (buf_ptr != buffer) heap_free( buf_ptr );
2020 if (!(buf_ptr = heap_alloc( total_size )))
2021 return ERROR_NOT_ENOUGH_MEMORY;
2022 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2023 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
2024 buf_ptr, total_size, &total_size );
2027 if (status) goto done;
2029 if (is_string(info->Type))
2031 DWORD len;
2032 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
2033 total_size - info->DataOffset );
2034 if (data && len)
2036 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
2037 else
2039 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
2040 total_size - info->DataOffset );
2041 /* if the type is REG_SZ and data is not 0-terminated
2042 * and there is enough space in the buffer NT appends a \0 */
2043 if (len < *count && data[len-1]) data[len] = 0;
2046 info->DataLength = len;
2048 else if (data)
2050 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
2051 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2054 if (value && !status)
2056 DWORD len;
2058 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2059 if (len >= *val_count)
2061 status = STATUS_BUFFER_OVERFLOW;
2062 if (*val_count)
2064 len = *val_count - 1;
2065 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2066 value[len] = 0;
2069 else
2071 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2072 value[len] = 0;
2073 *val_count = len;
2077 else status = STATUS_SUCCESS;
2079 if (type) *type = info->Type;
2080 if (count) *count = info->DataLength;
2082 done:
2083 if (buf_ptr != buffer) heap_free( buf_ptr );
2084 return RtlNtStatusToDosError(status);
2087 /******************************************************************************
2088 * RegDeleteValueW [ADVAPI32.@]
2090 * See RegDeleteValueA.
2092 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2094 return RegDeleteKeyValueW( hkey, NULL, name );
2097 /******************************************************************************
2098 * RegDeleteValueA [ADVAPI32.@]
2100 * Delete a value from the registry.
2102 * PARAMS
2103 * hkey [I] Registry handle of the key holding the value
2104 * name [I] Name of the value under hkey to delete
2106 * RETURNS
2107 * Success: ERROR_SUCCESS
2108 * Failure: nonzero error code from Winerror.h
2110 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2112 return RegDeleteKeyValueA( hkey, NULL, name );
2115 /******************************************************************************
2116 * RegDeleteKeyValueW [ADVAPI32.@]
2118 LONG WINAPI RegDeleteKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name )
2120 UNICODE_STRING nameW;
2121 HKEY hsubkey = 0;
2122 LONG ret;
2124 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2126 if (subkey)
2128 if ((ret = RegOpenKeyExW( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey )))
2129 return ret;
2130 hkey = hsubkey;
2133 RtlInitUnicodeString( &nameW, name );
2134 ret = RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2135 if (hsubkey) RegCloseKey( hsubkey );
2136 return ret;
2139 /******************************************************************************
2140 * RegDeleteKeyValueA [ADVAPI32.@]
2142 LONG WINAPI RegDeleteKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name )
2144 UNICODE_STRING nameW;
2145 HKEY hsubkey = 0;
2146 ANSI_STRING nameA;
2147 NTSTATUS status;
2149 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2151 if (subkey)
2153 LONG ret = RegOpenKeyExA( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey );
2154 if (ret)
2155 return ret;
2156 hkey = hsubkey;
2159 RtlInitAnsiString( &nameA, name );
2160 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2162 status = NtDeleteValueKey( hkey, &nameW );
2163 RtlFreeUnicodeString( &nameW );
2166 if (hsubkey) RegCloseKey( hsubkey );
2167 return RtlNtStatusToDosError( status );
2170 /******************************************************************************
2171 * RegLoadKeyW [ADVAPI32.@]
2173 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2174 * registration information from a specified file into that subkey.
2176 * PARAMS
2177 * hkey [I] Handle of open key
2178 * subkey [I] Address of name of subkey
2179 * filename [I] Address of filename for registry information
2181 * RETURNS
2182 * Success: ERROR_SUCCESS
2183 * Failure: nonzero error code from Winerror.h
2185 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2187 OBJECT_ATTRIBUTES destkey, file;
2188 UNICODE_STRING subkeyW, filenameW;
2189 NTSTATUS status;
2191 if (!(hkey = get_special_root_hkey(hkey, 0))) return ERROR_INVALID_HANDLE;
2193 destkey.Length = sizeof(destkey);
2194 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2195 destkey.ObjectName = &subkeyW; /* name of the key */
2196 destkey.Attributes = 0;
2197 destkey.SecurityDescriptor = NULL;
2198 destkey.SecurityQualityOfService = NULL;
2199 RtlInitUnicodeString(&subkeyW, subkey);
2201 file.Length = sizeof(file);
2202 file.RootDirectory = NULL;
2203 file.ObjectName = &filenameW; /* file containing the hive */
2204 file.Attributes = OBJ_CASE_INSENSITIVE;
2205 file.SecurityDescriptor = NULL;
2206 file.SecurityQualityOfService = NULL;
2207 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2209 status = NtLoadKey(&destkey, &file);
2210 RtlFreeUnicodeString(&filenameW);
2211 return RtlNtStatusToDosError( status );
2215 /******************************************************************************
2216 * RegLoadKeyA [ADVAPI32.@]
2218 * See RegLoadKeyW.
2220 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2222 UNICODE_STRING subkeyW, filenameW;
2223 STRING subkeyA, filenameA;
2224 NTSTATUS status;
2225 LONG ret;
2227 RtlInitAnsiString(&subkeyA, subkey);
2228 RtlInitAnsiString(&filenameA, filename);
2230 RtlInitUnicodeString(&subkeyW, NULL);
2231 RtlInitUnicodeString(&filenameW, NULL);
2232 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2233 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2235 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2237 else ret = RtlNtStatusToDosError(status);
2238 RtlFreeUnicodeString(&subkeyW);
2239 RtlFreeUnicodeString(&filenameW);
2240 return ret;
2244 /******************************************************************************
2245 * RegSaveKeyW [ADVAPI32.@]
2247 * Save a key and all of its subkeys and values to a new file in the standard format.
2249 * PARAMS
2250 * hkey [I] Handle of key where save begins
2251 * lpFile [I] Address of filename to save to
2252 * sa [I] Address of security structure
2254 * RETURNS
2255 * Success: ERROR_SUCCESS
2256 * Failure: nonzero error code from Winerror.h
2258 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2260 static const WCHAR format[] =
2261 {'r','e','g','%','0','4','x','.','t','m','p',0};
2262 WCHAR buffer[MAX_PATH];
2263 int count = 0;
2264 LPWSTR nameW;
2265 DWORD ret, err;
2266 HANDLE handle;
2268 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2270 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2271 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2273 err = GetLastError();
2274 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2276 for (;;)
2278 snprintfW( nameW, 16, format, count++ );
2279 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2280 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2281 if (handle != INVALID_HANDLE_VALUE) break;
2282 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2284 /* Something gone haywire ? Please report if this happens abnormally */
2285 if (count >= 100)
2286 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);
2289 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2291 CloseHandle( handle );
2292 if (!ret)
2294 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2296 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2297 debugstr_w(file) );
2298 ret = GetLastError();
2301 if (ret) DeleteFileW( buffer );
2303 done:
2304 SetLastError( err ); /* restore last error code */
2305 return ret;
2309 /******************************************************************************
2310 * RegSaveKeyA [ADVAPI32.@]
2312 * See RegSaveKeyW.
2314 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2316 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2317 NTSTATUS status;
2318 STRING fileA;
2320 RtlInitAnsiString(&fileA, file);
2321 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2322 return RtlNtStatusToDosError( status );
2323 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2327 /******************************************************************************
2328 * RegRestoreKeyW [ADVAPI32.@]
2330 * Read the registry information from a file and copy it over a key.
2332 * PARAMS
2333 * hkey [I] Handle of key where restore begins
2334 * lpFile [I] Address of filename containing saved tree
2335 * dwFlags [I] Optional flags
2337 * RETURNS
2338 * Success: ERROR_SUCCESS
2339 * Failure: nonzero error code from Winerror.h
2341 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2343 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2345 /* It seems to do this check before the hkey check */
2346 if (!lpFile || !*lpFile)
2347 return ERROR_INVALID_PARAMETER;
2349 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2351 /* Check for file existence */
2353 return ERROR_SUCCESS;
2357 /******************************************************************************
2358 * RegRestoreKeyA [ADVAPI32.@]
2360 * See RegRestoreKeyW.
2362 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2364 UNICODE_STRING lpFileW;
2365 LONG ret;
2367 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2368 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2369 RtlFreeUnicodeString( &lpFileW );
2370 return ret;
2374 /******************************************************************************
2375 * RegUnLoadKeyW [ADVAPI32.@]
2377 * Unload a registry key and its subkeys from the registry.
2379 * PARAMS
2380 * hkey [I] Handle of open key
2381 * lpSubKey [I] Address of name of subkey to unload
2383 * RETURNS
2384 * Success: ERROR_SUCCESS
2385 * Failure: nonzero error code from Winerror.h
2387 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2389 DWORD ret;
2390 HKEY shkey;
2391 OBJECT_ATTRIBUTES attr;
2392 UNICODE_STRING subkey;
2394 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2396 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2397 if( ret )
2398 return ERROR_INVALID_PARAMETER;
2400 RtlInitUnicodeString(&subkey, lpSubKey);
2401 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2402 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2404 RegCloseKey(shkey);
2406 return ret;
2410 /******************************************************************************
2411 * RegUnLoadKeyA [ADVAPI32.@]
2413 * See RegUnLoadKeyW.
2415 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2417 UNICODE_STRING lpSubKeyW;
2418 LONG ret;
2420 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2421 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2422 RtlFreeUnicodeString( &lpSubKeyW );
2423 return ret;
2427 /******************************************************************************
2428 * RegReplaceKeyW [ADVAPI32.@]
2430 * Replace the file backing a registry key and all its subkeys with another file.
2432 * PARAMS
2433 * hkey [I] Handle of open key
2434 * lpSubKey [I] Address of name of subkey
2435 * lpNewFile [I] Address of filename for file with new data
2436 * lpOldFile [I] Address of filename for backup file
2438 * RETURNS
2439 * Success: ERROR_SUCCESS
2440 * Failure: nonzero error code from Winerror.h
2442 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2443 LPCWSTR lpOldFile )
2445 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2446 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2447 return ERROR_SUCCESS;
2451 /******************************************************************************
2452 * RegReplaceKeyA [ADVAPI32.@]
2454 * See RegReplaceKeyW.
2456 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2457 LPCSTR lpOldFile )
2459 UNICODE_STRING lpSubKeyW;
2460 UNICODE_STRING lpNewFileW;
2461 UNICODE_STRING lpOldFileW;
2462 LONG ret;
2464 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2465 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2466 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2467 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2468 RtlFreeUnicodeString( &lpOldFileW );
2469 RtlFreeUnicodeString( &lpNewFileW );
2470 RtlFreeUnicodeString( &lpSubKeyW );
2471 return ret;
2475 /******************************************************************************
2476 * RegSetKeySecurity [ADVAPI32.@]
2478 * Set the security of an open registry key.
2480 * PARAMS
2481 * hkey [I] Open handle of key to set
2482 * SecurityInfo [I] Descriptor contents
2483 * pSecurityDesc [I] Address of descriptor for key
2485 * RETURNS
2486 * Success: ERROR_SUCCESS
2487 * Failure: nonzero error code from Winerror.h
2489 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2490 PSECURITY_DESCRIPTOR pSecurityDesc )
2492 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2494 /* It seems to perform this check before the hkey check */
2495 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2496 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2497 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2498 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2499 /* Param OK */
2500 } else
2501 return ERROR_INVALID_PARAMETER;
2503 if (!pSecurityDesc)
2504 return ERROR_INVALID_PARAMETER;
2506 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2508 return RtlNtStatusToDosError( NtSetSecurityObject( hkey, SecurityInfo, pSecurityDesc ) );
2512 /******************************************************************************
2513 * RegGetKeySecurity [ADVAPI32.@]
2515 * Get a copy of the security descriptor for a given registry key.
2517 * PARAMS
2518 * hkey [I] Open handle of key to set
2519 * SecurityInformation [I] Descriptor contents
2520 * pSecurityDescriptor [O] Address of descriptor for key
2521 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2523 * RETURNS
2524 * Success: ERROR_SUCCESS
2525 * Failure: Error code
2527 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2528 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2529 LPDWORD lpcbSecurityDescriptor )
2531 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2532 *lpcbSecurityDescriptor);
2534 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2536 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2537 SecurityInformation, pSecurityDescriptor,
2538 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2542 /******************************************************************************
2543 * RegFlushKey [ADVAPI32.@]
2545 * Immediately write a registry key to registry.
2547 * PARAMS
2548 * hkey [I] Handle of key to write
2550 * RETURNS
2551 * Success: ERROR_SUCCESS
2552 * Failure: Error code
2554 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2556 hkey = get_special_root_hkey( hkey, 0 );
2557 if (!hkey) return ERROR_INVALID_HANDLE;
2559 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2563 /******************************************************************************
2564 * RegConnectRegistryW [ADVAPI32.@]
2566 * Establish a connection to a predefined registry key on another computer.
2568 * PARAMS
2569 * lpMachineName [I] Address of name of remote computer
2570 * hHey [I] Predefined registry handle
2571 * phkResult [I] Address of buffer for remote registry handle
2573 * RETURNS
2574 * Success: ERROR_SUCCESS
2575 * Failure: nonzero error code from Winerror.h
2577 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2578 PHKEY phkResult )
2580 LONG ret;
2582 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName), hKey, phkResult);
2584 if (!lpMachineName || !*lpMachineName) {
2585 /* Use the local machine name */
2586 ret = RegOpenKeyW( hKey, NULL, phkResult );
2588 else {
2589 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2590 DWORD len = sizeof(compName) / sizeof(WCHAR);
2592 /* MSDN says lpMachineName must start with \\ : not so */
2593 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2594 lpMachineName += 2;
2595 if (GetComputerNameW(compName, &len))
2597 if (!strcmpiW(lpMachineName, compName))
2598 ret = RegOpenKeyW(hKey, NULL, phkResult);
2599 else
2601 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2602 ret = ERROR_BAD_NETPATH;
2605 else
2606 ret = GetLastError();
2608 return ret;
2612 /******************************************************************************
2613 * RegConnectRegistryA [ADVAPI32.@]
2615 * See RegConnectRegistryW.
2617 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2619 UNICODE_STRING machineW;
2620 LONG ret;
2622 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2623 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2624 RtlFreeUnicodeString( &machineW );
2625 return ret;
2629 /******************************************************************************
2630 * RegNotifyChangeKeyValue [ADVAPI32.@]
2632 * Notify the caller about changes to the attributes or contents of a registry key.
2634 * PARAMS
2635 * hkey [I] Handle of key to watch
2636 * fWatchSubTree [I] Flag for subkey notification
2637 * fdwNotifyFilter [I] Changes to be reported
2638 * hEvent [I] Handle of signaled event
2639 * fAsync [I] Flag for asynchronous reporting
2641 * RETURNS
2642 * Success: ERROR_SUCCESS
2643 * Failure: nonzero error code from Winerror.h
2645 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2646 DWORD fdwNotifyFilter, HANDLE hEvent,
2647 BOOL fAsync )
2649 NTSTATUS status;
2650 IO_STATUS_BLOCK iosb;
2652 hkey = get_special_root_hkey( hkey, 0 );
2653 if (!hkey) return ERROR_INVALID_HANDLE;
2655 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2656 hEvent, fAsync);
2658 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2659 fdwNotifyFilter, fAsync, NULL, 0,
2660 fWatchSubTree);
2662 if (status && status != STATUS_TIMEOUT)
2663 return RtlNtStatusToDosError( status );
2665 return ERROR_SUCCESS;
2668 /******************************************************************************
2669 * RegOpenUserClassesRoot [ADVAPI32.@]
2671 * Open the HKEY_CLASSES_ROOT key for a user.
2673 * PARAMS
2674 * hToken [I] Handle of token representing the user
2675 * dwOptions [I] Reserved, must be 0
2676 * samDesired [I] Desired access rights
2677 * phkResult [O] Destination for the resulting key handle
2679 * RETURNS
2680 * Success: ERROR_SUCCESS
2681 * Failure: nonzero error code from Winerror.h
2683 * NOTES
2684 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2685 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2686 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2688 LSTATUS WINAPI RegOpenUserClassesRoot(
2689 HANDLE hToken,
2690 DWORD dwOptions,
2691 REGSAM samDesired,
2692 PHKEY phkResult
2695 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2697 *phkResult = HKEY_CLASSES_ROOT;
2698 return ERROR_SUCCESS;
2701 /******************************************************************************
2702 * load_string [Internal]
2704 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2705 * avoid importing user32, which is higher level than advapi32. Helper for
2706 * RegLoadMUIString.
2708 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2710 HGLOBAL hMemory;
2711 HRSRC hResource;
2712 WCHAR *pString;
2713 int idxString;
2715 /* Negative values have to be inverted. */
2716 if (HIWORD(resId) == 0xffff)
2717 resId = (UINT)(-((INT)resId));
2719 /* Load the resource into memory and get a pointer to it. */
2720 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2721 if (!hResource) return 0;
2722 hMemory = LoadResource(hModule, hResource);
2723 if (!hMemory) return 0;
2724 pString = LockResource(hMemory);
2726 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2727 idxString = resId & 0xf;
2728 while (idxString--) pString += *pString + 1;
2730 /* If no buffer is given, return length of the string. */
2731 if (!pwszBuffer) return *pString;
2733 /* Else copy over the string, respecting the buffer size. */
2734 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2735 if (cMaxChars >= 0) {
2736 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2737 pwszBuffer[cMaxChars] = '\0';
2740 return cMaxChars;
2743 /******************************************************************************
2744 * RegLoadMUIStringW [ADVAPI32.@]
2746 * Load the localized version of a string resource from some PE, respective
2747 * id and path of which are given in the registry value in the format
2748 * @[path]\dllname,-resourceId
2750 * PARAMS
2751 * hKey [I] Key, of which to load the string value from.
2752 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2753 * pszBuffer [O] Buffer to store the localized string in.
2754 * cbBuffer [I] Size of the destination buffer in bytes.
2755 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2756 * dwFlags [I] None supported yet.
2757 * pszBaseDir [I] Not supported yet.
2759 * RETURNS
2760 * Success: ERROR_SUCCESS,
2761 * Failure: nonzero error code from winerror.h
2763 * NOTES
2764 * This is an API of Windows Vista, which wasn't available at the time this code
2765 * was written. We have to check for the correct behaviour once it's available.
2767 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2768 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2770 DWORD dwValueType, cbData;
2771 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2772 LONG result;
2774 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2775 "dwFlags = %d, pwszBaseDir = %s)\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2776 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2778 /* Parameter sanity checks. */
2779 if (!hKey || !pwszBuffer)
2780 return ERROR_INVALID_PARAMETER;
2782 if (pwszBaseDir && *pwszBaseDir) {
2783 FIXME("BaseDir parameter not yet supported!\n");
2784 return ERROR_INVALID_PARAMETER;
2787 /* Check for value existence and correctness of its type, allocate a buffer and load it. */
2788 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2789 if (result != ERROR_SUCCESS) goto cleanup;
2790 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2791 result = ERROR_FILE_NOT_FOUND;
2792 goto cleanup;
2794 pwszTempBuffer = heap_alloc(cbData);
2795 if (!pwszTempBuffer) {
2796 result = ERROR_NOT_ENOUGH_MEMORY;
2797 goto cleanup;
2799 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2800 if (result != ERROR_SUCCESS) goto cleanup;
2802 /* Expand environment variables, if appropriate, or copy the original string over. */
2803 if (dwValueType == REG_EXPAND_SZ) {
2804 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2805 if (!cbData) goto cleanup;
2806 pwszExpandedBuffer = heap_alloc(cbData);
2807 if (!pwszExpandedBuffer) {
2808 result = ERROR_NOT_ENOUGH_MEMORY;
2809 goto cleanup;
2811 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2812 } else {
2813 pwszExpandedBuffer = heap_alloc(cbData);
2814 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2817 /* If the value references a resource based string, parse the value and load the string.
2818 * Else just copy over the original value. */
2819 result = ERROR_SUCCESS;
2820 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2821 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2822 } else {
2823 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2824 UINT uiStringId;
2825 HMODULE hModule;
2827 /* Format of the expanded value is 'path_to_dll,-resId' */
2828 if (!pComma || pComma[1] != '-') {
2829 result = ERROR_BADKEY;
2830 goto cleanup;
2833 uiStringId = atoiW(pComma+2);
2834 *pComma = '\0';
2836 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2837 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2838 result = ERROR_BADKEY;
2839 FreeLibrary(hModule);
2842 cleanup:
2843 heap_free(pwszTempBuffer);
2844 heap_free(pwszExpandedBuffer);
2845 return result;
2848 /******************************************************************************
2849 * RegLoadMUIStringA [ADVAPI32.@]
2851 * See RegLoadMUIStringW
2853 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2854 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2856 UNICODE_STRING valueW, baseDirW;
2857 WCHAR *pwszBuffer;
2858 DWORD cbData = cbBuffer * sizeof(WCHAR);
2859 LONG result;
2861 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2862 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2863 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2864 !(pwszBuffer = heap_alloc(cbData)))
2866 result = ERROR_NOT_ENOUGH_MEMORY;
2867 goto cleanup;
2870 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2871 baseDirW.Buffer);
2873 if (result == ERROR_SUCCESS) {
2874 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2875 if (pcbData)
2876 *pcbData = cbData;
2879 cleanup:
2880 heap_free(pwszBuffer);
2881 RtlFreeUnicodeString(&baseDirW);
2882 RtlFreeUnicodeString(&valueW);
2884 return result;
2887 /******************************************************************************
2888 * RegDisablePredefinedCache [ADVAPI32.@]
2890 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2892 * PARAMS
2893 * None.
2895 * RETURNS
2896 * Success: ERROR_SUCCESS
2897 * Failure: nonzero error code from Winerror.h
2899 * NOTES
2900 * This is useful for services that use impersonation.
2902 LSTATUS WINAPI RegDisablePredefinedCache(void)
2904 HKEY hkey_current_user;
2905 int idx = HandleToUlong(HKEY_CURRENT_USER) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
2907 /* prevent caching of future requests */
2908 hkcu_cache_disabled = TRUE;
2910 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2912 if (hkey_current_user)
2913 NtClose( hkey_current_user );
2915 return ERROR_SUCCESS;
2918 /******************************************************************************
2919 * RegDeleteTreeW [ADVAPI32.@]
2922 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2924 LONG ret;
2925 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2926 DWORD dwMaxLen, dwSize;
2927 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2928 HKEY hSubKey = hKey;
2930 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2932 if(lpszSubKey)
2934 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2935 if (ret) return ret;
2938 /* Get highest length for keys, values */
2939 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2940 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2941 if (ret) goto cleanup;
2943 dwMaxSubkeyLen++;
2944 dwMaxValueLen++;
2945 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2946 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2948 /* Name too big: alloc a buffer for it */
2949 if (!(lpszName = heap_alloc( dwMaxLen*sizeof(WCHAR))))
2951 ret = ERROR_NOT_ENOUGH_MEMORY;
2952 goto cleanup;
2957 /* Recursively delete all the subkeys */
2958 while (TRUE)
2960 dwSize = dwMaxLen;
2961 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2962 NULL, NULL, NULL)) break;
2964 ret = RegDeleteTreeW(hSubKey, lpszName);
2965 if (ret) goto cleanup;
2968 if (lpszSubKey)
2969 ret = RegDeleteKeyW(hKey, lpszSubKey);
2970 else
2971 while (TRUE)
2973 dwSize = dwMaxLen;
2974 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2975 NULL, NULL, NULL, NULL)) break;
2977 ret = RegDeleteValueW(hKey, lpszName);
2978 if (ret) goto cleanup;
2981 cleanup:
2982 /* Free buffer if allocated */
2983 if (lpszName != szNameBuf)
2984 heap_free( lpszName);
2985 if(lpszSubKey)
2986 RegCloseKey(hSubKey);
2987 return ret;
2990 /******************************************************************************
2991 * RegDeleteTreeA [ADVAPI32.@]
2994 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2996 LONG ret;
2997 UNICODE_STRING lpszSubKeyW;
2999 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
3000 else lpszSubKeyW.Buffer = NULL;
3001 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
3002 RtlFreeUnicodeString( &lpszSubKeyW );
3003 return ret;
3006 /******************************************************************************
3007 * RegDisableReflectionKey [ADVAPI32.@]
3010 LONG WINAPI RegDisableReflectionKey(HKEY base)
3012 FIXME("%p: stub\n", base);
3013 return ERROR_SUCCESS;