dwrite/tests: Fix some test failures on older dwrite versions.
[wine.git] / dlls / advapi32 / registry.c
blob7675a598c38e3a77d68a0eb3006d3972a6c17cd0
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, const UNICODE_STRING *name )
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;
131 if (!force_wow32) status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class, options, dispos );
133 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
135 HANDLE subkey, root = attr->RootDirectory;
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, &str )))
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( (PHANDLE)retkey, 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 return status;
183 /* wrapper for NtOpenKey to handle Wow6432 nodes */
184 static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
186 NTSTATUS status;
187 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
188 HANDLE subkey, root = attr->RootDirectory;
189 WCHAR *buffer = attr->ObjectName->Buffer;
190 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
191 UNICODE_STRING str;
193 if (!force_wow32) return NtOpenKey( (HANDLE *)retkey, access, attr );
195 if (len && buffer[0] == '\\') return STATUS_OBJECT_PATH_INVALID;
196 while (i < len && buffer[i] != '\\') i++;
197 attrs = attr->Attributes;
198 attr->ObjectName = &str;
200 for (;;)
202 str.Buffer = buffer + pos;
203 str.Length = (i - pos) * sizeof(WCHAR);
204 if (force_wow32 && pos)
206 if (is_wow6432node( &str )) force_wow32 = FALSE;
207 else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
209 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
210 attr->RootDirectory = subkey;
211 force_wow32 = FALSE;
214 if (i == len)
216 attr->Attributes = attrs;
217 status = NtOpenKey( (PHANDLE)retkey, access, attr );
219 else
221 attr->Attributes = attrs & ~OBJ_OPENLINK;
222 status = NtOpenKey( &subkey, access, attr );
224 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
225 if (status) return status;
226 if (i == len) break;
227 attr->RootDirectory = subkey;
228 while (i < len && buffer[i] == '\\') i++;
229 pos = i;
230 while (i < len && buffer[i] != '\\') i++;
232 return status;
235 /* create one of the HKEY_* special root keys */
236 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
238 HKEY ret = 0;
239 int idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
241 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CURRENT_USER))
243 if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
244 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
246 /* don't cache the key in the table if caching is disabled */
247 if (hkcu_cache_disabled)
248 return hkey;
250 else
252 OBJECT_ATTRIBUTES attr;
253 UNICODE_STRING name;
255 attr.Length = sizeof(attr);
256 attr.RootDirectory = 0;
257 attr.ObjectName = &name;
258 attr.Attributes = 0;
259 attr.SecurityDescriptor = NULL;
260 attr.SecurityQualityOfService = NULL;
261 RtlInitUnicodeString( &name, root_key_names[idx] );
262 if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0;
263 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
266 if (!(access & (KEY_WOW64_64KEY | KEY_WOW64_32KEY)))
268 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
269 ret = hkey;
270 else
271 NtClose( hkey ); /* somebody beat us to it */
273 else
274 ret = hkey;
275 return ret;
278 /* map the hkey from special root to normal key if necessary */
279 static inline HKEY get_special_root_hkey( HKEY hkey, REGSAM access )
281 HKEY ret = hkey;
283 if ((HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST))
284 && (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
286 REGSAM mask = 0;
288 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT))
289 mask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
291 if ((access & mask) ||
292 !(ret = special_root_keys[HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)]))
293 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED | (access & mask) );
295 return ret;
299 /******************************************************************************
300 * RegOverridePredefKey [ADVAPI32.@]
302 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
304 HKEY old_key;
305 int idx;
307 TRACE("(%p %p)\n", hkey, override);
309 if ((HandleToUlong(hkey) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST))
310 || (HandleToUlong(hkey) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
311 return ERROR_INVALID_PARAMETER;
312 idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
314 if (override)
316 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
317 GetCurrentProcess(), (HANDLE *)&override,
318 0, 0, DUPLICATE_SAME_ACCESS );
319 if (status) return RtlNtStatusToDosError( status );
322 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
323 if (old_key) NtClose( old_key );
324 return ERROR_SUCCESS;
328 /******************************************************************************
329 * RegCreateKeyExW [ADVAPI32.@]
331 * See RegCreateKeyExA.
333 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
334 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
335 PHKEY retkey, LPDWORD dispos )
337 OBJECT_ATTRIBUTES attr;
338 UNICODE_STRING nameW, classW;
340 if (reserved) return ERROR_INVALID_PARAMETER;
341 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
343 attr.Length = sizeof(attr);
344 attr.RootDirectory = hkey;
345 attr.ObjectName = &nameW;
346 attr.Attributes = 0;
347 attr.SecurityDescriptor = NULL;
348 attr.SecurityQualityOfService = NULL;
349 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
350 RtlInitUnicodeString( &nameW, name );
351 RtlInitUnicodeString( &classW, class );
353 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
357 /******************************************************************************
358 * RegCreateKeyExA [ADVAPI32.@]
360 * Open a registry key, creating it if it doesn't exist.
362 * PARAMS
363 * hkey [I] Handle of the parent registry key
364 * name [I] Name of the new key to open or create
365 * reserved [I] Reserved, pass 0
366 * class [I] The object type of the new key
367 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
368 * access [I] Access level desired
369 * sa [I] Security attributes for the key
370 * retkey [O] Destination for the resulting handle
371 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
373 * RETURNS
374 * Success: ERROR_SUCCESS.
375 * Failure: A standard Win32 error code. retkey remains untouched.
377 * FIXME
378 * MAXIMUM_ALLOWED in access mask not supported by server
380 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
381 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
382 PHKEY retkey, LPDWORD dispos )
384 OBJECT_ATTRIBUTES attr;
385 UNICODE_STRING classW;
386 ANSI_STRING nameA, classA;
387 NTSTATUS status;
389 if (reserved) return ERROR_INVALID_PARAMETER;
390 if (!is_version_nt())
392 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
393 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
395 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
397 attr.Length = sizeof(attr);
398 attr.RootDirectory = hkey;
399 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
400 attr.Attributes = 0;
401 attr.SecurityDescriptor = NULL;
402 attr.SecurityQualityOfService = NULL;
403 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
404 RtlInitAnsiString( &nameA, name );
405 RtlInitAnsiString( &classA, class );
407 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
408 &nameA, FALSE )))
410 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
412 status = create_key( retkey, access, &attr, &classW, options, dispos );
413 RtlFreeUnicodeString( &classW );
416 return RtlNtStatusToDosError( status );
420 /******************************************************************************
421 * RegCreateKeyW [ADVAPI32.@]
423 * Creates the specified reg key.
425 * PARAMS
426 * hKey [I] Handle to an open key.
427 * lpSubKey [I] Name of a key that will be opened or created.
428 * phkResult [O] Receives a handle to the opened or created key.
430 * RETURNS
431 * Success: ERROR_SUCCESS
432 * Failure: nonzero error code defined in Winerror.h
434 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
436 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
437 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
438 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
439 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
443 /******************************************************************************
444 * RegCreateKeyA [ADVAPI32.@]
446 * See RegCreateKeyW.
448 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
450 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
451 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
456 /******************************************************************************
457 * RegOpenKeyExW [ADVAPI32.@]
459 * See RegOpenKeyExA.
461 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
463 OBJECT_ATTRIBUTES attr;
464 UNICODE_STRING nameW;
466 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
467 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++;
469 if (!retkey) return ERROR_INVALID_PARAMETER;
470 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
472 attr.Length = sizeof(attr);
473 attr.RootDirectory = hkey;
474 attr.ObjectName = &nameW;
475 attr.Attributes = 0;
476 attr.SecurityDescriptor = NULL;
477 attr.SecurityQualityOfService = NULL;
478 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
479 RtlInitUnicodeString( &nameW, name );
480 return RtlNtStatusToDosError( open_key( retkey, access, &attr ) );
484 /******************************************************************************
485 * RegOpenKeyExA [ADVAPI32.@]
487 * Open a registry key.
489 * PARAMS
490 * hkey [I] Handle of open key
491 * name [I] Name of subkey to open
492 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
493 * access [I] Security access mask
494 * retkey [O] Handle to open key
496 * RETURNS
497 * Success: ERROR_SUCCESS
498 * Failure: A standard Win32 error code. retkey is set to 0.
500 * NOTES
501 * Unlike RegCreateKeyExA(), this function will not create the key if it
502 * does not exist.
504 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
506 OBJECT_ATTRIBUTES attr;
507 STRING nameA;
508 NTSTATUS status;
510 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
511 else
513 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
514 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++;
517 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
519 attr.Length = sizeof(attr);
520 attr.RootDirectory = hkey;
521 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
522 attr.Attributes = 0;
523 attr.SecurityDescriptor = NULL;
524 attr.SecurityQualityOfService = NULL;
525 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
527 RtlInitAnsiString( &nameA, name );
528 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
529 &nameA, FALSE )))
531 status = open_key( retkey, access, &attr );
533 return RtlNtStatusToDosError( status );
537 /******************************************************************************
538 * RegOpenKeyW [ADVAPI32.@]
540 * See RegOpenKeyA.
542 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
544 if (!retkey)
545 return ERROR_INVALID_PARAMETER;
547 if (!name || !*name)
549 *retkey = hkey;
550 return ERROR_SUCCESS;
552 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
556 /******************************************************************************
557 * RegOpenKeyA [ADVAPI32.@]
559 * Open a registry key.
561 * PARAMS
562 * hkey [I] Handle of parent key to open the new key under
563 * name [I] Name of the key under hkey to open
564 * retkey [O] Destination for the resulting Handle
566 * RETURNS
567 * Success: ERROR_SUCCESS
568 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
570 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
572 if (!retkey)
573 return ERROR_INVALID_PARAMETER;
575 if (!name || !*name)
577 *retkey = hkey;
578 return ERROR_SUCCESS;
580 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
584 /******************************************************************************
585 * RegOpenCurrentUser [ADVAPI32.@]
587 * Get a handle to the HKEY_CURRENT_USER key for the user
588 * the current thread is impersonating.
590 * PARAMS
591 * access [I] Desired access rights to the key
592 * retkey [O] Handle to the opened key
594 * RETURNS
595 * Success: ERROR_SUCCESS
596 * Failure: nonzero error code from Winerror.h
598 * FIXME
599 * This function is supposed to retrieve a handle to the
600 * HKEY_CURRENT_USER for the user the current thread is impersonating.
601 * Since Wine does not currently allow threads to impersonate other users,
602 * this stub should work fine.
604 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
606 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
611 /******************************************************************************
612 * RegEnumKeyExW [ADVAPI32.@]
614 * Enumerate subkeys of the specified open registry key.
616 * PARAMS
617 * hkey [I] Handle to key to enumerate
618 * index [I] Index of subkey to enumerate
619 * name [O] Buffer for subkey name
620 * name_len [O] Size of subkey buffer
621 * reserved [I] Reserved
622 * class [O] Buffer for class string
623 * class_len [O] Size of class buffer
624 * ft [O] Time key last written to
626 * RETURNS
627 * Success: ERROR_SUCCESS
628 * Failure: System error code. If there are no more subkeys available, the
629 * function returns ERROR_NO_MORE_ITEMS.
631 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
632 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
634 NTSTATUS status;
635 char buffer[256], *buf_ptr = buffer;
636 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
637 DWORD total_size;
639 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
640 name_len ? *name_len : 0, reserved, class, class_len, ft );
642 if (reserved) return ERROR_INVALID_PARAMETER;
643 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
645 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
646 buffer, sizeof(buffer), &total_size );
648 while (status == STATUS_BUFFER_OVERFLOW)
650 /* retry with a dynamically allocated buffer */
651 if (buf_ptr != buffer) heap_free( buf_ptr );
652 if (!(buf_ptr = heap_alloc( total_size )))
653 return ERROR_NOT_ENOUGH_MEMORY;
654 info = (KEY_NODE_INFORMATION *)buf_ptr;
655 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
656 buf_ptr, total_size, &total_size );
659 if (!status)
661 DWORD len = info->NameLength / sizeof(WCHAR);
662 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
664 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
666 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
667 status = STATUS_BUFFER_OVERFLOW;
668 else
670 *name_len = len;
671 memcpy( name, info->Name, info->NameLength );
672 name[len] = 0;
673 if (class_len)
675 *class_len = cls_len;
676 if (class)
678 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
679 class[cls_len] = 0;
685 if (buf_ptr != buffer) heap_free( buf_ptr );
686 return RtlNtStatusToDosError( status );
690 /******************************************************************************
691 * RegEnumKeyExA [ADVAPI32.@]
693 * See RegEnumKeyExW.
695 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
696 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
698 NTSTATUS status;
699 char buffer[256], *buf_ptr = buffer;
700 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
701 DWORD total_size;
703 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
704 name_len ? *name_len : 0, reserved, class, class_len, ft );
706 if (reserved) return ERROR_INVALID_PARAMETER;
707 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
709 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
710 buffer, sizeof(buffer), &total_size );
712 while (status == STATUS_BUFFER_OVERFLOW)
714 /* retry with a dynamically allocated buffer */
715 if (buf_ptr != buffer) heap_free( buf_ptr );
716 if (!(buf_ptr = heap_alloc( total_size )))
717 return ERROR_NOT_ENOUGH_MEMORY;
718 info = (KEY_NODE_INFORMATION *)buf_ptr;
719 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
720 buf_ptr, total_size, &total_size );
723 if (!status)
725 DWORD len, cls_len;
727 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
728 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
729 info->ClassLength );
730 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
732 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
733 status = STATUS_BUFFER_OVERFLOW;
734 else
736 *name_len = len;
737 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
738 name[len] = 0;
739 if (class_len)
741 *class_len = cls_len;
742 if (class)
744 RtlUnicodeToMultiByteN( class, cls_len, NULL,
745 (WCHAR *)(buf_ptr + info->ClassOffset),
746 info->ClassLength );
747 class[cls_len] = 0;
753 if (buf_ptr != buffer) heap_free( buf_ptr );
754 return RtlNtStatusToDosError( status );
758 /******************************************************************************
759 * RegEnumKeyW [ADVAPI32.@]
761 * Enumerates subkeys of the specified open reg key.
763 * PARAMS
764 * hKey [I] Handle to an open key.
765 * dwIndex [I] Index of the subkey of hKey to retrieve.
766 * lpName [O] Name of the subkey.
767 * cchName [I] Size of lpName in TCHARS.
769 * RETURNS
770 * Success: ERROR_SUCCESS
771 * Failure: system error code. If there are no more subkeys available, the
772 * function returns ERROR_NO_MORE_ITEMS.
774 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
776 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
780 /******************************************************************************
781 * RegEnumKeyA [ADVAPI32.@]
783 * See RegEnumKeyW.
785 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
787 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
791 /******************************************************************************
792 * RegQueryInfoKeyW [ADVAPI32.@]
794 * Retrieves information about the specified registry key.
796 * PARAMS
797 * hkey [I] Handle to key to query
798 * class [O] Buffer for class string
799 * class_len [O] Size of class string buffer
800 * reserved [I] Reserved
801 * subkeys [O] Buffer for number of subkeys
802 * max_subkey [O] Buffer for longest subkey name length
803 * max_class [O] Buffer for longest class string length
804 * values [O] Buffer for number of value entries
805 * max_value [O] Buffer for longest value name length
806 * max_data [O] Buffer for longest value data length
807 * security [O] Buffer for security descriptor length
808 * modif [O] Modification time
810 * RETURNS
811 * Success: ERROR_SUCCESS
812 * Failure: system error code.
814 * NOTES
815 * - win95 allows class to be valid and class_len to be NULL
816 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
817 * - both allow class to be NULL and class_len to be NULL
818 * (it's hard to test validity, so test !NULL instead)
820 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
821 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
822 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
823 LPDWORD security, FILETIME *modif )
825 NTSTATUS status;
826 char buffer[256], *buf_ptr = buffer;
827 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
828 DWORD total_size;
830 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
831 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
833 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
834 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
836 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
837 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
839 if (class)
841 /* retry with a dynamically allocated buffer */
842 while (status == STATUS_BUFFER_OVERFLOW)
844 if (buf_ptr != buffer) heap_free( buf_ptr );
845 if (!(buf_ptr = heap_alloc( total_size )))
846 return ERROR_NOT_ENOUGH_MEMORY;
847 info = (KEY_FULL_INFORMATION *)buf_ptr;
848 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
851 if (status) goto done;
853 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
855 status = STATUS_BUFFER_OVERFLOW;
857 else
859 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
860 class[info->ClassLength/sizeof(WCHAR)] = 0;
863 else status = STATUS_SUCCESS;
865 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
866 if (subkeys) *subkeys = info->SubKeys;
867 if (max_subkey) *max_subkey = info->MaxNameLen;
868 if (max_class) *max_class = info->MaxClassLen;
869 if (values) *values = info->Values;
870 if (max_value) *max_value = info->MaxValueNameLen;
871 if (max_data) *max_data = info->MaxValueDataLen;
872 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
874 done:
875 if (buf_ptr != buffer) heap_free( buf_ptr );
876 return RtlNtStatusToDosError( status );
880 /******************************************************************************
881 * RegQueryMultipleValuesA [ADVAPI32.@]
883 * Retrieves the type and data for a list of value names associated with a key.
885 * PARAMS
886 * hKey [I] Handle to an open key.
887 * val_list [O] Array of VALENT structures that describes the entries.
888 * num_vals [I] Number of elements in val_list.
889 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
890 * ldwTotsize [I/O] Size of lpValueBuf.
892 * RETURNS
893 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
894 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
895 * bytes.
897 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
898 LPSTR lpValueBuf, LPDWORD ldwTotsize )
900 unsigned int i;
901 DWORD maxBytes = *ldwTotsize;
902 HRESULT status;
903 LPSTR bufptr = lpValueBuf;
904 *ldwTotsize = 0;
906 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
908 for(i=0; i < num_vals; ++i)
911 val_list[i].ve_valuelen=0;
912 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
913 if(status != ERROR_SUCCESS)
915 return status;
918 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
920 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
921 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
922 if(status != ERROR_SUCCESS)
924 return status;
927 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
929 bufptr += val_list[i].ve_valuelen;
932 *ldwTotsize += val_list[i].ve_valuelen;
934 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
938 /******************************************************************************
939 * RegQueryMultipleValuesW [ADVAPI32.@]
941 * See RegQueryMultipleValuesA.
943 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
944 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
946 unsigned int i;
947 DWORD maxBytes = *ldwTotsize;
948 HRESULT status;
949 LPSTR bufptr = (LPSTR)lpValueBuf;
950 *ldwTotsize = 0;
952 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
954 for(i=0; i < num_vals; ++i)
956 val_list[i].ve_valuelen=0;
957 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
958 if(status != ERROR_SUCCESS)
960 return status;
963 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
965 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
966 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
967 if(status != ERROR_SUCCESS)
969 return status;
972 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
974 bufptr += val_list[i].ve_valuelen;
977 *ldwTotsize += val_list[i].ve_valuelen;
979 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
982 /******************************************************************************
983 * RegQueryInfoKeyA [ADVAPI32.@]
985 * Retrieves information about a registry key.
987 * PARAMS
988 * hKey [I] Handle to an open key.
989 * lpClass [O] Class string of the key.
990 * lpcClass [I/O] size of lpClass.
991 * lpReserved [I] Reserved; must be NULL.
992 * lpcSubKeys [O] Number of subkeys contained by the key.
993 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
994 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
995 * class in TCHARS.
996 * lpcValues [O] Number of values associated with the key.
997 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
998 * lpcMaxValueLen [O] Longest data component among the key's values
999 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
1000 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
1002 * RETURNS
1003 * Success: ERROR_SUCCESS
1004 * Failure: nonzero error code from Winerror.h
1006 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
1007 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
1008 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
1009 LPDWORD security, FILETIME *modif )
1011 NTSTATUS status;
1012 char buffer[256], *buf_ptr = buffer;
1013 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
1014 DWORD total_size, len;
1016 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
1017 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
1019 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
1020 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1022 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
1023 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1025 if (class || class_len)
1027 /* retry with a dynamically allocated buffer */
1028 while (status == STATUS_BUFFER_OVERFLOW)
1030 if (buf_ptr != buffer) heap_free( buf_ptr );
1031 if (!(buf_ptr = heap_alloc( total_size )))
1032 return ERROR_NOT_ENOUGH_MEMORY;
1033 info = (KEY_FULL_INFORMATION *)buf_ptr;
1034 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
1037 if (status) goto done;
1039 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
1040 if (class_len)
1042 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
1043 *class_len = len;
1045 if (class && !status)
1047 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
1048 info->ClassLength );
1049 class[len] = 0;
1052 else status = STATUS_SUCCESS;
1054 if (subkeys) *subkeys = info->SubKeys;
1055 if (max_subkey) *max_subkey = info->MaxNameLen;
1056 if (max_class) *max_class = info->MaxClassLen;
1057 if (values) *values = info->Values;
1058 if (max_value) *max_value = info->MaxValueNameLen;
1059 if (max_data) *max_data = info->MaxValueDataLen;
1060 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
1062 done:
1063 if (buf_ptr != buffer) heap_free( buf_ptr );
1064 return RtlNtStatusToDosError( status );
1068 /******************************************************************************
1069 * RegCloseKey [ADVAPI32.@]
1071 * Close an open registry key.
1073 * PARAMS
1074 * hkey [I] Handle of key to close
1076 * RETURNS
1077 * Success: ERROR_SUCCESS
1078 * Failure: Error code
1080 LSTATUS WINAPI RegCloseKey( HKEY hkey )
1082 if (!hkey) return ERROR_INVALID_HANDLE;
1083 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
1084 return RtlNtStatusToDosError( NtClose( hkey ) );
1088 /******************************************************************************
1089 * RegDeleteKeyExW [ADVAPI32.@]
1091 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
1093 DWORD ret;
1094 HKEY tmp;
1096 if (!name) return ERROR_INVALID_PARAMETER;
1098 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
1100 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1101 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
1103 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1104 RegCloseKey( tmp );
1106 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
1107 return ret;
1111 /******************************************************************************
1112 * RegDeleteKeyW [ADVAPI32.@]
1114 * See RegDeleteKeyA.
1116 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
1118 return RegDeleteKeyExW( hkey, name, 0, 0 );
1122 /******************************************************************************
1123 * RegDeleteKeyExA [ADVAPI32.@]
1125 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1127 DWORD ret;
1128 HKEY tmp;
1130 if (!name) return ERROR_INVALID_PARAMETER;
1132 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
1134 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1135 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1137 if (!is_version_nt()) /* win95 does recursive key deletes */
1139 CHAR sub[MAX_PATH];
1141 while(!RegEnumKeyA(tmp, 0, sub, sizeof(sub)))
1143 if(RegDeleteKeyExA(tmp, sub, access, reserved)) /* recurse */
1144 break;
1147 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1148 RegCloseKey( tmp );
1150 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1151 return ret;
1155 /******************************************************************************
1156 * RegDeleteKeyA [ADVAPI32.@]
1158 * Delete a registry key.
1160 * PARAMS
1161 * hkey [I] Handle to parent key containing the key to delete
1162 * name [I] Name of the key user hkey to delete
1164 * NOTES
1166 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1167 * right. In reality, it opens a new handle with DELETE access.
1169 * RETURNS
1170 * Success: ERROR_SUCCESS
1171 * Failure: Error code
1173 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1175 return RegDeleteKeyExA( hkey, name, 0, 0 );
1180 /******************************************************************************
1181 * RegSetValueExW [ADVAPI32.@]
1183 * Set the data and contents of a registry value.
1185 * PARAMS
1186 * hkey [I] Handle of key to set value for
1187 * name [I] Name of value to set
1188 * reserved [I] Reserved, must be zero
1189 * type [I] Type of the value being set
1190 * data [I] The new contents of the value to set
1191 * count [I] Size of data
1193 * RETURNS
1194 * Success: ERROR_SUCCESS
1195 * Failure: Error code
1197 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1198 DWORD type, const BYTE *data, DWORD count )
1200 UNICODE_STRING nameW;
1202 /* no need for version check, not implemented on win9x anyway */
1204 if (data && ((ULONG_PTR)data >> 16) == 0) return ERROR_NOACCESS;
1206 if (count && is_string(type))
1208 LPCWSTR str = (LPCWSTR)data;
1209 /* if user forgot to count terminating null, add it (yes NT does this) */
1210 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1211 count += sizeof(WCHAR);
1213 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1215 RtlInitUnicodeString( &nameW, name );
1216 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1220 /******************************************************************************
1221 * RegSetValueExA [ADVAPI32.@]
1223 * See RegSetValueExW.
1225 * NOTES
1226 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1227 * NT does definitely care (aj)
1229 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1230 const BYTE *data, DWORD count )
1232 ANSI_STRING nameA;
1233 UNICODE_STRING nameW;
1234 WCHAR *dataW = NULL;
1235 NTSTATUS status;
1237 if (!is_version_nt()) /* win95 */
1239 if (type == REG_SZ)
1241 if (!data) return ERROR_INVALID_PARAMETER;
1242 count = strlen((const char *)data) + 1;
1245 else if (count && is_string(type))
1247 /* if user forgot to count terminating null, add it (yes NT does this) */
1248 if (data[count-1] && !data[count]) count++;
1251 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1253 if (is_string( type )) /* need to convert to Unicode */
1255 DWORD lenW;
1256 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1257 if (!(dataW = heap_alloc( lenW ))) return ERROR_OUTOFMEMORY;
1258 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1259 count = lenW;
1260 data = (BYTE *)dataW;
1263 RtlInitAnsiString( &nameA, name );
1264 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1266 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1267 RtlFreeUnicodeString( &nameW );
1269 heap_free( dataW );
1270 return RtlNtStatusToDosError( status );
1274 /******************************************************************************
1275 * RegSetValueW [ADVAPI32.@]
1277 * Sets the data for the default or unnamed value of a reg key.
1279 * PARAMS
1280 * hkey [I] Handle to an open key.
1281 * subkey [I] Name of a subkey of hKey.
1282 * type [I] Type of information to store.
1283 * data [I] String that contains the data to set for the default value.
1284 * count [I] Ignored.
1286 * RETURNS
1287 * Success: ERROR_SUCCESS
1288 * Failure: nonzero error code from Winerror.h
1290 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR subkey, DWORD type, LPCWSTR data, DWORD count )
1292 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(subkey), type, debugstr_w(data), count );
1294 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1296 return RegSetKeyValueW( hkey, subkey, NULL, type, data, (strlenW(data) + 1)*sizeof(WCHAR) );
1299 /******************************************************************************
1300 * RegSetValueA [ADVAPI32.@]
1302 * See RegSetValueW.
1304 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR subkey, DWORD type, LPCSTR data, DWORD count )
1306 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(subkey), type, debugstr_a(data), count );
1308 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1310 return RegSetKeyValueA( hkey, subkey, NULL, type, data, strlen(data) + 1 );
1313 /******************************************************************************
1314 * RegSetKeyValueW [ADVAPI32.@]
1316 LONG WINAPI RegSetKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name, DWORD type, const void *data, DWORD len )
1318 HKEY hsubkey = NULL;
1319 DWORD ret;
1321 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey, debugstr_w(subkey), debugstr_w(name), type, data, len );
1323 if (subkey && subkey[0]) /* need to create the subkey */
1325 if ((ret = RegCreateKeyW( hkey, subkey, &hsubkey )) != ERROR_SUCCESS) return ret;
1326 hkey = hsubkey;
1329 ret = RegSetValueExW( hkey, name, 0, type, (const BYTE*)data, len );
1330 if (hsubkey) RegCloseKey( hsubkey );
1331 return ret;
1334 /******************************************************************************
1335 * RegSetKeyValueA [ADVAPI32.@]
1337 LONG WINAPI RegSetKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name, DWORD type, const void *data, DWORD len )
1339 HKEY hsubkey = NULL;
1340 DWORD ret;
1342 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey, debugstr_a(subkey), debugstr_a(name), type, data, len );
1344 if (subkey && subkey[0]) /* need to create the subkey */
1346 if ((ret = RegCreateKeyA( hkey, subkey, &hsubkey )) != ERROR_SUCCESS) return ret;
1347 hkey = hsubkey;
1350 ret = RegSetValueExA( hkey, name, 0, type, (const BYTE*)data, len );
1351 if (hsubkey) RegCloseKey( hsubkey );
1352 return ret;
1355 /******************************************************************************
1356 * RegQueryValueExW [ADVAPI32.@]
1358 * See RegQueryValueExA.
1360 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1361 LPBYTE data, LPDWORD count )
1363 NTSTATUS status;
1364 UNICODE_STRING name_str;
1365 DWORD total_size;
1366 char buffer[256], *buf_ptr = buffer;
1367 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1368 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1370 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1371 hkey, debugstr_w(name), reserved, type, data, count,
1372 (count && data) ? *count : 0 );
1374 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1375 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1377 RtlInitUnicodeString( &name_str, name );
1379 if (data) total_size = min( sizeof(buffer), *count + info_size );
1380 else
1382 total_size = info_size;
1383 if (count) *count = 0;
1386 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1387 buffer, total_size, &total_size );
1388 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1390 if (data)
1392 /* retry with a dynamically allocated buffer */
1393 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1395 if (buf_ptr != buffer) heap_free( buf_ptr );
1396 if (!(buf_ptr = heap_alloc( total_size )))
1397 return ERROR_NOT_ENOUGH_MEMORY;
1398 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1399 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1400 buf_ptr, total_size, &total_size );
1403 if (!status)
1405 memcpy( data, buf_ptr + info_size, total_size - info_size );
1406 /* if the type is REG_SZ and data is not 0-terminated
1407 * and there is enough space in the buffer NT appends a \0 */
1408 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1410 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1411 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1414 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1416 else status = STATUS_SUCCESS;
1418 if (type) *type = info->Type;
1419 if (count) *count = total_size - info_size;
1421 done:
1422 if (buf_ptr != buffer) heap_free( buf_ptr );
1423 return RtlNtStatusToDosError(status);
1427 /******************************************************************************
1428 * RegQueryValueExA [ADVAPI32.@]
1430 * Get the type and contents of a specified value under with a key.
1432 * PARAMS
1433 * hkey [I] Handle of the key to query
1434 * name [I] Name of value under hkey to query
1435 * reserved [I] Reserved - must be NULL
1436 * type [O] Destination for the value type, or NULL if not required
1437 * data [O] Destination for the values contents, or NULL if not required
1438 * count [I/O] Size of data, updated with the number of bytes returned
1440 * RETURNS
1441 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1442 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1443 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1444 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1446 * NOTES
1447 * MSDN states that if data is too small it is partially filled. In reality
1448 * it remains untouched.
1450 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1451 LPBYTE data, LPDWORD count )
1453 NTSTATUS status;
1454 ANSI_STRING nameA;
1455 UNICODE_STRING nameW;
1456 DWORD total_size, datalen = 0;
1457 char buffer[256], *buf_ptr = buffer;
1458 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1459 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1461 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1462 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1464 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1465 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1467 if (count) datalen = *count;
1468 if (!data && count) *count = 0;
1470 /* this matches Win9x behaviour - NT sets *type to a random value */
1471 if (type) *type = REG_NONE;
1473 RtlInitAnsiString( &nameA, name );
1474 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1475 return RtlNtStatusToDosError(status);
1477 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1478 buffer, sizeof(buffer), &total_size );
1479 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1481 /* we need to fetch the contents for a string type even if not requested,
1482 * because we need to compute the length of the ASCII string. */
1483 if (data || is_string(info->Type))
1485 /* retry with a dynamically allocated buffer */
1486 while (status == STATUS_BUFFER_OVERFLOW)
1488 if (buf_ptr != buffer) heap_free( buf_ptr );
1489 if (!(buf_ptr = heap_alloc( total_size )))
1491 status = STATUS_NO_MEMORY;
1492 goto done;
1494 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1495 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1496 buf_ptr, total_size, &total_size );
1499 if (status) goto done;
1501 if (is_string(info->Type))
1503 DWORD len;
1505 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1506 total_size - info_size );
1507 if (data && len)
1509 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1510 else
1512 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1513 total_size - info_size );
1514 /* if the type is REG_SZ and data is not 0-terminated
1515 * and there is enough space in the buffer NT appends a \0 */
1516 if (len < datalen && data[len-1]) data[len] = 0;
1519 total_size = len + info_size;
1521 else if (data)
1523 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1524 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1527 else status = STATUS_SUCCESS;
1529 if (type) *type = info->Type;
1530 if (count) *count = total_size - info_size;
1532 done:
1533 if (buf_ptr != buffer) heap_free( buf_ptr );
1534 RtlFreeUnicodeString( &nameW );
1535 return RtlNtStatusToDosError(status);
1539 /******************************************************************************
1540 * RegQueryValueW [ADVAPI32.@]
1542 * Retrieves the data associated with the default or unnamed value of a key.
1544 * PARAMS
1545 * hkey [I] Handle to an open key.
1546 * name [I] Name of the subkey of hKey.
1547 * data [O] Receives the string associated with the default value
1548 * of the key.
1549 * count [I/O] Size of lpValue in bytes.
1551 * RETURNS
1552 * Success: ERROR_SUCCESS
1553 * Failure: nonzero error code from Winerror.h
1555 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1557 DWORD ret;
1558 HKEY subkey = hkey;
1560 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1562 if (name && name[0])
1564 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1566 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1567 if (subkey != hkey) RegCloseKey( subkey );
1568 if (ret == ERROR_FILE_NOT_FOUND)
1570 /* return empty string if default value not found */
1571 if (data) *data = 0;
1572 if (count) *count = sizeof(WCHAR);
1573 ret = ERROR_SUCCESS;
1575 return ret;
1579 /******************************************************************************
1580 * RegQueryValueA [ADVAPI32.@]
1582 * See RegQueryValueW.
1584 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1586 DWORD ret;
1587 HKEY subkey = hkey;
1589 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1591 if (name && name[0])
1593 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1595 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1596 if (subkey != hkey) RegCloseKey( subkey );
1597 if (ret == ERROR_FILE_NOT_FOUND)
1599 /* return empty string if default value not found */
1600 if (data) *data = 0;
1601 if (count) *count = 1;
1602 ret = ERROR_SUCCESS;
1604 return ret;
1608 /******************************************************************************
1609 * ADVAPI_ApplyRestrictions [internal]
1611 * Helper function for RegGetValueA/W.
1613 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1614 DWORD cbData, PLONG ret )
1616 /* Check if the type is restricted by the passed flags */
1617 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1619 DWORD dwMask = 0;
1621 switch (dwType)
1623 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1624 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1625 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1626 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1627 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1628 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1629 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1632 if (dwFlags & dwMask)
1634 /* Type is not restricted, check for size mismatch */
1635 if (dwType == REG_BINARY)
1637 DWORD cbExpect = 0;
1639 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1640 cbExpect = 4;
1641 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1642 cbExpect = 8;
1644 if (cbExpect && cbData != cbExpect)
1645 *ret = ERROR_DATATYPE_MISMATCH;
1648 else *ret = ERROR_UNSUPPORTED_TYPE;
1653 /******************************************************************************
1654 * RegGetValueW [ADVAPI32.@]
1656 * Retrieves the type and data for a value name associated with a key,
1657 * optionally expanding its content and restricting its type.
1659 * PARAMS
1660 * hKey [I] Handle to an open key.
1661 * pszSubKey [I] Name of the subkey of hKey.
1662 * pszValue [I] Name of value under hKey/szSubKey to query.
1663 * dwFlags [I] Flags restricting the value type to retrieve.
1664 * pdwType [O] Destination for the values type, may be NULL.
1665 * pvData [O] Destination for the values content, may be NULL.
1666 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1667 * retrieve the whole content, including the trailing '\0'
1668 * for strings.
1670 * RETURNS
1671 * Success: ERROR_SUCCESS
1672 * Failure: nonzero error code from Winerror.h
1674 * NOTES
1675 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1676 * expanded and pdwType is set to REG_SZ instead.
1677 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1678 * without RRF_NOEXPAND is thus not allowed.
1679 * An exception is the case where RRF_RT_ANY is specified, because then
1680 * RRF_NOEXPAND is allowed.
1682 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1683 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1684 LPDWORD pcbData )
1686 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1687 PVOID pvBuf = NULL;
1688 LONG ret;
1690 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1691 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1692 pvData, pcbData, cbData);
1694 if (pvData && !pcbData)
1695 return ERROR_INVALID_PARAMETER;
1696 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1697 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1698 return ERROR_INVALID_PARAMETER;
1700 if (pszSubKey && pszSubKey[0])
1702 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1703 if (ret != ERROR_SUCCESS) return ret;
1706 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1708 /* If we are going to expand we need to read in the whole the value even
1709 * if the passed buffer was too small as the expanded string might be
1710 * smaller than the unexpanded one and could fit into cbData bytes. */
1711 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1712 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1714 do {
1715 heap_free(pvBuf);
1717 pvBuf = heap_alloc(cbData);
1718 if (!pvBuf)
1720 ret = ERROR_NOT_ENOUGH_MEMORY;
1721 break;
1724 if (ret == ERROR_MORE_DATA || !pvData)
1725 ret = RegQueryValueExW(hKey, pszValue, NULL,
1726 &dwType, pvBuf, &cbData);
1727 else
1729 /* Even if cbData was large enough we have to copy the
1730 * string since ExpandEnvironmentStrings can't handle
1731 * overlapping buffers. */
1732 CopyMemory(pvBuf, pvData, cbData);
1735 /* Both the type or the value itself could have been modified in
1736 * between so we have to keep retrying until the buffer is large
1737 * enough or we no longer have to expand the value. */
1738 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1740 if (ret == ERROR_SUCCESS)
1742 /* Recheck dwType in case it changed since the first call */
1743 if (dwType == REG_EXPAND_SZ)
1745 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1746 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1747 dwType = REG_SZ;
1748 if(pvData && pcbData && cbData > *pcbData)
1749 ret = ERROR_MORE_DATA;
1751 else if (pvData)
1752 CopyMemory(pvData, pvBuf, *pcbData);
1755 heap_free(pvBuf);
1758 if (pszSubKey && pszSubKey[0])
1759 RegCloseKey(hKey);
1761 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1763 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1764 ZeroMemory(pvData, *pcbData);
1766 if (pdwType) *pdwType = dwType;
1767 if (pcbData) *pcbData = cbData;
1769 return ret;
1773 /******************************************************************************
1774 * RegGetValueA [ADVAPI32.@]
1776 * See RegGetValueW.
1778 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1779 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1780 LPDWORD pcbData )
1782 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1783 PVOID pvBuf = NULL;
1784 LONG ret;
1786 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1787 hKey, debugstr_a(pszSubKey), debugstr_a(pszValue), dwFlags,
1788 pdwType, pvData, pcbData, cbData);
1790 if (pvData && !pcbData)
1791 return ERROR_INVALID_PARAMETER;
1792 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1793 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1794 return ERROR_INVALID_PARAMETER;
1796 if (pszSubKey && pszSubKey[0])
1798 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1799 if (ret != ERROR_SUCCESS) return ret;
1802 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1804 /* If we are going to expand we need to read in the whole the value even
1805 * if the passed buffer was too small as the expanded string might be
1806 * smaller than the unexpanded one and could fit into cbData bytes. */
1807 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1808 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1810 do {
1811 heap_free(pvBuf);
1813 pvBuf = heap_alloc(cbData);
1814 if (!pvBuf)
1816 ret = ERROR_NOT_ENOUGH_MEMORY;
1817 break;
1820 if (ret == ERROR_MORE_DATA || !pvData)
1821 ret = RegQueryValueExA(hKey, pszValue, NULL,
1822 &dwType, pvBuf, &cbData);
1823 else
1825 /* Even if cbData was large enough we have to copy the
1826 * string since ExpandEnvironmentStrings can't handle
1827 * overlapping buffers. */
1828 CopyMemory(pvBuf, pvData, cbData);
1831 /* Both the type or the value itself could have been modified in
1832 * between so we have to keep retrying until the buffer is large
1833 * enough or we no longer have to expand the value. */
1834 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1836 if (ret == ERROR_SUCCESS)
1838 /* Recheck dwType in case it changed since the first call */
1839 if (dwType == REG_EXPAND_SZ)
1841 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1842 pcbData ? *pcbData : 0);
1843 dwType = REG_SZ;
1844 if(pvData && pcbData && cbData > *pcbData)
1845 ret = ERROR_MORE_DATA;
1847 else if (pvData)
1848 CopyMemory(pvData, pvBuf, *pcbData);
1851 heap_free(pvBuf);
1854 if (pszSubKey && pszSubKey[0])
1855 RegCloseKey(hKey);
1857 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1859 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1860 ZeroMemory(pvData, *pcbData);
1862 if (pdwType) *pdwType = dwType;
1863 if (pcbData) *pcbData = cbData;
1865 return ret;
1869 /******************************************************************************
1870 * RegEnumValueW [ADVAPI32.@]
1872 * Enumerates the values for the specified open registry key.
1874 * PARAMS
1875 * hkey [I] Handle to key to query
1876 * index [I] Index of value to query
1877 * value [O] Value string
1878 * val_count [I/O] Size of value buffer (in wchars)
1879 * reserved [I] Reserved
1880 * type [O] Type code
1881 * data [O] Value data
1882 * count [I/O] Size of data buffer (in bytes)
1884 * RETURNS
1885 * Success: ERROR_SUCCESS
1886 * Failure: nonzero error code from Winerror.h
1889 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1890 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1892 NTSTATUS status;
1893 DWORD total_size;
1894 char buffer[256], *buf_ptr = buffer;
1895 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1896 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1898 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1899 hkey, index, value, val_count, reserved, type, data, count );
1901 /* NT only checks count, not val_count */
1902 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1903 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1905 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1906 if (data) total_size += *count;
1907 total_size = min( sizeof(buffer), total_size );
1909 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1910 buffer, total_size, &total_size );
1911 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1913 if (value || data)
1915 /* retry with a dynamically allocated buffer */
1916 while (status == STATUS_BUFFER_OVERFLOW)
1918 if (buf_ptr != buffer) heap_free( buf_ptr );
1919 if (!(buf_ptr = heap_alloc( total_size )))
1920 return ERROR_NOT_ENOUGH_MEMORY;
1921 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1922 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1923 buf_ptr, total_size, &total_size );
1926 if (status) goto done;
1928 if (value)
1930 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1932 status = STATUS_BUFFER_OVERFLOW;
1933 goto overflow;
1935 memcpy( value, info->Name, info->NameLength );
1936 *val_count = info->NameLength / sizeof(WCHAR);
1937 value[*val_count] = 0;
1940 if (data)
1942 if (total_size - info->DataOffset > *count)
1944 status = STATUS_BUFFER_OVERFLOW;
1945 goto overflow;
1947 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1948 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1950 /* if the type is REG_SZ and data is not 0-terminated
1951 * and there is enough space in the buffer NT appends a \0 */
1952 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1953 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1957 else status = STATUS_SUCCESS;
1959 overflow:
1960 if (type) *type = info->Type;
1961 if (count) *count = info->DataLength;
1963 done:
1964 if (buf_ptr != buffer) heap_free( buf_ptr );
1965 return RtlNtStatusToDosError(status);
1969 /******************************************************************************
1970 * RegEnumValueA [ADVAPI32.@]
1972 * See RegEnumValueW.
1974 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1975 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1977 NTSTATUS status;
1978 DWORD total_size;
1979 char buffer[256], *buf_ptr = buffer;
1980 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1981 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1983 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1984 hkey, index, value, val_count, reserved, type, data, count );
1986 /* NT only checks count, not val_count */
1987 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1988 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1990 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1991 if (data) total_size += *count;
1992 total_size = min( sizeof(buffer), total_size );
1994 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1995 buffer, total_size, &total_size );
1996 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1998 /* we need to fetch the contents for a string type even if not requested,
1999 * because we need to compute the length of the ASCII string. */
2000 if (value || data || is_string(info->Type))
2002 /* retry with a dynamically allocated buffer */
2003 while (status == STATUS_BUFFER_OVERFLOW)
2005 if (buf_ptr != buffer) heap_free( buf_ptr );
2006 if (!(buf_ptr = heap_alloc( total_size )))
2007 return ERROR_NOT_ENOUGH_MEMORY;
2008 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2009 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
2010 buf_ptr, total_size, &total_size );
2013 if (status) goto done;
2015 if (is_string(info->Type))
2017 DWORD len;
2018 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
2019 total_size - info->DataOffset );
2020 if (data && len)
2022 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
2023 else
2025 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
2026 total_size - info->DataOffset );
2027 /* if the type is REG_SZ and data is not 0-terminated
2028 * and there is enough space in the buffer NT appends a \0 */
2029 if (len < *count && data[len-1]) data[len] = 0;
2032 info->DataLength = len;
2034 else if (data)
2036 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
2037 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2040 if (value && !status)
2042 DWORD len;
2044 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2045 if (len >= *val_count)
2047 status = STATUS_BUFFER_OVERFLOW;
2048 if (*val_count)
2050 len = *val_count - 1;
2051 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2052 value[len] = 0;
2055 else
2057 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2058 value[len] = 0;
2059 *val_count = len;
2063 else status = STATUS_SUCCESS;
2065 if (type) *type = info->Type;
2066 if (count) *count = info->DataLength;
2068 done:
2069 if (buf_ptr != buffer) heap_free( buf_ptr );
2070 return RtlNtStatusToDosError(status);
2073 /******************************************************************************
2074 * RegDeleteValueW [ADVAPI32.@]
2076 * See RegDeleteValueA.
2078 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2080 return RegDeleteKeyValueW( hkey, NULL, name );
2083 /******************************************************************************
2084 * RegDeleteValueA [ADVAPI32.@]
2086 * Delete a value from the registry.
2088 * PARAMS
2089 * hkey [I] Registry handle of the key holding the value
2090 * name [I] Name of the value under hkey to delete
2092 * RETURNS
2093 * Success: ERROR_SUCCESS
2094 * Failure: nonzero error code from Winerror.h
2096 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2098 return RegDeleteKeyValueA( hkey, NULL, name );
2101 /******************************************************************************
2102 * RegDeleteKeyValueW [ADVAPI32.@]
2104 LONG WINAPI RegDeleteKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name )
2106 UNICODE_STRING nameW;
2107 HKEY hsubkey = 0;
2108 LONG ret;
2110 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2112 if (subkey)
2114 if ((ret = RegOpenKeyExW( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey )))
2115 return ret;
2116 hkey = hsubkey;
2119 RtlInitUnicodeString( &nameW, name );
2120 ret = RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2121 if (hsubkey) RegCloseKey( hsubkey );
2122 return ret;
2125 /******************************************************************************
2126 * RegDeleteKeyValueA [ADVAPI32.@]
2128 LONG WINAPI RegDeleteKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name )
2130 UNICODE_STRING nameW;
2131 HKEY hsubkey = 0;
2132 ANSI_STRING nameA;
2133 NTSTATUS status;
2135 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2137 if (subkey)
2139 LONG ret = RegOpenKeyExA( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey );
2140 if (ret)
2141 return ret;
2142 hkey = hsubkey;
2145 RtlInitAnsiString( &nameA, name );
2146 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2148 status = NtDeleteValueKey( hkey, &nameW );
2149 RtlFreeUnicodeString( &nameW );
2152 if (hsubkey) RegCloseKey( hsubkey );
2153 return RtlNtStatusToDosError( status );
2156 /******************************************************************************
2157 * RegLoadKeyW [ADVAPI32.@]
2159 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2160 * registration information from a specified file into that subkey.
2162 * PARAMS
2163 * hkey [I] Handle of open key
2164 * subkey [I] Address of name of subkey
2165 * filename [I] Address of filename for registry information
2167 * RETURNS
2168 * Success: ERROR_SUCCESS
2169 * Failure: nonzero error code from Winerror.h
2171 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2173 OBJECT_ATTRIBUTES destkey, file;
2174 UNICODE_STRING subkeyW, filenameW;
2175 NTSTATUS status;
2177 if (!(hkey = get_special_root_hkey(hkey, 0))) return ERROR_INVALID_HANDLE;
2179 destkey.Length = sizeof(destkey);
2180 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2181 destkey.ObjectName = &subkeyW; /* name of the key */
2182 destkey.Attributes = 0;
2183 destkey.SecurityDescriptor = NULL;
2184 destkey.SecurityQualityOfService = NULL;
2185 RtlInitUnicodeString(&subkeyW, subkey);
2187 file.Length = sizeof(file);
2188 file.RootDirectory = NULL;
2189 file.ObjectName = &filenameW; /* file containing the hive */
2190 file.Attributes = OBJ_CASE_INSENSITIVE;
2191 file.SecurityDescriptor = NULL;
2192 file.SecurityQualityOfService = NULL;
2193 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2195 status = NtLoadKey(&destkey, &file);
2196 RtlFreeUnicodeString(&filenameW);
2197 return RtlNtStatusToDosError( status );
2201 /******************************************************************************
2202 * RegLoadKeyA [ADVAPI32.@]
2204 * See RegLoadKeyW.
2206 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2208 UNICODE_STRING subkeyW, filenameW;
2209 STRING subkeyA, filenameA;
2210 NTSTATUS status;
2211 LONG ret;
2213 RtlInitAnsiString(&subkeyA, subkey);
2214 RtlInitAnsiString(&filenameA, filename);
2216 RtlInitUnicodeString(&subkeyW, NULL);
2217 RtlInitUnicodeString(&filenameW, NULL);
2218 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2219 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2221 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2223 else ret = RtlNtStatusToDosError(status);
2224 RtlFreeUnicodeString(&subkeyW);
2225 RtlFreeUnicodeString(&filenameW);
2226 return ret;
2230 /******************************************************************************
2231 * RegSaveKeyW [ADVAPI32.@]
2233 * Save a key and all of its subkeys and values to a new file in the standard format.
2235 * PARAMS
2236 * hkey [I] Handle of key where save begins
2237 * lpFile [I] Address of filename to save to
2238 * sa [I] Address of security structure
2240 * RETURNS
2241 * Success: ERROR_SUCCESS
2242 * Failure: nonzero error code from Winerror.h
2244 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2246 static const WCHAR format[] =
2247 {'r','e','g','%','0','4','x','.','t','m','p',0};
2248 WCHAR buffer[MAX_PATH];
2249 int count = 0;
2250 LPWSTR nameW;
2251 DWORD ret, err;
2252 HANDLE handle;
2254 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2256 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2257 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2259 err = GetLastError();
2260 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2262 for (;;)
2264 snprintfW( nameW, 16, format, count++ );
2265 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2266 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2267 if (handle != INVALID_HANDLE_VALUE) break;
2268 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2270 /* Something gone haywire ? Please report if this happens abnormally */
2271 if (count >= 100)
2272 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);
2275 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2277 CloseHandle( handle );
2278 if (!ret)
2280 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2282 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2283 debugstr_w(file) );
2284 ret = GetLastError();
2287 if (ret) DeleteFileW( buffer );
2289 done:
2290 SetLastError( err ); /* restore last error code */
2291 return ret;
2295 /******************************************************************************
2296 * RegSaveKeyA [ADVAPI32.@]
2298 * See RegSaveKeyW.
2300 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2302 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2303 NTSTATUS status;
2304 STRING fileA;
2306 RtlInitAnsiString(&fileA, file);
2307 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2308 return RtlNtStatusToDosError( status );
2309 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2313 /******************************************************************************
2314 * RegRestoreKeyW [ADVAPI32.@]
2316 * Read the registry information from a file and copy it over a key.
2318 * PARAMS
2319 * hkey [I] Handle of key where restore begins
2320 * lpFile [I] Address of filename containing saved tree
2321 * dwFlags [I] Optional flags
2323 * RETURNS
2324 * Success: ERROR_SUCCESS
2325 * Failure: nonzero error code from Winerror.h
2327 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2329 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2331 /* It seems to do this check before the hkey check */
2332 if (!lpFile || !*lpFile)
2333 return ERROR_INVALID_PARAMETER;
2335 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2337 /* Check for file existence */
2339 return ERROR_SUCCESS;
2343 /******************************************************************************
2344 * RegRestoreKeyA [ADVAPI32.@]
2346 * See RegRestoreKeyW.
2348 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2350 UNICODE_STRING lpFileW;
2351 LONG ret;
2353 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2354 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2355 RtlFreeUnicodeString( &lpFileW );
2356 return ret;
2360 /******************************************************************************
2361 * RegUnLoadKeyW [ADVAPI32.@]
2363 * Unload a registry key and its subkeys from the registry.
2365 * PARAMS
2366 * hkey [I] Handle of open key
2367 * lpSubKey [I] Address of name of subkey to unload
2369 * RETURNS
2370 * Success: ERROR_SUCCESS
2371 * Failure: nonzero error code from Winerror.h
2373 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2375 DWORD ret;
2376 HKEY shkey;
2377 OBJECT_ATTRIBUTES attr;
2378 UNICODE_STRING subkey;
2380 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2382 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2383 if( ret )
2384 return ERROR_INVALID_PARAMETER;
2386 RtlInitUnicodeString(&subkey, lpSubKey);
2387 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2388 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2390 RegCloseKey(shkey);
2392 return ret;
2396 /******************************************************************************
2397 * RegUnLoadKeyA [ADVAPI32.@]
2399 * See RegUnLoadKeyW.
2401 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2403 UNICODE_STRING lpSubKeyW;
2404 LONG ret;
2406 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2407 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2408 RtlFreeUnicodeString( &lpSubKeyW );
2409 return ret;
2413 /******************************************************************************
2414 * RegReplaceKeyW [ADVAPI32.@]
2416 * Replace the file backing a registry key and all its subkeys with another file.
2418 * PARAMS
2419 * hkey [I] Handle of open key
2420 * lpSubKey [I] Address of name of subkey
2421 * lpNewFile [I] Address of filename for file with new data
2422 * lpOldFile [I] Address of filename for backup file
2424 * RETURNS
2425 * Success: ERROR_SUCCESS
2426 * Failure: nonzero error code from Winerror.h
2428 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2429 LPCWSTR lpOldFile )
2431 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2432 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2433 return ERROR_SUCCESS;
2437 /******************************************************************************
2438 * RegReplaceKeyA [ADVAPI32.@]
2440 * See RegReplaceKeyW.
2442 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2443 LPCSTR lpOldFile )
2445 UNICODE_STRING lpSubKeyW;
2446 UNICODE_STRING lpNewFileW;
2447 UNICODE_STRING lpOldFileW;
2448 LONG ret;
2450 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2451 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2452 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2453 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2454 RtlFreeUnicodeString( &lpOldFileW );
2455 RtlFreeUnicodeString( &lpNewFileW );
2456 RtlFreeUnicodeString( &lpSubKeyW );
2457 return ret;
2461 /******************************************************************************
2462 * RegSetKeySecurity [ADVAPI32.@]
2464 * Set the security of an open registry key.
2466 * PARAMS
2467 * hkey [I] Open handle of key to set
2468 * SecurityInfo [I] Descriptor contents
2469 * pSecurityDesc [I] Address of descriptor for key
2471 * RETURNS
2472 * Success: ERROR_SUCCESS
2473 * Failure: nonzero error code from Winerror.h
2475 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2476 PSECURITY_DESCRIPTOR pSecurityDesc )
2478 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2480 /* It seems to perform this check before the hkey check */
2481 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2482 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2483 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2484 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2485 /* Param OK */
2486 } else
2487 return ERROR_INVALID_PARAMETER;
2489 if (!pSecurityDesc)
2490 return ERROR_INVALID_PARAMETER;
2492 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2494 return RtlNtStatusToDosError( NtSetSecurityObject( hkey, SecurityInfo, pSecurityDesc ) );
2498 /******************************************************************************
2499 * RegGetKeySecurity [ADVAPI32.@]
2501 * Get a copy of the security descriptor for a given registry key.
2503 * PARAMS
2504 * hkey [I] Open handle of key to set
2505 * SecurityInformation [I] Descriptor contents
2506 * pSecurityDescriptor [O] Address of descriptor for key
2507 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2509 * RETURNS
2510 * Success: ERROR_SUCCESS
2511 * Failure: Error code
2513 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2514 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2515 LPDWORD lpcbSecurityDescriptor )
2517 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2518 *lpcbSecurityDescriptor);
2520 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2522 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2523 SecurityInformation, pSecurityDescriptor,
2524 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2528 /******************************************************************************
2529 * RegFlushKey [ADVAPI32.@]
2531 * Immediately write a registry key to registry.
2533 * PARAMS
2534 * hkey [I] Handle of key to write
2536 * RETURNS
2537 * Success: ERROR_SUCCESS
2538 * Failure: Error code
2540 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2542 hkey = get_special_root_hkey( hkey, 0 );
2543 if (!hkey) return ERROR_INVALID_HANDLE;
2545 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2549 /******************************************************************************
2550 * RegConnectRegistryW [ADVAPI32.@]
2552 * Establish a connection to a predefined registry key on another computer.
2554 * PARAMS
2555 * lpMachineName [I] Address of name of remote computer
2556 * hHey [I] Predefined registry handle
2557 * phkResult [I] Address of buffer for remote registry handle
2559 * RETURNS
2560 * Success: ERROR_SUCCESS
2561 * Failure: nonzero error code from Winerror.h
2563 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2564 PHKEY phkResult )
2566 LONG ret;
2568 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName), hKey, phkResult);
2570 if (!lpMachineName || !*lpMachineName) {
2571 /* Use the local machine name */
2572 ret = RegOpenKeyW( hKey, NULL, phkResult );
2574 else {
2575 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2576 DWORD len = sizeof(compName) / sizeof(WCHAR);
2578 /* MSDN says lpMachineName must start with \\ : not so */
2579 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2580 lpMachineName += 2;
2581 if (GetComputerNameW(compName, &len))
2583 if (!strcmpiW(lpMachineName, compName))
2584 ret = RegOpenKeyW(hKey, NULL, phkResult);
2585 else
2587 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2588 ret = ERROR_BAD_NETPATH;
2591 else
2592 ret = GetLastError();
2594 return ret;
2598 /******************************************************************************
2599 * RegConnectRegistryA [ADVAPI32.@]
2601 * See RegConnectRegistryW.
2603 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2605 UNICODE_STRING machineW;
2606 LONG ret;
2608 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2609 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2610 RtlFreeUnicodeString( &machineW );
2611 return ret;
2615 /******************************************************************************
2616 * RegNotifyChangeKeyValue [ADVAPI32.@]
2618 * Notify the caller about changes to the attributes or contents of a registry key.
2620 * PARAMS
2621 * hkey [I] Handle of key to watch
2622 * fWatchSubTree [I] Flag for subkey notification
2623 * fdwNotifyFilter [I] Changes to be reported
2624 * hEvent [I] Handle of signaled event
2625 * fAsync [I] Flag for asynchronous reporting
2627 * RETURNS
2628 * Success: ERROR_SUCCESS
2629 * Failure: nonzero error code from Winerror.h
2631 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2632 DWORD fdwNotifyFilter, HANDLE hEvent,
2633 BOOL fAsync )
2635 NTSTATUS status;
2636 IO_STATUS_BLOCK iosb;
2638 hkey = get_special_root_hkey( hkey, 0 );
2639 if (!hkey) return ERROR_INVALID_HANDLE;
2641 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2642 hEvent, fAsync);
2644 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2645 fdwNotifyFilter, fAsync, NULL, 0,
2646 fWatchSubTree);
2648 if (status && status != STATUS_TIMEOUT)
2649 return RtlNtStatusToDosError( status );
2651 return ERROR_SUCCESS;
2654 /******************************************************************************
2655 * RegOpenUserClassesRoot [ADVAPI32.@]
2657 * Open the HKEY_CLASSES_ROOT key for a user.
2659 * PARAMS
2660 * hToken [I] Handle of token representing the user
2661 * dwOptions [I] Reserved, must be 0
2662 * samDesired [I] Desired access rights
2663 * phkResult [O] Destination for the resulting key handle
2665 * RETURNS
2666 * Success: ERROR_SUCCESS
2667 * Failure: nonzero error code from Winerror.h
2669 * NOTES
2670 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2671 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2672 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2674 LSTATUS WINAPI RegOpenUserClassesRoot(
2675 HANDLE hToken,
2676 DWORD dwOptions,
2677 REGSAM samDesired,
2678 PHKEY phkResult
2681 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2683 *phkResult = HKEY_CLASSES_ROOT;
2684 return ERROR_SUCCESS;
2687 /******************************************************************************
2688 * load_string [Internal]
2690 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2691 * avoid importing user32, which is higher level than advapi32. Helper for
2692 * RegLoadMUIString.
2694 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2696 HGLOBAL hMemory;
2697 HRSRC hResource;
2698 WCHAR *pString;
2699 int idxString;
2701 /* Negative values have to be inverted. */
2702 if (HIWORD(resId) == 0xffff)
2703 resId = (UINT)(-((INT)resId));
2705 /* Load the resource into memory and get a pointer to it. */
2706 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2707 if (!hResource) return 0;
2708 hMemory = LoadResource(hModule, hResource);
2709 if (!hMemory) return 0;
2710 pString = LockResource(hMemory);
2712 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2713 idxString = resId & 0xf;
2714 while (idxString--) pString += *pString + 1;
2716 /* If no buffer is given, return length of the string. */
2717 if (!pwszBuffer) return *pString;
2719 /* Else copy over the string, respecting the buffer size. */
2720 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2721 if (cMaxChars >= 0) {
2722 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2723 pwszBuffer[cMaxChars] = '\0';
2726 return cMaxChars;
2729 /******************************************************************************
2730 * RegLoadMUIStringW [ADVAPI32.@]
2732 * Load the localized version of a string resource from some PE, respective
2733 * id and path of which are given in the registry value in the format
2734 * @[path]\dllname,-resourceId
2736 * PARAMS
2737 * hKey [I] Key, of which to load the string value from.
2738 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2739 * pszBuffer [O] Buffer to store the localized string in.
2740 * cbBuffer [I] Size of the destination buffer in bytes.
2741 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2742 * dwFlags [I] None supported yet.
2743 * pszBaseDir [I] Not supported yet.
2745 * RETURNS
2746 * Success: ERROR_SUCCESS,
2747 * Failure: nonzero error code from winerror.h
2749 * NOTES
2750 * This is an API of Windows Vista, which wasn't available at the time this code
2751 * was written. We have to check for the correct behaviour once it's available.
2753 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2754 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2756 DWORD dwValueType, cbData;
2757 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2758 LONG result;
2760 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2761 "dwFlags = %d, pwszBaseDir = %s)\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2762 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2764 /* Parameter sanity checks. */
2765 if (!hKey || !pwszBuffer)
2766 return ERROR_INVALID_PARAMETER;
2768 if (pwszBaseDir && *pwszBaseDir) {
2769 FIXME("BaseDir parameter not yet supported!\n");
2770 return ERROR_INVALID_PARAMETER;
2773 /* Check for value existence and correctness of its type, allocate a buffer and load it. */
2774 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2775 if (result != ERROR_SUCCESS) goto cleanup;
2776 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2777 result = ERROR_FILE_NOT_FOUND;
2778 goto cleanup;
2780 pwszTempBuffer = heap_alloc(cbData);
2781 if (!pwszTempBuffer) {
2782 result = ERROR_NOT_ENOUGH_MEMORY;
2783 goto cleanup;
2785 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2786 if (result != ERROR_SUCCESS) goto cleanup;
2788 /* Expand environment variables, if appropriate, or copy the original string over. */
2789 if (dwValueType == REG_EXPAND_SZ) {
2790 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2791 if (!cbData) goto cleanup;
2792 pwszExpandedBuffer = heap_alloc(cbData);
2793 if (!pwszExpandedBuffer) {
2794 result = ERROR_NOT_ENOUGH_MEMORY;
2795 goto cleanup;
2797 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2798 } else {
2799 pwszExpandedBuffer = heap_alloc(cbData);
2800 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2803 /* If the value references a resource based string, parse the value and load the string.
2804 * Else just copy over the original value. */
2805 result = ERROR_SUCCESS;
2806 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2807 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2808 } else {
2809 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2810 UINT uiStringId;
2811 HMODULE hModule;
2813 /* Format of the expanded value is 'path_to_dll,-resId' */
2814 if (!pComma || pComma[1] != '-') {
2815 result = ERROR_BADKEY;
2816 goto cleanup;
2819 uiStringId = atoiW(pComma+2);
2820 *pComma = '\0';
2822 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2823 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2824 result = ERROR_BADKEY;
2825 FreeLibrary(hModule);
2828 cleanup:
2829 heap_free(pwszTempBuffer);
2830 heap_free(pwszExpandedBuffer);
2831 return result;
2834 /******************************************************************************
2835 * RegLoadMUIStringA [ADVAPI32.@]
2837 * See RegLoadMUIStringW
2839 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2840 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2842 UNICODE_STRING valueW, baseDirW;
2843 WCHAR *pwszBuffer;
2844 DWORD cbData = cbBuffer * sizeof(WCHAR);
2845 LONG result;
2847 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2848 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2849 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2850 !(pwszBuffer = heap_alloc(cbData)))
2852 result = ERROR_NOT_ENOUGH_MEMORY;
2853 goto cleanup;
2856 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2857 baseDirW.Buffer);
2859 if (result == ERROR_SUCCESS) {
2860 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2861 if (pcbData)
2862 *pcbData = cbData;
2865 cleanup:
2866 heap_free(pwszBuffer);
2867 RtlFreeUnicodeString(&baseDirW);
2868 RtlFreeUnicodeString(&valueW);
2870 return result;
2873 /******************************************************************************
2874 * RegDisablePredefinedCache [ADVAPI32.@]
2876 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2878 * PARAMS
2879 * None.
2881 * RETURNS
2882 * Success: ERROR_SUCCESS
2883 * Failure: nonzero error code from Winerror.h
2885 * NOTES
2886 * This is useful for services that use impersonation.
2888 LSTATUS WINAPI RegDisablePredefinedCache(void)
2890 HKEY hkey_current_user;
2891 int idx = HandleToUlong(HKEY_CURRENT_USER) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
2893 /* prevent caching of future requests */
2894 hkcu_cache_disabled = TRUE;
2896 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2898 if (hkey_current_user)
2899 NtClose( hkey_current_user );
2901 return ERROR_SUCCESS;
2904 /******************************************************************************
2905 * RegDeleteTreeW [ADVAPI32.@]
2908 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2910 LONG ret;
2911 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2912 DWORD dwMaxLen, dwSize;
2913 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2914 HKEY hSubKey = hKey;
2916 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2918 if(lpszSubKey)
2920 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2921 if (ret) return ret;
2924 /* Get highest length for keys, values */
2925 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2926 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2927 if (ret) goto cleanup;
2929 dwMaxSubkeyLen++;
2930 dwMaxValueLen++;
2931 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2932 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2934 /* Name too big: alloc a buffer for it */
2935 if (!(lpszName = heap_alloc( dwMaxLen*sizeof(WCHAR))))
2937 ret = ERROR_NOT_ENOUGH_MEMORY;
2938 goto cleanup;
2943 /* Recursively delete all the subkeys */
2944 while (TRUE)
2946 dwSize = dwMaxLen;
2947 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2948 NULL, NULL, NULL)) break;
2950 ret = RegDeleteTreeW(hSubKey, lpszName);
2951 if (ret) goto cleanup;
2954 if (lpszSubKey)
2955 ret = RegDeleteKeyW(hKey, lpszSubKey);
2956 else
2957 while (TRUE)
2959 dwSize = dwMaxLen;
2960 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2961 NULL, NULL, NULL, NULL)) break;
2963 ret = RegDeleteValueW(hKey, lpszName);
2964 if (ret) goto cleanup;
2967 cleanup:
2968 /* Free buffer if allocated */
2969 if (lpszName != szNameBuf)
2970 heap_free( lpszName);
2971 if(lpszSubKey)
2972 RegCloseKey(hSubKey);
2973 return ret;
2976 /******************************************************************************
2977 * RegDeleteTreeA [ADVAPI32.@]
2980 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2982 LONG ret;
2983 UNICODE_STRING lpszSubKeyW;
2985 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2986 else lpszSubKeyW.Buffer = NULL;
2987 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2988 RtlFreeUnicodeString( &lpszSubKeyW );
2989 return ret;
2992 /******************************************************************************
2993 * RegDisableReflectionKey [ADVAPI32.@]
2996 LONG WINAPI RegDisableReflectionKey(HKEY base)
2998 FIXME("%p: stub\n", base);
2999 return ERROR_SUCCESS;