d3d8: Improve d3d8_device_TestCooperativeLevel().
[wine/multimedia.git] / dlls / advapi32 / registry.c
blobc7ba3ef221fb91fdf0b51ef04516d74e8241c1db
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"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(reg);
44 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
45 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
47 static const WCHAR name_CLASSES_ROOT[] =
48 {'M','a','c','h','i','n','e','\\',
49 'S','o','f','t','w','a','r','e','\\',
50 'C','l','a','s','s','e','s',0};
51 static const WCHAR name_LOCAL_MACHINE[] =
52 {'M','a','c','h','i','n','e',0};
53 static const WCHAR name_USERS[] =
54 {'U','s','e','r',0};
55 static const WCHAR name_PERFORMANCE_DATA[] =
56 {'P','e','r','f','D','a','t','a',0};
57 static const WCHAR name_CURRENT_CONFIG[] =
58 {'M','a','c','h','i','n','e','\\',
59 'S','y','s','t','e','m','\\',
60 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
61 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
62 'C','u','r','r','e','n','t',0};
63 static const WCHAR name_DYN_DATA[] =
64 {'D','y','n','D','a','t','a',0};
66 static const WCHAR * const root_key_names[] =
68 name_CLASSES_ROOT,
69 NULL, /* HKEY_CURRENT_USER is determined dynamically */
70 name_LOCAL_MACHINE,
71 name_USERS,
72 name_PERFORMANCE_DATA,
73 name_CURRENT_CONFIG,
74 name_DYN_DATA
77 #define NB_SPECIAL_ROOT_KEYS (sizeof(root_key_names)/sizeof(root_key_names[0]))
79 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
80 static BOOL hkcu_cache_disabled;
82 static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
84 /* check if value type needs string conversion (Ansi<->Unicode) */
85 static inline BOOL is_string( DWORD type )
87 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
90 /* check if current version is NT or Win95 */
91 static inline BOOL is_version_nt(void)
93 return !(GetVersion() & 0x80000000);
96 static BOOL is_wow6432node( const UNICODE_STRING *name )
98 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e'};
100 return (name->Length == sizeof(wow6432nodeW) &&
101 !memicmpW( name->Buffer, wow6432nodeW, sizeof(wow6432nodeW)/sizeof(WCHAR) ));
104 /* open the Wow6432Node subkey of the specified key */
105 static HANDLE open_wow6432node( HANDLE key, const UNICODE_STRING *name )
107 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
108 OBJECT_ATTRIBUTES attr;
109 UNICODE_STRING nameW;
110 HANDLE ret;
112 attr.Length = sizeof(attr);
113 attr.RootDirectory = key;
114 attr.ObjectName = &nameW;
115 attr.Attributes = 0;
116 attr.SecurityDescriptor = NULL;
117 attr.SecurityQualityOfService = NULL;
118 RtlInitUnicodeString( &nameW, wow6432nodeW );
119 if (NtOpenKey( &ret, MAXIMUM_ALLOWED, &attr )) ret = 0;
120 return ret;
123 /* wrapper for NtCreateKey that creates the key recursively if necessary */
124 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
125 const UNICODE_STRING *class, ULONG options, PULONG dispos )
127 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
128 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
130 if (!force_wow32) status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class, options, dispos );
132 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
134 HANDLE subkey, root = attr->RootDirectory;
135 WCHAR *buffer = attr->ObjectName->Buffer;
136 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
137 UNICODE_STRING str;
139 while (i < len && buffer[i] != '\\') i++;
140 if (i == len && !force_wow32) return status;
142 attrs = attr->Attributes;
143 attr->ObjectName = &str;
145 for (;;)
147 str.Buffer = buffer + pos;
148 str.Length = (i - pos) * sizeof(WCHAR);
149 if (force_wow32 && pos)
151 if (is_wow6432node( &str )) force_wow32 = FALSE;
152 else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
154 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
155 attr->RootDirectory = subkey;
156 force_wow32 = FALSE;
159 if (i == len)
161 attr->Attributes = attrs;
162 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, class, options, dispos );
164 else
166 attr->Attributes = attrs & ~OBJ_OPENLINK;
167 status = NtCreateKey( &subkey, access, attr, 0, class,
168 options & ~REG_OPTION_CREATE_LINK, dispos );
170 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
171 if (status) return status;
172 if (i == len) break;
173 attr->RootDirectory = subkey;
174 while (i < len && buffer[i] == '\\') i++;
175 pos = i;
176 while (i < len && buffer[i] != '\\') i++;
179 return status;
182 /* wrapper for NtOpenKey to handle Wow6432 nodes */
183 static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
185 NTSTATUS status;
186 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
187 HANDLE subkey, root = attr->RootDirectory;
188 WCHAR *buffer = attr->ObjectName->Buffer;
189 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
190 UNICODE_STRING str;
192 if (!force_wow32) return NtOpenKey( (HANDLE *)retkey, access, attr );
194 if (len && buffer[0] == '\\') return STATUS_OBJECT_PATH_INVALID;
195 while (i < len && buffer[i] != '\\') i++;
196 attrs = attr->Attributes;
197 attr->ObjectName = &str;
199 for (;;)
201 str.Buffer = buffer + pos;
202 str.Length = (i - pos) * sizeof(WCHAR);
203 if (force_wow32 && pos)
205 if (is_wow6432node( &str )) force_wow32 = FALSE;
206 else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
208 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
209 attr->RootDirectory = subkey;
210 force_wow32 = FALSE;
213 if (i == len)
215 attr->Attributes = attrs;
216 status = NtOpenKey( (PHANDLE)retkey, access, attr );
218 else
220 attr->Attributes = attrs & ~OBJ_OPENLINK;
221 status = NtOpenKey( &subkey, access, attr );
223 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
224 if (status) return status;
225 if (i == len) break;
226 attr->RootDirectory = subkey;
227 while (i < len && buffer[i] == '\\') i++;
228 pos = i;
229 while (i < len && buffer[i] != '\\') i++;
231 return status;
234 /* create one of the HKEY_* special root keys */
235 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
237 HKEY ret = 0;
238 int idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
240 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CURRENT_USER))
242 if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
243 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
245 /* don't cache the key in the table if caching is disabled */
246 if (hkcu_cache_disabled)
247 return hkey;
249 else
251 OBJECT_ATTRIBUTES attr;
252 UNICODE_STRING name;
254 attr.Length = sizeof(attr);
255 attr.RootDirectory = 0;
256 attr.ObjectName = &name;
257 attr.Attributes = 0;
258 attr.SecurityDescriptor = NULL;
259 attr.SecurityQualityOfService = NULL;
260 RtlInitUnicodeString( &name, root_key_names[idx] );
261 if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0;
262 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
265 if (!(access & (KEY_WOW64_64KEY | KEY_WOW64_32KEY)))
267 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
268 ret = hkey;
269 else
270 NtClose( hkey ); /* somebody beat us to it */
272 else
273 ret = hkey;
274 return ret;
277 /* map the hkey from special root to normal key if necessary */
278 static inline HKEY get_special_root_hkey( HKEY hkey, REGSAM access )
280 HKEY ret = hkey;
282 if ((HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST))
283 && (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
285 REGSAM mask = 0;
287 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT))
288 mask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
290 if ((access & mask) ||
291 !(ret = special_root_keys[HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)]))
292 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED | (access & mask) );
294 return ret;
298 /******************************************************************************
299 * RegOverridePredefKey [ADVAPI32.@]
301 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
303 HKEY old_key;
304 int idx;
306 TRACE("(%p %p)\n", hkey, override);
308 if ((HandleToUlong(hkey) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST))
309 || (HandleToUlong(hkey) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
310 return ERROR_INVALID_PARAMETER;
311 idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
313 if (override)
315 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
316 GetCurrentProcess(), (HANDLE *)&override,
317 0, 0, DUPLICATE_SAME_ACCESS );
318 if (status) return RtlNtStatusToDosError( status );
321 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
322 if (old_key) NtClose( old_key );
323 return ERROR_SUCCESS;
327 /******************************************************************************
328 * RegCreateKeyExW [ADVAPI32.@]
330 * See RegCreateKeyExA.
332 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
333 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
334 PHKEY retkey, LPDWORD dispos )
336 OBJECT_ATTRIBUTES attr;
337 UNICODE_STRING nameW, classW;
339 if (reserved) return ERROR_INVALID_PARAMETER;
340 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
342 attr.Length = sizeof(attr);
343 attr.RootDirectory = hkey;
344 attr.ObjectName = &nameW;
345 attr.Attributes = 0;
346 attr.SecurityDescriptor = NULL;
347 attr.SecurityQualityOfService = NULL;
348 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
349 RtlInitUnicodeString( &nameW, name );
350 RtlInitUnicodeString( &classW, class );
352 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
356 /******************************************************************************
357 * RegCreateKeyExA [ADVAPI32.@]
359 * Open a registry key, creating it if it doesn't exist.
361 * PARAMS
362 * hkey [I] Handle of the parent registry key
363 * name [I] Name of the new key to open or create
364 * reserved [I] Reserved, pass 0
365 * class [I] The object type of the new key
366 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
367 * access [I] Access level desired
368 * sa [I] Security attributes for the key
369 * retkey [O] Destination for the resulting handle
370 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
372 * RETURNS
373 * Success: ERROR_SUCCESS.
374 * Failure: A standard Win32 error code. retkey remains untouched.
376 * FIXME
377 * MAXIMUM_ALLOWED in access mask not supported by server
379 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
380 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
381 PHKEY retkey, LPDWORD dispos )
383 OBJECT_ATTRIBUTES attr;
384 UNICODE_STRING classW;
385 ANSI_STRING nameA, classA;
386 NTSTATUS status;
388 if (reserved) return ERROR_INVALID_PARAMETER;
389 if (!is_version_nt())
391 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
392 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
394 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
396 attr.Length = sizeof(attr);
397 attr.RootDirectory = hkey;
398 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
399 attr.Attributes = 0;
400 attr.SecurityDescriptor = NULL;
401 attr.SecurityQualityOfService = NULL;
402 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
403 RtlInitAnsiString( &nameA, name );
404 RtlInitAnsiString( &classA, class );
406 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
407 &nameA, FALSE )))
409 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
411 status = create_key( retkey, access, &attr, &classW, options, dispos );
412 RtlFreeUnicodeString( &classW );
415 return RtlNtStatusToDosError( status );
419 /******************************************************************************
420 * RegCreateKeyW [ADVAPI32.@]
422 * Creates the specified reg key.
424 * PARAMS
425 * hKey [I] Handle to an open key.
426 * lpSubKey [I] Name of a key that will be opened or created.
427 * phkResult [O] Receives a handle to the opened or created key.
429 * RETURNS
430 * Success: ERROR_SUCCESS
431 * Failure: nonzero error code defined in Winerror.h
433 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
435 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
436 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
437 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
438 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
442 /******************************************************************************
443 * RegCreateKeyA [ADVAPI32.@]
445 * See RegCreateKeyW.
447 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
449 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
450 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
455 /******************************************************************************
456 * RegOpenKeyExW [ADVAPI32.@]
458 * See RegOpenKeyExA.
460 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
462 OBJECT_ATTRIBUTES attr;
463 UNICODE_STRING nameW;
465 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
466 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++;
468 if (!retkey) return ERROR_INVALID_PARAMETER;
469 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
471 attr.Length = sizeof(attr);
472 attr.RootDirectory = hkey;
473 attr.ObjectName = &nameW;
474 attr.Attributes = 0;
475 attr.SecurityDescriptor = NULL;
476 attr.SecurityQualityOfService = NULL;
477 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
478 RtlInitUnicodeString( &nameW, name );
479 return RtlNtStatusToDosError( open_key( retkey, access, &attr ) );
483 /******************************************************************************
484 * RegOpenKeyExA [ADVAPI32.@]
486 * Open a registry key.
488 * PARAMS
489 * hkey [I] Handle of open key
490 * name [I] Name of subkey to open
491 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
492 * access [I] Security access mask
493 * retkey [O] Handle to open key
495 * RETURNS
496 * Success: ERROR_SUCCESS
497 * Failure: A standard Win32 error code. retkey is set to 0.
499 * NOTES
500 * Unlike RegCreateKeyExA(), this function will not create the key if it
501 * does not exist.
503 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
505 OBJECT_ATTRIBUTES attr;
506 STRING nameA;
507 NTSTATUS status;
509 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
510 else
512 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
513 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++;
516 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
518 attr.Length = sizeof(attr);
519 attr.RootDirectory = hkey;
520 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
521 attr.Attributes = 0;
522 attr.SecurityDescriptor = NULL;
523 attr.SecurityQualityOfService = NULL;
524 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
526 RtlInitAnsiString( &nameA, name );
527 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
528 &nameA, FALSE )))
530 status = open_key( retkey, access, &attr );
532 return RtlNtStatusToDosError( status );
536 /******************************************************************************
537 * RegOpenKeyW [ADVAPI32.@]
539 * See RegOpenKeyA.
541 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
543 if (!retkey)
544 return ERROR_INVALID_PARAMETER;
546 if (!name || !*name)
548 *retkey = hkey;
549 return ERROR_SUCCESS;
551 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
555 /******************************************************************************
556 * RegOpenKeyA [ADVAPI32.@]
558 * Open a registry key.
560 * PARAMS
561 * hkey [I] Handle of parent key to open the new key under
562 * name [I] Name of the key under hkey to open
563 * retkey [O] Destination for the resulting Handle
565 * RETURNS
566 * Success: ERROR_SUCCESS
567 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
569 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
571 if (!retkey)
572 return ERROR_INVALID_PARAMETER;
574 if (!name || !*name)
576 *retkey = hkey;
577 return ERROR_SUCCESS;
579 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
583 /******************************************************************************
584 * RegOpenCurrentUser [ADVAPI32.@]
586 * Get a handle to the HKEY_CURRENT_USER key for the user
587 * the current thread is impersonating.
589 * PARAMS
590 * access [I] Desired access rights to the key
591 * retkey [O] Handle to the opened key
593 * RETURNS
594 * Success: ERROR_SUCCESS
595 * Failure: nonzero error code from Winerror.h
597 * FIXME
598 * This function is supposed to retrieve a handle to the
599 * HKEY_CURRENT_USER for the user the current thread is impersonating.
600 * Since Wine does not currently allow threads to impersonate other users,
601 * this stub should work fine.
603 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
605 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
610 /******************************************************************************
611 * RegEnumKeyExW [ADVAPI32.@]
613 * Enumerate subkeys of the specified open registry key.
615 * PARAMS
616 * hkey [I] Handle to key to enumerate
617 * index [I] Index of subkey to enumerate
618 * name [O] Buffer for subkey name
619 * name_len [O] Size of subkey buffer
620 * reserved [I] Reserved
621 * class [O] Buffer for class string
622 * class_len [O] Size of class buffer
623 * ft [O] Time key last written to
625 * RETURNS
626 * Success: ERROR_SUCCESS
627 * Failure: System error code. If there are no more subkeys available, the
628 * function returns ERROR_NO_MORE_ITEMS.
630 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
631 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
633 NTSTATUS status;
634 char buffer[256], *buf_ptr = buffer;
635 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
636 DWORD total_size;
638 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
639 name_len ? *name_len : 0, reserved, class, class_len, ft );
641 if (reserved) return ERROR_INVALID_PARAMETER;
642 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
644 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
645 buffer, sizeof(buffer), &total_size );
647 while (status == STATUS_BUFFER_OVERFLOW)
649 /* retry with a dynamically allocated buffer */
650 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
651 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
652 return ERROR_NOT_ENOUGH_MEMORY;
653 info = (KEY_NODE_INFORMATION *)buf_ptr;
654 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
655 buf_ptr, total_size, &total_size );
658 if (!status)
660 DWORD len = info->NameLength / sizeof(WCHAR);
661 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
663 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
665 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
666 status = STATUS_BUFFER_OVERFLOW;
667 else
669 *name_len = len;
670 memcpy( name, info->Name, info->NameLength );
671 name[len] = 0;
672 if (class_len)
674 *class_len = cls_len;
675 if (class)
677 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
678 class[cls_len] = 0;
684 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
685 return RtlNtStatusToDosError( status );
689 /******************************************************************************
690 * RegEnumKeyExA [ADVAPI32.@]
692 * See RegEnumKeyExW.
694 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
695 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
697 NTSTATUS status;
698 char buffer[256], *buf_ptr = buffer;
699 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
700 DWORD total_size;
702 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
703 name_len ? *name_len : 0, reserved, class, class_len, ft );
705 if (reserved) return ERROR_INVALID_PARAMETER;
706 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
708 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
709 buffer, sizeof(buffer), &total_size );
711 while (status == STATUS_BUFFER_OVERFLOW)
713 /* retry with a dynamically allocated buffer */
714 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
715 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
716 return ERROR_NOT_ENOUGH_MEMORY;
717 info = (KEY_NODE_INFORMATION *)buf_ptr;
718 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
719 buf_ptr, total_size, &total_size );
722 if (!status)
724 DWORD len, cls_len;
726 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
727 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
728 info->ClassLength );
729 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
731 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
732 status = STATUS_BUFFER_OVERFLOW;
733 else
735 *name_len = len;
736 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
737 name[len] = 0;
738 if (class_len)
740 *class_len = cls_len;
741 if (class)
743 RtlUnicodeToMultiByteN( class, cls_len, NULL,
744 (WCHAR *)(buf_ptr + info->ClassOffset),
745 info->ClassLength );
746 class[cls_len] = 0;
752 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
753 return RtlNtStatusToDosError( status );
757 /******************************************************************************
758 * RegEnumKeyW [ADVAPI32.@]
760 * Enumerates subkeys of the specified open reg key.
762 * PARAMS
763 * hKey [I] Handle to an open key.
764 * dwIndex [I] Index of the subkey of hKey to retrieve.
765 * lpName [O] Name of the subkey.
766 * cchName [I] Size of lpName in TCHARS.
768 * RETURNS
769 * Success: ERROR_SUCCESS
770 * Failure: system error code. If there are no more subkeys available, the
771 * function returns ERROR_NO_MORE_ITEMS.
773 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
775 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
779 /******************************************************************************
780 * RegEnumKeyA [ADVAPI32.@]
782 * See RegEnumKeyW.
784 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
786 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
790 /******************************************************************************
791 * RegQueryInfoKeyW [ADVAPI32.@]
793 * Retrieves information about the specified registry key.
795 * PARAMS
796 * hkey [I] Handle to key to query
797 * class [O] Buffer for class string
798 * class_len [O] Size of class string buffer
799 * reserved [I] Reserved
800 * subkeys [O] Buffer for number of subkeys
801 * max_subkey [O] Buffer for longest subkey name length
802 * max_class [O] Buffer for longest class string length
803 * values [O] Buffer for number of value entries
804 * max_value [O] Buffer for longest value name length
805 * max_data [O] Buffer for longest value data length
806 * security [O] Buffer for security descriptor length
807 * modif [O] Modification time
809 * RETURNS
810 * Success: ERROR_SUCCESS
811 * Failure: system error code.
813 * NOTES
814 * - win95 allows class to be valid and class_len to be NULL
815 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
816 * - both allow class to be NULL and class_len to be NULL
817 * (it's hard to test validity, so test !NULL instead)
819 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
820 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
821 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
822 LPDWORD security, FILETIME *modif )
824 NTSTATUS status;
825 char buffer[256], *buf_ptr = buffer;
826 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
827 DWORD total_size;
829 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
830 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
832 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
833 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
835 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
836 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
838 if (class)
840 /* retry with a dynamically allocated buffer */
841 while (status == STATUS_BUFFER_OVERFLOW)
843 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
844 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
845 return ERROR_NOT_ENOUGH_MEMORY;
846 info = (KEY_FULL_INFORMATION *)buf_ptr;
847 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
850 if (status) goto done;
852 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
854 status = STATUS_BUFFER_OVERFLOW;
856 else
858 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
859 class[info->ClassLength/sizeof(WCHAR)] = 0;
862 else status = STATUS_SUCCESS;
864 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
865 if (subkeys) *subkeys = info->SubKeys;
866 if (max_subkey) *max_subkey = info->MaxNameLen;
867 if (max_class) *max_class = info->MaxClassLen;
868 if (values) *values = info->Values;
869 if (max_value) *max_value = info->MaxValueNameLen;
870 if (max_data) *max_data = info->MaxValueDataLen;
871 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
873 done:
874 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
875 return RtlNtStatusToDosError( status );
879 /******************************************************************************
880 * RegQueryMultipleValuesA [ADVAPI32.@]
882 * Retrieves the type and data for a list of value names associated with a key.
884 * PARAMS
885 * hKey [I] Handle to an open key.
886 * val_list [O] Array of VALENT structures that describes the entries.
887 * num_vals [I] Number of elements in val_list.
888 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
889 * ldwTotsize [I/O] Size of lpValueBuf.
891 * RETURNS
892 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
893 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
894 * bytes.
896 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
897 LPSTR lpValueBuf, LPDWORD ldwTotsize )
899 unsigned int i;
900 DWORD maxBytes = *ldwTotsize;
901 HRESULT status;
902 LPSTR bufptr = lpValueBuf;
903 *ldwTotsize = 0;
905 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
907 for(i=0; i < num_vals; ++i)
910 val_list[i].ve_valuelen=0;
911 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
912 if(status != ERROR_SUCCESS)
914 return status;
917 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
919 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
920 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
921 if(status != ERROR_SUCCESS)
923 return status;
926 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
928 bufptr += val_list[i].ve_valuelen;
931 *ldwTotsize += val_list[i].ve_valuelen;
933 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
937 /******************************************************************************
938 * RegQueryMultipleValuesW [ADVAPI32.@]
940 * See RegQueryMultipleValuesA.
942 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
943 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
945 unsigned int i;
946 DWORD maxBytes = *ldwTotsize;
947 HRESULT status;
948 LPSTR bufptr = (LPSTR)lpValueBuf;
949 *ldwTotsize = 0;
951 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
953 for(i=0; i < num_vals; ++i)
955 val_list[i].ve_valuelen=0;
956 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
957 if(status != ERROR_SUCCESS)
959 return status;
962 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
964 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
965 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
966 if(status != ERROR_SUCCESS)
968 return status;
971 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
973 bufptr += val_list[i].ve_valuelen;
976 *ldwTotsize += val_list[i].ve_valuelen;
978 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
981 /******************************************************************************
982 * RegQueryInfoKeyA [ADVAPI32.@]
984 * Retrieves information about a registry key.
986 * PARAMS
987 * hKey [I] Handle to an open key.
988 * lpClass [O] Class string of the key.
989 * lpcClass [I/O] size of lpClass.
990 * lpReserved [I] Reserved; must be NULL.
991 * lpcSubKeys [O] Number of subkeys contained by the key.
992 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
993 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
994 * class in TCHARS.
995 * lpcValues [O] Number of values associated with the key.
996 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
997 * lpcMaxValueLen [O] Longest data component among the key's values
998 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
999 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
1001 * RETURNS
1002 * Success: ERROR_SUCCESS
1003 * Failure: nonzero error code from Winerror.h
1005 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
1006 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
1007 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
1008 LPDWORD security, FILETIME *modif )
1010 NTSTATUS status;
1011 char buffer[256], *buf_ptr = buffer;
1012 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
1013 DWORD total_size, len;
1015 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
1016 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
1018 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
1019 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1021 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
1022 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1024 if (class || class_len)
1026 /* retry with a dynamically allocated buffer */
1027 while (status == STATUS_BUFFER_OVERFLOW)
1029 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1030 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1031 return ERROR_NOT_ENOUGH_MEMORY;
1032 info = (KEY_FULL_INFORMATION *)buf_ptr;
1033 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
1036 if (status) goto done;
1038 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
1039 if (class_len)
1041 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
1042 *class_len = len;
1044 if (class && !status)
1046 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
1047 info->ClassLength );
1048 class[len] = 0;
1051 else status = STATUS_SUCCESS;
1053 if (subkeys) *subkeys = info->SubKeys;
1054 if (max_subkey) *max_subkey = info->MaxNameLen;
1055 if (max_class) *max_class = info->MaxClassLen;
1056 if (values) *values = info->Values;
1057 if (max_value) *max_value = info->MaxValueNameLen;
1058 if (max_data) *max_data = info->MaxValueDataLen;
1059 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
1061 done:
1062 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1063 return RtlNtStatusToDosError( status );
1067 /******************************************************************************
1068 * RegCloseKey [ADVAPI32.@]
1070 * Close an open registry key.
1072 * PARAMS
1073 * hkey [I] Handle of key to close
1075 * RETURNS
1076 * Success: ERROR_SUCCESS
1077 * Failure: Error code
1079 LSTATUS WINAPI RegCloseKey( HKEY hkey )
1081 if (!hkey) return ERROR_INVALID_HANDLE;
1082 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
1083 return RtlNtStatusToDosError( NtClose( hkey ) );
1087 /******************************************************************************
1088 * RegDeleteKeyExW [ADVAPI32.@]
1090 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
1092 DWORD ret;
1093 HKEY tmp;
1095 if (!name) return ERROR_INVALID_PARAMETER;
1097 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
1099 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1100 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
1102 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1103 RegCloseKey( tmp );
1105 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
1106 return ret;
1110 /******************************************************************************
1111 * RegDeleteKeyW [ADVAPI32.@]
1113 * See RegDeleteKeyA.
1115 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
1117 return RegDeleteKeyExW( hkey, name, 0, 0 );
1121 /******************************************************************************
1122 * RegDeleteKeyExA [ADVAPI32.@]
1124 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1126 DWORD ret;
1127 HKEY tmp;
1129 if (!name) return ERROR_INVALID_PARAMETER;
1131 if (!(hkey = get_special_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
1133 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1134 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1136 if (!is_version_nt()) /* win95 does recursive key deletes */
1138 CHAR sub[MAX_PATH];
1140 while(!RegEnumKeyA(tmp, 0, sub, sizeof(sub)))
1142 if(RegDeleteKeyExA(tmp, sub, access, reserved)) /* recurse */
1143 break;
1146 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1147 RegCloseKey( tmp );
1149 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1150 return ret;
1154 /******************************************************************************
1155 * RegDeleteKeyA [ADVAPI32.@]
1157 * Delete a registry key.
1159 * PARAMS
1160 * hkey [I] Handle to parent key containing the key to delete
1161 * name [I] Name of the key user hkey to delete
1163 * NOTES
1165 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1166 * right. In reality, it opens a new handle with DELETE access.
1168 * RETURNS
1169 * Success: ERROR_SUCCESS
1170 * Failure: Error code
1172 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1174 return RegDeleteKeyExA( hkey, name, 0, 0 );
1179 /******************************************************************************
1180 * RegSetValueExW [ADVAPI32.@]
1182 * Set the data and contents of a registry value.
1184 * PARAMS
1185 * hkey [I] Handle of key to set value for
1186 * name [I] Name of value to set
1187 * reserved [I] Reserved, must be zero
1188 * type [I] Type of the value being set
1189 * data [I] The new contents of the value to set
1190 * count [I] Size of data
1192 * RETURNS
1193 * Success: ERROR_SUCCESS
1194 * Failure: Error code
1196 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1197 DWORD type, const BYTE *data, DWORD count )
1199 UNICODE_STRING nameW;
1201 /* no need for version check, not implemented on win9x anyway */
1203 if (data && ((ULONG_PTR)data >> 16) == 0) return ERROR_NOACCESS;
1205 if (count && is_string(type))
1207 LPCWSTR str = (LPCWSTR)data;
1208 /* if user forgot to count terminating null, add it (yes NT does this) */
1209 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1210 count += sizeof(WCHAR);
1212 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1214 RtlInitUnicodeString( &nameW, name );
1215 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1219 /******************************************************************************
1220 * RegSetValueExA [ADVAPI32.@]
1222 * See RegSetValueExW.
1224 * NOTES
1225 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1226 * NT does definitely care (aj)
1228 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1229 const BYTE *data, DWORD count )
1231 ANSI_STRING nameA;
1232 UNICODE_STRING nameW;
1233 WCHAR *dataW = NULL;
1234 NTSTATUS status;
1236 if (!is_version_nt()) /* win95 */
1238 if (type == REG_SZ)
1240 if (!data) return ERROR_INVALID_PARAMETER;
1241 count = strlen((const char *)data) + 1;
1244 else if (count && is_string(type))
1246 /* if user forgot to count terminating null, add it (yes NT does this) */
1247 if (data[count-1] && !data[count]) count++;
1250 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1252 if (is_string( type )) /* need to convert to Unicode */
1254 DWORD lenW;
1255 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1256 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1257 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1258 count = lenW;
1259 data = (BYTE *)dataW;
1262 RtlInitAnsiString( &nameA, name );
1263 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1265 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1266 RtlFreeUnicodeString( &nameW );
1268 HeapFree( GetProcessHeap(), 0, dataW );
1269 return RtlNtStatusToDosError( status );
1273 /******************************************************************************
1274 * RegSetValueW [ADVAPI32.@]
1276 * Sets the data for the default or unnamed value of a reg key.
1278 * PARAMS
1279 * hKey [I] Handle to an open key.
1280 * lpSubKey [I] Name of a subkey of hKey.
1281 * dwType [I] Type of information to store.
1282 * lpData [I] String that contains the data to set for the default value.
1283 * cbData [I] Ignored.
1285 * RETURNS
1286 * Success: ERROR_SUCCESS
1287 * Failure: nonzero error code from Winerror.h
1289 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1291 HKEY subkey = hkey;
1292 DWORD ret;
1294 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1296 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1298 if (name && name[0]) /* need to create the subkey */
1300 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1303 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1304 (strlenW( data ) + 1) * sizeof(WCHAR) );
1305 if (subkey != hkey) RegCloseKey( subkey );
1306 return ret;
1310 /******************************************************************************
1311 * RegSetValueA [ADVAPI32.@]
1313 * See RegSetValueW.
1315 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1317 HKEY subkey = hkey;
1318 DWORD ret;
1320 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1322 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1324 if (name && name[0]) /* need to create the subkey */
1326 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1328 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1329 if (subkey != hkey) RegCloseKey( subkey );
1330 return ret;
1335 /******************************************************************************
1336 * RegQueryValueExW [ADVAPI32.@]
1338 * See RegQueryValueExA.
1340 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1341 LPBYTE data, LPDWORD count )
1343 NTSTATUS status;
1344 UNICODE_STRING name_str;
1345 DWORD total_size;
1346 char buffer[256], *buf_ptr = buffer;
1347 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1348 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1350 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1351 hkey, debugstr_w(name), reserved, type, data, count,
1352 (count && data) ? *count : 0 );
1354 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1355 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1357 RtlInitUnicodeString( &name_str, name );
1359 if (data) total_size = min( sizeof(buffer), *count + info_size );
1360 else
1362 total_size = info_size;
1363 if (count) *count = 0;
1366 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1367 buffer, total_size, &total_size );
1368 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1370 if (data)
1372 /* retry with a dynamically allocated buffer */
1373 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1375 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1376 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1377 return ERROR_NOT_ENOUGH_MEMORY;
1378 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1379 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1380 buf_ptr, total_size, &total_size );
1383 if (!status)
1385 memcpy( data, buf_ptr + info_size, total_size - info_size );
1386 /* if the type is REG_SZ and data is not 0-terminated
1387 * and there is enough space in the buffer NT appends a \0 */
1388 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1390 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1391 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1394 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1396 else status = STATUS_SUCCESS;
1398 if (type) *type = info->Type;
1399 if (count) *count = total_size - info_size;
1401 done:
1402 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1403 return RtlNtStatusToDosError(status);
1407 /******************************************************************************
1408 * RegQueryValueExA [ADVAPI32.@]
1410 * Get the type and contents of a specified value under with a key.
1412 * PARAMS
1413 * hkey [I] Handle of the key to query
1414 * name [I] Name of value under hkey to query
1415 * reserved [I] Reserved - must be NULL
1416 * type [O] Destination for the value type, or NULL if not required
1417 * data [O] Destination for the values contents, or NULL if not required
1418 * count [I/O] Size of data, updated with the number of bytes returned
1420 * RETURNS
1421 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1422 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1423 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1424 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1426 * NOTES
1427 * MSDN states that if data is too small it is partially filled. In reality
1428 * it remains untouched.
1430 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1431 LPBYTE data, LPDWORD count )
1433 NTSTATUS status;
1434 ANSI_STRING nameA;
1435 UNICODE_STRING nameW;
1436 DWORD total_size, datalen = 0;
1437 char buffer[256], *buf_ptr = buffer;
1438 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1439 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1441 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1442 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1444 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1445 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1447 if (count) datalen = *count;
1448 if (!data && count) *count = 0;
1450 /* this matches Win9x behaviour - NT sets *type to a random value */
1451 if (type) *type = REG_NONE;
1453 RtlInitAnsiString( &nameA, name );
1454 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1455 return RtlNtStatusToDosError(status);
1457 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1458 buffer, sizeof(buffer), &total_size );
1459 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1461 /* we need to fetch the contents for a string type even if not requested,
1462 * because we need to compute the length of the ASCII string. */
1463 if (data || is_string(info->Type))
1465 /* retry with a dynamically allocated buffer */
1466 while (status == STATUS_BUFFER_OVERFLOW)
1468 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1469 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1471 status = STATUS_NO_MEMORY;
1472 goto done;
1474 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1475 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1476 buf_ptr, total_size, &total_size );
1479 if (status) goto done;
1481 if (is_string(info->Type))
1483 DWORD len;
1485 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1486 total_size - info_size );
1487 if (data && len)
1489 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1490 else
1492 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1493 total_size - info_size );
1494 /* if the type is REG_SZ and data is not 0-terminated
1495 * and there is enough space in the buffer NT appends a \0 */
1496 if (len < datalen && data[len-1]) data[len] = 0;
1499 total_size = len + info_size;
1501 else if (data)
1503 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1504 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1507 else status = STATUS_SUCCESS;
1509 if (type) *type = info->Type;
1510 if (count) *count = total_size - info_size;
1512 done:
1513 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1514 RtlFreeUnicodeString( &nameW );
1515 return RtlNtStatusToDosError(status);
1519 /******************************************************************************
1520 * RegQueryValueW [ADVAPI32.@]
1522 * Retrieves the data associated with the default or unnamed value of a key.
1524 * PARAMS
1525 * hkey [I] Handle to an open key.
1526 * name [I] Name of the subkey of hKey.
1527 * data [O] Receives the string associated with the default value
1528 * of the key.
1529 * count [I/O] Size of lpValue in bytes.
1531 * RETURNS
1532 * Success: ERROR_SUCCESS
1533 * Failure: nonzero error code from Winerror.h
1535 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1537 DWORD ret;
1538 HKEY subkey = hkey;
1540 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1542 if (name && name[0])
1544 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1546 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1547 if (subkey != hkey) RegCloseKey( subkey );
1548 if (ret == ERROR_FILE_NOT_FOUND)
1550 /* return empty string if default value not found */
1551 if (data) *data = 0;
1552 if (count) *count = sizeof(WCHAR);
1553 ret = ERROR_SUCCESS;
1555 return ret;
1559 /******************************************************************************
1560 * RegQueryValueA [ADVAPI32.@]
1562 * See RegQueryValueW.
1564 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1566 DWORD ret;
1567 HKEY subkey = hkey;
1569 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1571 if (name && name[0])
1573 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1575 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1576 if (subkey != hkey) RegCloseKey( subkey );
1577 if (ret == ERROR_FILE_NOT_FOUND)
1579 /* return empty string if default value not found */
1580 if (data) *data = 0;
1581 if (count) *count = 1;
1582 ret = ERROR_SUCCESS;
1584 return ret;
1588 /******************************************************************************
1589 * ADVAPI_ApplyRestrictions [internal]
1591 * Helper function for RegGetValueA/W.
1593 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1594 DWORD cbData, PLONG ret )
1596 /* Check if the type is restricted by the passed flags */
1597 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1599 DWORD dwMask = 0;
1601 switch (dwType)
1603 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1604 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1605 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1606 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1607 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1608 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1609 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1612 if (dwFlags & dwMask)
1614 /* Type is not restricted, check for size mismatch */
1615 if (dwType == REG_BINARY)
1617 DWORD cbExpect = 0;
1619 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1620 cbExpect = 4;
1621 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1622 cbExpect = 8;
1624 if (cbExpect && cbData != cbExpect)
1625 *ret = ERROR_DATATYPE_MISMATCH;
1628 else *ret = ERROR_UNSUPPORTED_TYPE;
1633 /******************************************************************************
1634 * RegGetValueW [ADVAPI32.@]
1636 * Retrieves the type and data for a value name associated with a key,
1637 * optionally expanding its content and restricting its type.
1639 * PARAMS
1640 * hKey [I] Handle to an open key.
1641 * pszSubKey [I] Name of the subkey of hKey.
1642 * pszValue [I] Name of value under hKey/szSubKey to query.
1643 * dwFlags [I] Flags restricting the value type to retrieve.
1644 * pdwType [O] Destination for the values type, may be NULL.
1645 * pvData [O] Destination for the values content, may be NULL.
1646 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1647 * retrieve the whole content, including the trailing '\0'
1648 * for strings.
1650 * RETURNS
1651 * Success: ERROR_SUCCESS
1652 * Failure: nonzero error code from Winerror.h
1654 * NOTES
1655 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1656 * expanded and pdwType is set to REG_SZ instead.
1657 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1658 * without RRF_NOEXPAND is thus not allowed.
1659 * An exception is the case where RRF_RT_ANY is specified, because then
1660 * RRF_NOEXPAND is allowed.
1662 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1663 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1664 LPDWORD pcbData )
1666 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1667 PVOID pvBuf = NULL;
1668 LONG ret;
1670 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1671 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1672 pvData, pcbData, cbData);
1674 if (pvData && !pcbData)
1675 return ERROR_INVALID_PARAMETER;
1676 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1677 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1678 return ERROR_INVALID_PARAMETER;
1680 if (pszSubKey && pszSubKey[0])
1682 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1683 if (ret != ERROR_SUCCESS) return ret;
1686 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1688 /* If we are going to expand we need to read in the whole the value even
1689 * if the passed buffer was too small as the expanded string might be
1690 * smaller than the unexpanded one and could fit into cbData bytes. */
1691 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1692 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1694 do {
1695 HeapFree(GetProcessHeap(), 0, pvBuf);
1697 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1698 if (!pvBuf)
1700 ret = ERROR_NOT_ENOUGH_MEMORY;
1701 break;
1704 if (ret == ERROR_MORE_DATA || !pvData)
1705 ret = RegQueryValueExW(hKey, pszValue, NULL,
1706 &dwType, pvBuf, &cbData);
1707 else
1709 /* Even if cbData was large enough we have to copy the
1710 * string since ExpandEnvironmentStrings can't handle
1711 * overlapping buffers. */
1712 CopyMemory(pvBuf, pvData, cbData);
1715 /* Both the type or the value itself could have been modified in
1716 * between so we have to keep retrying until the buffer is large
1717 * enough or we no longer have to expand the value. */
1718 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1720 if (ret == ERROR_SUCCESS)
1722 /* Recheck dwType in case it changed since the first call */
1723 if (dwType == REG_EXPAND_SZ)
1725 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1726 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1727 dwType = REG_SZ;
1728 if(pvData && pcbData && cbData > *pcbData)
1729 ret = ERROR_MORE_DATA;
1731 else if (pvData)
1732 CopyMemory(pvData, pvBuf, *pcbData);
1735 HeapFree(GetProcessHeap(), 0, pvBuf);
1738 if (pszSubKey && pszSubKey[0])
1739 RegCloseKey(hKey);
1741 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1743 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1744 ZeroMemory(pvData, *pcbData);
1746 if (pdwType) *pdwType = dwType;
1747 if (pcbData) *pcbData = cbData;
1749 return ret;
1753 /******************************************************************************
1754 * RegGetValueA [ADVAPI32.@]
1756 * See RegGetValueW.
1758 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1759 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1760 LPDWORD pcbData )
1762 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1763 PVOID pvBuf = NULL;
1764 LONG ret;
1766 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1767 hKey, debugstr_a(pszSubKey), debugstr_a(pszValue), dwFlags,
1768 pdwType, pvData, pcbData, cbData);
1770 if (pvData && !pcbData)
1771 return ERROR_INVALID_PARAMETER;
1772 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1773 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1774 return ERROR_INVALID_PARAMETER;
1776 if (pszSubKey && pszSubKey[0])
1778 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1779 if (ret != ERROR_SUCCESS) return ret;
1782 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1784 /* If we are going to expand we need to read in the whole the value even
1785 * if the passed buffer was too small as the expanded string might be
1786 * smaller than the unexpanded one and could fit into cbData bytes. */
1787 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1788 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1790 do {
1791 HeapFree(GetProcessHeap(), 0, pvBuf);
1793 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1794 if (!pvBuf)
1796 ret = ERROR_NOT_ENOUGH_MEMORY;
1797 break;
1800 if (ret == ERROR_MORE_DATA || !pvData)
1801 ret = RegQueryValueExA(hKey, pszValue, NULL,
1802 &dwType, pvBuf, &cbData);
1803 else
1805 /* Even if cbData was large enough we have to copy the
1806 * string since ExpandEnvironmentStrings can't handle
1807 * overlapping buffers. */
1808 CopyMemory(pvBuf, pvData, cbData);
1811 /* Both the type or the value itself could have been modified in
1812 * between so we have to keep retrying until the buffer is large
1813 * enough or we no longer have to expand the value. */
1814 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1816 if (ret == ERROR_SUCCESS)
1818 /* Recheck dwType in case it changed since the first call */
1819 if (dwType == REG_EXPAND_SZ)
1821 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1822 pcbData ? *pcbData : 0);
1823 dwType = REG_SZ;
1824 if(pvData && pcbData && cbData > *pcbData)
1825 ret = ERROR_MORE_DATA;
1827 else if (pvData)
1828 CopyMemory(pvData, pvBuf, *pcbData);
1831 HeapFree(GetProcessHeap(), 0, pvBuf);
1834 if (pszSubKey && pszSubKey[0])
1835 RegCloseKey(hKey);
1837 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1839 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1840 ZeroMemory(pvData, *pcbData);
1842 if (pdwType) *pdwType = dwType;
1843 if (pcbData) *pcbData = cbData;
1845 return ret;
1849 /******************************************************************************
1850 * RegEnumValueW [ADVAPI32.@]
1852 * Enumerates the values for the specified open registry key.
1854 * PARAMS
1855 * hkey [I] Handle to key to query
1856 * index [I] Index of value to query
1857 * value [O] Value string
1858 * val_count [I/O] Size of value buffer (in wchars)
1859 * reserved [I] Reserved
1860 * type [O] Type code
1861 * data [O] Value data
1862 * count [I/O] Size of data buffer (in bytes)
1864 * RETURNS
1865 * Success: ERROR_SUCCESS
1866 * Failure: nonzero error code from Winerror.h
1869 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1870 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1872 NTSTATUS status;
1873 DWORD total_size;
1874 char buffer[256], *buf_ptr = buffer;
1875 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1876 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1878 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1879 hkey, index, value, val_count, reserved, type, data, count );
1881 /* NT only checks count, not val_count */
1882 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1883 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1885 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1886 if (data) total_size += *count;
1887 total_size = min( sizeof(buffer), total_size );
1889 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1890 buffer, total_size, &total_size );
1891 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1893 if (value || data)
1895 /* retry with a dynamically allocated buffer */
1896 while (status == STATUS_BUFFER_OVERFLOW)
1898 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1899 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1900 return ERROR_NOT_ENOUGH_MEMORY;
1901 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1902 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1903 buf_ptr, total_size, &total_size );
1906 if (status) goto done;
1908 if (value)
1910 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1912 status = STATUS_BUFFER_OVERFLOW;
1913 goto overflow;
1915 memcpy( value, info->Name, info->NameLength );
1916 *val_count = info->NameLength / sizeof(WCHAR);
1917 value[*val_count] = 0;
1920 if (data)
1922 if (total_size - info->DataOffset > *count)
1924 status = STATUS_BUFFER_OVERFLOW;
1925 goto overflow;
1927 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1928 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1930 /* if the type is REG_SZ and data is not 0-terminated
1931 * and there is enough space in the buffer NT appends a \0 */
1932 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1933 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1937 else status = STATUS_SUCCESS;
1939 overflow:
1940 if (type) *type = info->Type;
1941 if (count) *count = info->DataLength;
1943 done:
1944 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1945 return RtlNtStatusToDosError(status);
1949 /******************************************************************************
1950 * RegEnumValueA [ADVAPI32.@]
1952 * See RegEnumValueW.
1954 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1955 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1957 NTSTATUS status;
1958 DWORD total_size;
1959 char buffer[256], *buf_ptr = buffer;
1960 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1961 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1963 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1964 hkey, index, value, val_count, reserved, type, data, count );
1966 /* NT only checks count, not val_count */
1967 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1968 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1970 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1971 if (data) total_size += *count;
1972 total_size = min( sizeof(buffer), total_size );
1974 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1975 buffer, total_size, &total_size );
1976 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1978 /* we need to fetch the contents for a string type even if not requested,
1979 * because we need to compute the length of the ASCII string. */
1980 if (value || data || is_string(info->Type))
1982 /* retry with a dynamically allocated buffer */
1983 while (status == STATUS_BUFFER_OVERFLOW)
1985 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1986 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1987 return ERROR_NOT_ENOUGH_MEMORY;
1988 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1989 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1990 buf_ptr, total_size, &total_size );
1993 if (status) goto done;
1995 if (is_string(info->Type))
1997 DWORD len;
1998 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1999 total_size - info->DataOffset );
2000 if (data && len)
2002 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
2003 else
2005 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
2006 total_size - info->DataOffset );
2007 /* if the type is REG_SZ and data is not 0-terminated
2008 * and there is enough space in the buffer NT appends a \0 */
2009 if (len < *count && data[len-1]) data[len] = 0;
2012 info->DataLength = len;
2014 else if (data)
2016 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
2017 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2020 if (value && !status)
2022 DWORD len;
2024 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2025 if (len >= *val_count)
2027 status = STATUS_BUFFER_OVERFLOW;
2028 if (*val_count)
2030 len = *val_count - 1;
2031 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2032 value[len] = 0;
2035 else
2037 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2038 value[len] = 0;
2039 *val_count = len;
2043 else status = STATUS_SUCCESS;
2045 if (type) *type = info->Type;
2046 if (count) *count = info->DataLength;
2048 done:
2049 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2050 return RtlNtStatusToDosError(status);
2053 /******************************************************************************
2054 * RegDeleteValueW [ADVAPI32.@]
2056 * See RegDeleteValueA.
2058 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2060 return RegDeleteKeyValueW( hkey, NULL, name );
2063 /******************************************************************************
2064 * RegDeleteValueA [ADVAPI32.@]
2066 * Delete a value from the registry.
2068 * PARAMS
2069 * hkey [I] Registry handle of the key holding the value
2070 * name [I] Name of the value under hkey to delete
2072 * RETURNS
2073 * Success: ERROR_SUCCESS
2074 * Failure: nonzero error code from Winerror.h
2076 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2078 return RegDeleteKeyValueA( hkey, NULL, name );
2081 /******************************************************************************
2082 * RegDeleteKeyValueW [ADVAPI32.@]
2084 LONG WINAPI RegDeleteKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name )
2086 UNICODE_STRING nameW;
2087 HKEY hsubkey = 0;
2088 LONG ret;
2090 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2092 if (subkey)
2094 if ((ret = RegOpenKeyExW( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey )))
2095 return ret;
2096 hkey = hsubkey;
2099 RtlInitUnicodeString( &nameW, name );
2100 ret = RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2101 if (hsubkey) RegCloseKey( hsubkey );
2102 return ret;
2105 /******************************************************************************
2106 * RegDeleteKeyValueA [ADVAPI32.@]
2108 LONG WINAPI RegDeleteKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name )
2110 UNICODE_STRING nameW;
2111 HKEY hsubkey = 0;
2112 ANSI_STRING nameA;
2113 NTSTATUS status;
2115 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2117 if (subkey)
2119 LONG ret = RegOpenKeyExA( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey );
2120 if (ret)
2121 return ret;
2122 hkey = hsubkey;
2125 RtlInitAnsiString( &nameA, name );
2126 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2128 status = NtDeleteValueKey( hkey, &nameW );
2129 RtlFreeUnicodeString( &nameW );
2132 if (hsubkey) RegCloseKey( hsubkey );
2133 return RtlNtStatusToDosError( status );
2136 /******************************************************************************
2137 * RegLoadKeyW [ADVAPI32.@]
2139 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2140 * registration information from a specified file into that subkey.
2142 * PARAMS
2143 * hkey [I] Handle of open key
2144 * subkey [I] Address of name of subkey
2145 * filename [I] Address of filename for registry information
2147 * RETURNS
2148 * Success: ERROR_SUCCESS
2149 * Failure: nonzero error code from Winerror.h
2151 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2153 OBJECT_ATTRIBUTES destkey, file;
2154 UNICODE_STRING subkeyW, filenameW;
2155 NTSTATUS status;
2157 if (!(hkey = get_special_root_hkey(hkey, 0))) return ERROR_INVALID_HANDLE;
2159 destkey.Length = sizeof(destkey);
2160 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2161 destkey.ObjectName = &subkeyW; /* name of the key */
2162 destkey.Attributes = 0;
2163 destkey.SecurityDescriptor = NULL;
2164 destkey.SecurityQualityOfService = NULL;
2165 RtlInitUnicodeString(&subkeyW, subkey);
2167 file.Length = sizeof(file);
2168 file.RootDirectory = NULL;
2169 file.ObjectName = &filenameW; /* file containing the hive */
2170 file.Attributes = OBJ_CASE_INSENSITIVE;
2171 file.SecurityDescriptor = NULL;
2172 file.SecurityQualityOfService = NULL;
2173 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2175 status = NtLoadKey(&destkey, &file);
2176 RtlFreeUnicodeString(&filenameW);
2177 return RtlNtStatusToDosError( status );
2181 /******************************************************************************
2182 * RegLoadKeyA [ADVAPI32.@]
2184 * See RegLoadKeyW.
2186 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2188 UNICODE_STRING subkeyW, filenameW;
2189 STRING subkeyA, filenameA;
2190 NTSTATUS status;
2191 LONG ret;
2193 RtlInitAnsiString(&subkeyA, subkey);
2194 RtlInitAnsiString(&filenameA, filename);
2196 RtlInitUnicodeString(&subkeyW, NULL);
2197 RtlInitUnicodeString(&filenameW, NULL);
2198 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2199 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2201 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2203 else ret = RtlNtStatusToDosError(status);
2204 RtlFreeUnicodeString(&subkeyW);
2205 RtlFreeUnicodeString(&filenameW);
2206 return ret;
2210 /******************************************************************************
2211 * RegSaveKeyW [ADVAPI32.@]
2213 * Save a key and all of its subkeys and values to a new file in the standard format.
2215 * PARAMS
2216 * hkey [I] Handle of key where save begins
2217 * lpFile [I] Address of filename to save to
2218 * sa [I] Address of security structure
2220 * RETURNS
2221 * Success: ERROR_SUCCESS
2222 * Failure: nonzero error code from Winerror.h
2224 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2226 static const WCHAR format[] =
2227 {'r','e','g','%','0','4','x','.','t','m','p',0};
2228 WCHAR buffer[MAX_PATH];
2229 int count = 0;
2230 LPWSTR nameW;
2231 DWORD ret, err;
2232 HANDLE handle;
2234 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2236 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2237 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2239 err = GetLastError();
2240 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2242 for (;;)
2244 snprintfW( nameW, 16, format, count++ );
2245 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2246 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2247 if (handle != INVALID_HANDLE_VALUE) break;
2248 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2250 /* Something gone haywire ? Please report if this happens abnormally */
2251 if (count >= 100)
2252 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);
2255 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2257 CloseHandle( handle );
2258 if (!ret)
2260 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2262 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2263 debugstr_w(file) );
2264 ret = GetLastError();
2267 if (ret) DeleteFileW( buffer );
2269 done:
2270 SetLastError( err ); /* restore last error code */
2271 return ret;
2275 /******************************************************************************
2276 * RegSaveKeyA [ADVAPI32.@]
2278 * See RegSaveKeyW.
2280 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2282 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2283 NTSTATUS status;
2284 STRING fileA;
2286 RtlInitAnsiString(&fileA, file);
2287 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2288 return RtlNtStatusToDosError( status );
2289 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2293 /******************************************************************************
2294 * RegRestoreKeyW [ADVAPI32.@]
2296 * Read the registry information from a file and copy it over a key.
2298 * PARAMS
2299 * hkey [I] Handle of key where restore begins
2300 * lpFile [I] Address of filename containing saved tree
2301 * dwFlags [I] Optional flags
2303 * RETURNS
2304 * Success: ERROR_SUCCESS
2305 * Failure: nonzero error code from Winerror.h
2307 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2309 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2311 /* It seems to do this check before the hkey check */
2312 if (!lpFile || !*lpFile)
2313 return ERROR_INVALID_PARAMETER;
2315 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2317 /* Check for file existence */
2319 return ERROR_SUCCESS;
2323 /******************************************************************************
2324 * RegRestoreKeyA [ADVAPI32.@]
2326 * See RegRestoreKeyW.
2328 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2330 UNICODE_STRING lpFileW;
2331 LONG ret;
2333 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2334 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2335 RtlFreeUnicodeString( &lpFileW );
2336 return ret;
2340 /******************************************************************************
2341 * RegUnLoadKeyW [ADVAPI32.@]
2343 * Unload a registry key and its subkeys from the registry.
2345 * PARAMS
2346 * hkey [I] Handle of open key
2347 * lpSubKey [I] Address of name of subkey to unload
2349 * RETURNS
2350 * Success: ERROR_SUCCESS
2351 * Failure: nonzero error code from Winerror.h
2353 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2355 DWORD ret;
2356 HKEY shkey;
2357 OBJECT_ATTRIBUTES attr;
2358 UNICODE_STRING subkey;
2360 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2362 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2363 if( ret )
2364 return ERROR_INVALID_PARAMETER;
2366 RtlInitUnicodeString(&subkey, lpSubKey);
2367 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2368 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2370 RegCloseKey(shkey);
2372 return ret;
2376 /******************************************************************************
2377 * RegUnLoadKeyA [ADVAPI32.@]
2379 * See RegUnLoadKeyW.
2381 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2383 UNICODE_STRING lpSubKeyW;
2384 LONG ret;
2386 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2387 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2388 RtlFreeUnicodeString( &lpSubKeyW );
2389 return ret;
2393 /******************************************************************************
2394 * RegReplaceKeyW [ADVAPI32.@]
2396 * Replace the file backing a registry key and all its subkeys with another file.
2398 * PARAMS
2399 * hkey [I] Handle of open key
2400 * lpSubKey [I] Address of name of subkey
2401 * lpNewFile [I] Address of filename for file with new data
2402 * lpOldFile [I] Address of filename for backup file
2404 * RETURNS
2405 * Success: ERROR_SUCCESS
2406 * Failure: nonzero error code from Winerror.h
2408 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2409 LPCWSTR lpOldFile )
2411 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2412 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2413 return ERROR_SUCCESS;
2417 /******************************************************************************
2418 * RegReplaceKeyA [ADVAPI32.@]
2420 * See RegReplaceKeyW.
2422 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2423 LPCSTR lpOldFile )
2425 UNICODE_STRING lpSubKeyW;
2426 UNICODE_STRING lpNewFileW;
2427 UNICODE_STRING lpOldFileW;
2428 LONG ret;
2430 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2431 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2432 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2433 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2434 RtlFreeUnicodeString( &lpOldFileW );
2435 RtlFreeUnicodeString( &lpNewFileW );
2436 RtlFreeUnicodeString( &lpSubKeyW );
2437 return ret;
2441 /******************************************************************************
2442 * RegSetKeySecurity [ADVAPI32.@]
2444 * Set the security of an open registry key.
2446 * PARAMS
2447 * hkey [I] Open handle of key to set
2448 * SecurityInfo [I] Descriptor contents
2449 * pSecurityDesc [I] Address of descriptor for key
2451 * RETURNS
2452 * Success: ERROR_SUCCESS
2453 * Failure: nonzero error code from Winerror.h
2455 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2456 PSECURITY_DESCRIPTOR pSecurityDesc )
2458 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2460 /* It seems to perform this check before the hkey check */
2461 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2462 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2463 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2464 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2465 /* Param OK */
2466 } else
2467 return ERROR_INVALID_PARAMETER;
2469 if (!pSecurityDesc)
2470 return ERROR_INVALID_PARAMETER;
2472 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2474 return ERROR_SUCCESS;
2478 /******************************************************************************
2479 * RegGetKeySecurity [ADVAPI32.@]
2481 * Get a copy of the security descriptor for a given registry key.
2483 * PARAMS
2484 * hkey [I] Open handle of key to set
2485 * SecurityInformation [I] Descriptor contents
2486 * pSecurityDescriptor [O] Address of descriptor for key
2487 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2489 * RETURNS
2490 * Success: ERROR_SUCCESS
2491 * Failure: Error code
2493 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2494 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2495 LPDWORD lpcbSecurityDescriptor )
2497 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2498 *lpcbSecurityDescriptor);
2500 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2502 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2503 SecurityInformation, pSecurityDescriptor,
2504 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2508 /******************************************************************************
2509 * RegFlushKey [ADVAPI32.@]
2511 * Immediately write a registry key to registry.
2513 * PARAMS
2514 * hkey [I] Handle of key to write
2516 * RETURNS
2517 * Success: ERROR_SUCCESS
2518 * Failure: Error code
2520 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2522 hkey = get_special_root_hkey( hkey, 0 );
2523 if (!hkey) return ERROR_INVALID_HANDLE;
2525 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2529 /******************************************************************************
2530 * RegConnectRegistryW [ADVAPI32.@]
2532 * Establish a connection to a predefined registry key on another computer.
2534 * PARAMS
2535 * lpMachineName [I] Address of name of remote computer
2536 * hHey [I] Predefined registry handle
2537 * phkResult [I] Address of buffer for remote registry handle
2539 * RETURNS
2540 * Success: ERROR_SUCCESS
2541 * Failure: nonzero error code from Winerror.h
2543 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2544 PHKEY phkResult )
2546 LONG ret;
2548 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName), hKey, phkResult);
2550 if (!lpMachineName || !*lpMachineName) {
2551 /* Use the local machine name */
2552 ret = RegOpenKeyW( hKey, NULL, phkResult );
2554 else {
2555 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2556 DWORD len = sizeof(compName) / sizeof(WCHAR);
2558 /* MSDN says lpMachineName must start with \\ : not so */
2559 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2560 lpMachineName += 2;
2561 if (GetComputerNameW(compName, &len))
2563 if (!strcmpiW(lpMachineName, compName))
2564 ret = RegOpenKeyW(hKey, NULL, phkResult);
2565 else
2567 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2568 ret = ERROR_BAD_NETPATH;
2571 else
2572 ret = GetLastError();
2574 return ret;
2578 /******************************************************************************
2579 * RegConnectRegistryA [ADVAPI32.@]
2581 * See RegConnectRegistryW.
2583 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2585 UNICODE_STRING machineW;
2586 LONG ret;
2588 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2589 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2590 RtlFreeUnicodeString( &machineW );
2591 return ret;
2595 /******************************************************************************
2596 * RegNotifyChangeKeyValue [ADVAPI32.@]
2598 * Notify the caller about changes to the attributes or contents of a registry key.
2600 * PARAMS
2601 * hkey [I] Handle of key to watch
2602 * fWatchSubTree [I] Flag for subkey notification
2603 * fdwNotifyFilter [I] Changes to be reported
2604 * hEvent [I] Handle of signaled event
2605 * fAsync [I] Flag for asynchronous reporting
2607 * RETURNS
2608 * Success: ERROR_SUCCESS
2609 * Failure: nonzero error code from Winerror.h
2611 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2612 DWORD fdwNotifyFilter, HANDLE hEvent,
2613 BOOL fAsync )
2615 NTSTATUS status;
2616 IO_STATUS_BLOCK iosb;
2618 hkey = get_special_root_hkey( hkey, 0 );
2619 if (!hkey) return ERROR_INVALID_HANDLE;
2621 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2622 hEvent, fAsync);
2624 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2625 fdwNotifyFilter, fAsync, NULL, 0,
2626 fWatchSubTree);
2628 if (status && status != STATUS_TIMEOUT)
2629 return RtlNtStatusToDosError( status );
2631 return ERROR_SUCCESS;
2634 /******************************************************************************
2635 * RegOpenUserClassesRoot [ADVAPI32.@]
2637 * Open the HKEY_CLASSES_ROOT key for a user.
2639 * PARAMS
2640 * hToken [I] Handle of token representing the user
2641 * dwOptions [I] Reserved, must be 0
2642 * samDesired [I] Desired access rights
2643 * phkResult [O] Destination for the resulting key handle
2645 * RETURNS
2646 * Success: ERROR_SUCCESS
2647 * Failure: nonzero error code from Winerror.h
2649 * NOTES
2650 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2651 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2652 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2654 LSTATUS WINAPI RegOpenUserClassesRoot(
2655 HANDLE hToken,
2656 DWORD dwOptions,
2657 REGSAM samDesired,
2658 PHKEY phkResult
2661 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2663 *phkResult = HKEY_CLASSES_ROOT;
2664 return ERROR_SUCCESS;
2667 /******************************************************************************
2668 * load_string [Internal]
2670 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2671 * avoid importing user32, which is higher level than advapi32. Helper for
2672 * RegLoadMUIString.
2674 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2676 HGLOBAL hMemory;
2677 HRSRC hResource;
2678 WCHAR *pString;
2679 int idxString;
2681 /* Negative values have to be inverted. */
2682 if (HIWORD(resId) == 0xffff)
2683 resId = (UINT)(-((INT)resId));
2685 /* Load the resource into memory and get a pointer to it. */
2686 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2687 if (!hResource) return 0;
2688 hMemory = LoadResource(hModule, hResource);
2689 if (!hMemory) return 0;
2690 pString = LockResource(hMemory);
2692 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2693 idxString = resId & 0xf;
2694 while (idxString--) pString += *pString + 1;
2696 /* If no buffer is given, return length of the string. */
2697 if (!pwszBuffer) return *pString;
2699 /* Else copy over the string, respecting the buffer size. */
2700 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2701 if (cMaxChars >= 0) {
2702 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2703 pwszBuffer[cMaxChars] = '\0';
2706 return cMaxChars;
2709 /******************************************************************************
2710 * RegLoadMUIStringW [ADVAPI32.@]
2712 * Load the localized version of a string resource from some PE, respective
2713 * id and path of which are given in the registry value in the format
2714 * @[path]\dllname,-resourceId
2716 * PARAMS
2717 * hKey [I] Key, of which to load the string value from.
2718 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2719 * pszBuffer [O] Buffer to store the localized string in.
2720 * cbBuffer [I] Size of the destination buffer in bytes.
2721 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2722 * dwFlags [I] None supported yet.
2723 * pszBaseDir [I] Not supported yet.
2725 * RETURNS
2726 * Success: ERROR_SUCCESS,
2727 * Failure: nonzero error code from winerror.h
2729 * NOTES
2730 * This is an API of Windows Vista, which wasn't available at the time this code
2731 * was written. We have to check for the correct behaviour once it's available.
2733 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2734 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2736 DWORD dwValueType, cbData;
2737 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2738 LONG result;
2740 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2741 "dwFlags = %d, pwszBaseDir = %s)\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2742 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2744 /* Parameter sanity checks. */
2745 if (!hKey || !pwszBuffer)
2746 return ERROR_INVALID_PARAMETER;
2748 if (pwszBaseDir && *pwszBaseDir) {
2749 FIXME("BaseDir parameter not yet supported!\n");
2750 return ERROR_INVALID_PARAMETER;
2753 /* Check for value existence and correctness of its type, allocate a buffer and load it. */
2754 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2755 if (result != ERROR_SUCCESS) goto cleanup;
2756 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2757 result = ERROR_FILE_NOT_FOUND;
2758 goto cleanup;
2760 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2761 if (!pwszTempBuffer) {
2762 result = ERROR_NOT_ENOUGH_MEMORY;
2763 goto cleanup;
2765 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2766 if (result != ERROR_SUCCESS) goto cleanup;
2768 /* Expand environment variables, if appropriate, or copy the original string over. */
2769 if (dwValueType == REG_EXPAND_SZ) {
2770 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2771 if (!cbData) goto cleanup;
2772 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2773 if (!pwszExpandedBuffer) {
2774 result = ERROR_NOT_ENOUGH_MEMORY;
2775 goto cleanup;
2777 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2778 } else {
2779 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2780 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2783 /* If the value references a resource based string, parse the value and load the string.
2784 * Else just copy over the original value. */
2785 result = ERROR_SUCCESS;
2786 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2787 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2788 } else {
2789 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2790 UINT uiStringId;
2791 HMODULE hModule;
2793 /* Format of the expanded value is 'path_to_dll,-resId' */
2794 if (!pComma || pComma[1] != '-') {
2795 result = ERROR_BADKEY;
2796 goto cleanup;
2799 uiStringId = atoiW(pComma+2);
2800 *pComma = '\0';
2802 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2803 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2804 result = ERROR_BADKEY;
2805 FreeLibrary(hModule);
2808 cleanup:
2809 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2810 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2811 return result;
2814 /******************************************************************************
2815 * RegLoadMUIStringA [ADVAPI32.@]
2817 * See RegLoadMUIStringW
2819 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2820 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2822 UNICODE_STRING valueW, baseDirW;
2823 WCHAR *pwszBuffer;
2824 DWORD cbData = cbBuffer * sizeof(WCHAR);
2825 LONG result;
2827 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2828 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2829 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2830 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2832 result = ERROR_NOT_ENOUGH_MEMORY;
2833 goto cleanup;
2836 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2837 baseDirW.Buffer);
2839 if (result == ERROR_SUCCESS) {
2840 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2841 if (pcbData)
2842 *pcbData = cbData;
2845 cleanup:
2846 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2847 RtlFreeUnicodeString(&baseDirW);
2848 RtlFreeUnicodeString(&valueW);
2850 return result;
2853 /******************************************************************************
2854 * RegDisablePredefinedCache [ADVAPI32.@]
2856 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2858 * PARAMS
2859 * None.
2861 * RETURNS
2862 * Success: ERROR_SUCCESS
2863 * Failure: nonzero error code from Winerror.h
2865 * NOTES
2866 * This is useful for services that use impersonation.
2868 LSTATUS WINAPI RegDisablePredefinedCache(void)
2870 HKEY hkey_current_user;
2871 int idx = HandleToUlong(HKEY_CURRENT_USER) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
2873 /* prevent caching of future requests */
2874 hkcu_cache_disabled = TRUE;
2876 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2878 if (hkey_current_user)
2879 NtClose( hkey_current_user );
2881 return ERROR_SUCCESS;
2884 /******************************************************************************
2885 * RegDeleteTreeW [ADVAPI32.@]
2888 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2890 LONG ret;
2891 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2892 DWORD dwMaxLen, dwSize;
2893 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2894 HKEY hSubKey = hKey;
2896 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2898 if(lpszSubKey)
2900 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2901 if (ret) return ret;
2904 /* Get highest length for keys, values */
2905 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2906 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2907 if (ret) goto cleanup;
2909 dwMaxSubkeyLen++;
2910 dwMaxValueLen++;
2911 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2912 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2914 /* Name too big: alloc a buffer for it */
2915 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2917 ret = ERROR_NOT_ENOUGH_MEMORY;
2918 goto cleanup;
2923 /* Recursively delete all the subkeys */
2924 while (TRUE)
2926 dwSize = dwMaxLen;
2927 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2928 NULL, NULL, NULL)) break;
2930 ret = RegDeleteTreeW(hSubKey, lpszName);
2931 if (ret) goto cleanup;
2934 if (lpszSubKey)
2935 ret = RegDeleteKeyW(hKey, lpszSubKey);
2936 else
2937 while (TRUE)
2939 dwSize = dwMaxLen;
2940 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2941 NULL, NULL, NULL, NULL)) break;
2943 ret = RegDeleteValueW(hKey, lpszName);
2944 if (ret) goto cleanup;
2947 cleanup:
2948 /* Free buffer if allocated */
2949 if (lpszName != szNameBuf)
2950 HeapFree( GetProcessHeap(), 0, lpszName);
2951 if(lpszSubKey)
2952 RegCloseKey(hSubKey);
2953 return ret;
2956 /******************************************************************************
2957 * RegDeleteTreeA [ADVAPI32.@]
2960 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2962 LONG ret;
2963 UNICODE_STRING lpszSubKeyW;
2965 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2966 else lpszSubKeyW.Buffer = NULL;
2967 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2968 RtlFreeUnicodeString( &lpszSubKeyW );
2969 return ret;
2972 /******************************************************************************
2973 * RegDisableReflectionKey [ADVAPI32.@]
2976 LONG WINAPI RegDisableReflectionKey(HKEY base)
2978 FIXME("%p: stub\n", base);
2979 return ERROR_SUCCESS;