wbemprox: Don't fail if there are less objects than asked for in IEnumWbemClassObject...
[wine.git] / dlls / advapi32 / registry.c
blobc01e12546f00c2f54d46c482e8a1bb0e0a329fde
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 int is_win64 = (sizeof(void *) > sizeof(int));
84 /* check if value type needs string conversion (Ansi<->Unicode) */
85 static inline int 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 int 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->Attributes &= ~OBJ_OPENLINK;
144 attr->ObjectName = &str;
146 while (i < len)
148 str.Buffer = buffer + pos;
149 str.Length = (i - pos) * sizeof(WCHAR);
150 if (force_wow32 && pos)
152 if (is_wow6432node( &str )) force_wow32 = FALSE;
153 else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
155 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
156 attr->RootDirectory = subkey;
157 force_wow32 = FALSE;
160 status = NtCreateKey( &subkey, access, attr, 0, class,
161 options & ~REG_OPTION_CREATE_LINK, dispos );
162 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
163 if (status) return status;
164 attr->RootDirectory = subkey;
165 while (i < len && buffer[i] == '\\') i++;
166 pos = i;
167 while (i < len && buffer[i] != '\\') i++;
169 str.Buffer = buffer + pos;
170 str.Length = (i - pos) * sizeof(WCHAR);
171 attr->Attributes = attrs;
172 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, class, options, dispos );
173 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
175 return status;
178 /* wrapper for NtOpenKey to handle Wow6432 nodes */
179 static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
181 NTSTATUS status;
182 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
183 HANDLE subkey, root = attr->RootDirectory;
184 WCHAR *buffer = attr->ObjectName->Buffer;
185 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
186 UNICODE_STRING str;
188 if (!force_wow32) return NtOpenKey( (HANDLE *)retkey, access, attr );
190 if (len && buffer[0] == '\\') return STATUS_OBJECT_PATH_INVALID;
191 while (i < len && buffer[i] != '\\') i++;
192 attrs = attr->Attributes;
193 attr->Attributes &= ~OBJ_OPENLINK;
194 attr->ObjectName = &str;
196 while (i < len)
198 str.Buffer = buffer + pos;
199 str.Length = (i - pos) * sizeof(WCHAR);
200 if (force_wow32 && pos)
202 if (is_wow6432node( &str )) force_wow32 = FALSE;
203 else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
205 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
206 attr->RootDirectory = subkey;
207 force_wow32 = FALSE;
210 status = NtOpenKey( &subkey, access, attr );
211 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
212 if (status) return status;
213 attr->RootDirectory = subkey;
214 while (i < len && buffer[i] == '\\') i++;
215 pos = i;
216 while (i < len && buffer[i] != '\\') i++;
218 str.Buffer = buffer + pos;
219 str.Length = (i - pos) * sizeof(WCHAR);
220 attr->Attributes = attrs;
221 status = NtOpenKey( (PHANDLE)retkey, access, attr );
222 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
223 return status;
227 /* create one of the HKEY_* special root keys */
228 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
230 HKEY ret = 0;
231 int idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
233 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CURRENT_USER))
235 if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
236 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
238 /* don't cache the key in the table if caching is disabled */
239 if (hkcu_cache_disabled)
240 return hkey;
242 else
244 OBJECT_ATTRIBUTES attr;
245 UNICODE_STRING name;
247 attr.Length = sizeof(attr);
248 attr.RootDirectory = 0;
249 attr.ObjectName = &name;
250 attr.Attributes = 0;
251 attr.SecurityDescriptor = NULL;
252 attr.SecurityQualityOfService = NULL;
253 RtlInitUnicodeString( &name, root_key_names[idx] );
254 if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0;
255 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
258 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
259 ret = hkey;
260 else
261 NtClose( hkey ); /* somebody beat us to it */
262 return ret;
265 /* map the hkey from special root to normal key if necessary */
266 static inline HKEY get_special_root_hkey( HKEY hkey )
268 HKEY ret = hkey;
270 if ((HandleToUlong(hkey) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST))
271 && (HandleToUlong(hkey) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
273 if (!(ret = special_root_keys[HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST)]))
274 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED );
276 return ret;
280 /******************************************************************************
281 * RegOverridePredefKey [ADVAPI32.@]
283 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
285 HKEY old_key;
286 int idx;
288 TRACE("(%p %p)\n", hkey, override);
290 if ((HandleToUlong(hkey) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST))
291 || (HandleToUlong(hkey) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST)))
292 return ERROR_INVALID_PARAMETER;
293 idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
295 if (override)
297 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
298 GetCurrentProcess(), (HANDLE *)&override,
299 0, 0, DUPLICATE_SAME_ACCESS );
300 if (status) return RtlNtStatusToDosError( status );
303 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
304 if (old_key) NtClose( old_key );
305 return ERROR_SUCCESS;
309 /******************************************************************************
310 * RegCreateKeyExW [ADVAPI32.@]
312 * See RegCreateKeyExA.
314 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
315 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
316 PHKEY retkey, LPDWORD dispos )
318 OBJECT_ATTRIBUTES attr;
319 UNICODE_STRING nameW, classW;
321 if (reserved) return ERROR_INVALID_PARAMETER;
322 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
324 attr.Length = sizeof(attr);
325 attr.RootDirectory = hkey;
326 attr.ObjectName = &nameW;
327 attr.Attributes = 0;
328 attr.SecurityDescriptor = NULL;
329 attr.SecurityQualityOfService = NULL;
330 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
331 RtlInitUnicodeString( &nameW, name );
332 RtlInitUnicodeString( &classW, class );
334 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
338 /******************************************************************************
339 * RegCreateKeyExA [ADVAPI32.@]
341 * Open a registry key, creating it if it doesn't exist.
343 * PARAMS
344 * hkey [I] Handle of the parent registry key
345 * name [I] Name of the new key to open or create
346 * reserved [I] Reserved, pass 0
347 * class [I] The object type of the new key
348 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
349 * access [I] Access level desired
350 * sa [I] Security attributes for the key
351 * retkey [O] Destination for the resulting handle
352 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
354 * RETURNS
355 * Success: ERROR_SUCCESS.
356 * Failure: A standard Win32 error code. retkey remains untouched.
358 * FIXME
359 * MAXIMUM_ALLOWED in access mask not supported by server
361 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
362 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
363 PHKEY retkey, LPDWORD dispos )
365 OBJECT_ATTRIBUTES attr;
366 UNICODE_STRING classW;
367 ANSI_STRING nameA, classA;
368 NTSTATUS status;
370 if (reserved) return ERROR_INVALID_PARAMETER;
371 if (!is_version_nt())
373 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
374 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
376 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
378 attr.Length = sizeof(attr);
379 attr.RootDirectory = hkey;
380 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
381 attr.Attributes = 0;
382 attr.SecurityDescriptor = NULL;
383 attr.SecurityQualityOfService = NULL;
384 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
385 RtlInitAnsiString( &nameA, name );
386 RtlInitAnsiString( &classA, class );
388 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
389 &nameA, FALSE )))
391 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
393 status = create_key( retkey, access, &attr, &classW, options, dispos );
394 RtlFreeUnicodeString( &classW );
397 return RtlNtStatusToDosError( status );
401 /******************************************************************************
402 * RegCreateKeyW [ADVAPI32.@]
404 * Creates the specified reg key.
406 * PARAMS
407 * hKey [I] Handle to an open key.
408 * lpSubKey [I] Name of a key that will be opened or created.
409 * phkResult [O] Receives a handle to the opened or created key.
411 * RETURNS
412 * Success: ERROR_SUCCESS
413 * Failure: nonzero error code defined in Winerror.h
415 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
417 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
418 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
419 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
420 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
424 /******************************************************************************
425 * RegCreateKeyA [ADVAPI32.@]
427 * See RegCreateKeyW.
429 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
431 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
432 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
437 /******************************************************************************
438 * RegOpenKeyExW [ADVAPI32.@]
440 * See RegOpenKeyExA.
442 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
444 OBJECT_ATTRIBUTES attr;
445 UNICODE_STRING nameW;
447 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
448 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++;
450 if (!retkey) return ERROR_INVALID_PARAMETER;
451 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
453 attr.Length = sizeof(attr);
454 attr.RootDirectory = hkey;
455 attr.ObjectName = &nameW;
456 attr.Attributes = 0;
457 attr.SecurityDescriptor = NULL;
458 attr.SecurityQualityOfService = NULL;
459 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
460 RtlInitUnicodeString( &nameW, name );
461 return RtlNtStatusToDosError( open_key( retkey, access, &attr ) );
465 /******************************************************************************
466 * RegOpenKeyExA [ADVAPI32.@]
468 * Open a registry key.
470 * PARAMS
471 * hkey [I] Handle of open key
472 * name [I] Name of subkey to open
473 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
474 * access [I] Security access mask
475 * retkey [O] Handle to open key
477 * RETURNS
478 * Success: ERROR_SUCCESS
479 * Failure: A standard Win32 error code. retkey is set to 0.
481 * NOTES
482 * Unlike RegCreateKeyExA(), this function will not create the key if it
483 * does not exist.
485 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
487 OBJECT_ATTRIBUTES attr;
488 STRING nameA;
489 NTSTATUS status;
491 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
492 else
494 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
495 if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT) && name && *name == '\\') name++;
498 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
500 attr.Length = sizeof(attr);
501 attr.RootDirectory = hkey;
502 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
503 attr.Attributes = 0;
504 attr.SecurityDescriptor = NULL;
505 attr.SecurityQualityOfService = NULL;
506 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
508 RtlInitAnsiString( &nameA, name );
509 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
510 &nameA, FALSE )))
512 status = open_key( retkey, access, &attr );
514 return RtlNtStatusToDosError( status );
518 /******************************************************************************
519 * RegOpenKeyW [ADVAPI32.@]
521 * See RegOpenKeyA.
523 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
525 if (!retkey)
526 return ERROR_INVALID_PARAMETER;
528 if (!name || !*name)
530 *retkey = hkey;
531 return ERROR_SUCCESS;
533 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
537 /******************************************************************************
538 * RegOpenKeyA [ADVAPI32.@]
540 * Open a registry key.
542 * PARAMS
543 * hkey [I] Handle of parent key to open the new key under
544 * name [I] Name of the key under hkey to open
545 * retkey [O] Destination for the resulting Handle
547 * RETURNS
548 * Success: ERROR_SUCCESS
549 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
551 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
553 if (!retkey)
554 return ERROR_INVALID_PARAMETER;
556 if (!name || !*name)
558 *retkey = hkey;
559 return ERROR_SUCCESS;
561 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
565 /******************************************************************************
566 * RegOpenCurrentUser [ADVAPI32.@]
568 * Get a handle to the HKEY_CURRENT_USER key for the user
569 * the current thread is impersonating.
571 * PARAMS
572 * access [I] Desired access rights to the key
573 * retkey [O] Handle to the opened key
575 * RETURNS
576 * Success: ERROR_SUCCESS
577 * Failure: nonzero error code from Winerror.h
579 * FIXME
580 * This function is supposed to retrieve a handle to the
581 * HKEY_CURRENT_USER for the user the current thread is impersonating.
582 * Since Wine does not currently allow threads to impersonate other users,
583 * this stub should work fine.
585 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
587 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
592 /******************************************************************************
593 * RegEnumKeyExW [ADVAPI32.@]
595 * Enumerate subkeys of the specified open registry key.
597 * PARAMS
598 * hkey [I] Handle to key to enumerate
599 * index [I] Index of subkey to enumerate
600 * name [O] Buffer for subkey name
601 * name_len [O] Size of subkey buffer
602 * reserved [I] Reserved
603 * class [O] Buffer for class string
604 * class_len [O] Size of class buffer
605 * ft [O] Time key last written to
607 * RETURNS
608 * Success: ERROR_SUCCESS
609 * Failure: System error code. If there are no more subkeys available, the
610 * function returns ERROR_NO_MORE_ITEMS.
612 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
613 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
615 NTSTATUS status;
616 char buffer[256], *buf_ptr = buffer;
617 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
618 DWORD total_size;
620 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
621 name_len ? *name_len : 0, reserved, class, class_len, ft );
623 if (reserved) return ERROR_INVALID_PARAMETER;
624 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
626 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
627 buffer, sizeof(buffer), &total_size );
629 while (status == STATUS_BUFFER_OVERFLOW)
631 /* retry with a dynamically allocated buffer */
632 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
633 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
634 return ERROR_NOT_ENOUGH_MEMORY;
635 info = (KEY_NODE_INFORMATION *)buf_ptr;
636 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
637 buf_ptr, total_size, &total_size );
640 if (!status)
642 DWORD len = info->NameLength / sizeof(WCHAR);
643 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
645 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
647 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
648 status = STATUS_BUFFER_OVERFLOW;
649 else
651 *name_len = len;
652 memcpy( name, info->Name, info->NameLength );
653 name[len] = 0;
654 if (class_len)
656 *class_len = cls_len;
657 if (class)
659 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
660 class[cls_len] = 0;
666 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
667 return RtlNtStatusToDosError( status );
671 /******************************************************************************
672 * RegEnumKeyExA [ADVAPI32.@]
674 * See RegEnumKeyExW.
676 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
677 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
679 NTSTATUS status;
680 char buffer[256], *buf_ptr = buffer;
681 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
682 DWORD total_size;
684 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
685 name_len ? *name_len : 0, reserved, class, class_len, ft );
687 if (reserved) return ERROR_INVALID_PARAMETER;
688 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
690 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
691 buffer, sizeof(buffer), &total_size );
693 while (status == STATUS_BUFFER_OVERFLOW)
695 /* retry with a dynamically allocated buffer */
696 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
697 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
698 return ERROR_NOT_ENOUGH_MEMORY;
699 info = (KEY_NODE_INFORMATION *)buf_ptr;
700 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
701 buf_ptr, total_size, &total_size );
704 if (!status)
706 DWORD len, cls_len;
708 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
709 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
710 info->ClassLength );
711 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
713 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
714 status = STATUS_BUFFER_OVERFLOW;
715 else
717 *name_len = len;
718 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
719 name[len] = 0;
720 if (class_len)
722 *class_len = cls_len;
723 if (class)
725 RtlUnicodeToMultiByteN( class, cls_len, NULL,
726 (WCHAR *)(buf_ptr + info->ClassOffset),
727 info->ClassLength );
728 class[cls_len] = 0;
734 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
735 return RtlNtStatusToDosError( status );
739 /******************************************************************************
740 * RegEnumKeyW [ADVAPI32.@]
742 * Enumerates subkeys of the specified open reg key.
744 * PARAMS
745 * hKey [I] Handle to an open key.
746 * dwIndex [I] Index of the subkey of hKey to retrieve.
747 * lpName [O] Name of the subkey.
748 * cchName [I] Size of lpName in TCHARS.
750 * RETURNS
751 * Success: ERROR_SUCCESS
752 * Failure: system error code. If there are no more subkeys available, the
753 * function returns ERROR_NO_MORE_ITEMS.
755 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
757 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
761 /******************************************************************************
762 * RegEnumKeyA [ADVAPI32.@]
764 * See RegEnumKeyW.
766 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
768 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
772 /******************************************************************************
773 * RegQueryInfoKeyW [ADVAPI32.@]
775 * Retrieves information about the specified registry key.
777 * PARAMS
778 * hkey [I] Handle to key to query
779 * class [O] Buffer for class string
780 * class_len [O] Size of class string buffer
781 * reserved [I] Reserved
782 * subkeys [O] Buffer for number of subkeys
783 * max_subkey [O] Buffer for longest subkey name length
784 * max_class [O] Buffer for longest class string length
785 * values [O] Buffer for number of value entries
786 * max_value [O] Buffer for longest value name length
787 * max_data [O] Buffer for longest value data length
788 * security [O] Buffer for security descriptor length
789 * modif [O] Modification time
791 * RETURNS
792 * Success: ERROR_SUCCESS
793 * Failure: system error code.
795 * NOTES
796 * - win95 allows class to be valid and class_len to be NULL
797 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
798 * - both allow class to be NULL and class_len to be NULL
799 * (it's hard to test validity, so test !NULL instead)
801 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
802 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
803 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
804 LPDWORD security, FILETIME *modif )
806 NTSTATUS status;
807 char buffer[256], *buf_ptr = buffer;
808 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
809 DWORD total_size;
811 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
812 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
814 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
815 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
817 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
818 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
820 if (class)
822 /* retry with a dynamically allocated buffer */
823 while (status == STATUS_BUFFER_OVERFLOW)
825 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
826 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
827 return ERROR_NOT_ENOUGH_MEMORY;
828 info = (KEY_FULL_INFORMATION *)buf_ptr;
829 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
832 if (status) goto done;
834 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
836 status = STATUS_BUFFER_OVERFLOW;
838 else
840 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
841 class[info->ClassLength/sizeof(WCHAR)] = 0;
844 else status = STATUS_SUCCESS;
846 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
847 if (subkeys) *subkeys = info->SubKeys;
848 if (max_subkey) *max_subkey = info->MaxNameLen;
849 if (max_class) *max_class = info->MaxClassLen;
850 if (values) *values = info->Values;
851 if (max_value) *max_value = info->MaxValueNameLen;
852 if (max_data) *max_data = info->MaxValueDataLen;
853 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
855 done:
856 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
857 return RtlNtStatusToDosError( status );
861 /******************************************************************************
862 * RegQueryMultipleValuesA [ADVAPI32.@]
864 * Retrieves the type and data for a list of value names associated with a key.
866 * PARAMS
867 * hKey [I] Handle to an open key.
868 * val_list [O] Array of VALENT structures that describes the entries.
869 * num_vals [I] Number of elements in val_list.
870 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
871 * ldwTotsize [I/O] Size of lpValueBuf.
873 * RETURNS
874 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
875 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
876 * bytes.
878 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
879 LPSTR lpValueBuf, LPDWORD ldwTotsize )
881 unsigned int i;
882 DWORD maxBytes = *ldwTotsize;
883 HRESULT status;
884 LPSTR bufptr = lpValueBuf;
885 *ldwTotsize = 0;
887 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
889 for(i=0; i < num_vals; ++i)
892 val_list[i].ve_valuelen=0;
893 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
894 if(status != ERROR_SUCCESS)
896 return status;
899 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
901 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
902 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
903 if(status != ERROR_SUCCESS)
905 return status;
908 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
910 bufptr += val_list[i].ve_valuelen;
913 *ldwTotsize += val_list[i].ve_valuelen;
915 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
919 /******************************************************************************
920 * RegQueryMultipleValuesW [ADVAPI32.@]
922 * See RegQueryMultipleValuesA.
924 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
925 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
927 unsigned int i;
928 DWORD maxBytes = *ldwTotsize;
929 HRESULT status;
930 LPSTR bufptr = (LPSTR)lpValueBuf;
931 *ldwTotsize = 0;
933 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
935 for(i=0; i < num_vals; ++i)
937 val_list[i].ve_valuelen=0;
938 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
939 if(status != ERROR_SUCCESS)
941 return status;
944 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
946 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
947 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
948 if(status != ERROR_SUCCESS)
950 return status;
953 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
955 bufptr += val_list[i].ve_valuelen;
958 *ldwTotsize += val_list[i].ve_valuelen;
960 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
963 /******************************************************************************
964 * RegQueryInfoKeyA [ADVAPI32.@]
966 * Retrieves information about a registry key.
968 * PARAMS
969 * hKey [I] Handle to an open key.
970 * lpClass [O] Class string of the key.
971 * lpcClass [I/O] size of lpClass.
972 * lpReserved [I] Reserved; must be NULL.
973 * lpcSubKeys [O] Number of subkeys contained by the key.
974 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
975 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
976 * class in TCHARS.
977 * lpcValues [O] Number of values associated with the key.
978 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
979 * lpcMaxValueLen [O] Longest data component among the key's values
980 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
981 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
983 * RETURNS
984 * Success: ERROR_SUCCESS
985 * Failure: nonzero error code from Winerror.h
987 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
988 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
989 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
990 LPDWORD security, FILETIME *modif )
992 NTSTATUS status;
993 char buffer[256], *buf_ptr = buffer;
994 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
995 DWORD total_size, len;
997 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
998 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
1000 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
1001 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1003 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
1004 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1006 if (class || class_len)
1008 /* retry with a dynamically allocated buffer */
1009 while (status == STATUS_BUFFER_OVERFLOW)
1011 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1012 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1013 return ERROR_NOT_ENOUGH_MEMORY;
1014 info = (KEY_FULL_INFORMATION *)buf_ptr;
1015 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
1018 if (status) goto done;
1020 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
1021 if (class_len)
1023 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
1024 *class_len = len;
1026 if (class && !status)
1028 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
1029 info->ClassLength );
1030 class[len] = 0;
1033 else status = STATUS_SUCCESS;
1035 if (subkeys) *subkeys = info->SubKeys;
1036 if (max_subkey) *max_subkey = info->MaxNameLen;
1037 if (max_class) *max_class = info->MaxClassLen;
1038 if (values) *values = info->Values;
1039 if (max_value) *max_value = info->MaxValueNameLen;
1040 if (max_data) *max_data = info->MaxValueDataLen;
1041 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
1043 done:
1044 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1045 return RtlNtStatusToDosError( status );
1049 /******************************************************************************
1050 * RegCloseKey [ADVAPI32.@]
1052 * Close an open registry key.
1054 * PARAMS
1055 * hkey [I] Handle of key to close
1057 * RETURNS
1058 * Success: ERROR_SUCCESS
1059 * Failure: Error code
1061 LSTATUS WINAPI RegCloseKey( HKEY hkey )
1063 if (!hkey) return ERROR_INVALID_HANDLE;
1064 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
1065 return RtlNtStatusToDosError( NtClose( hkey ) );
1069 /******************************************************************************
1070 * RegDeleteKeyExW [ADVAPI32.@]
1072 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
1074 DWORD ret;
1075 HKEY tmp;
1077 if (!name) return ERROR_INVALID_PARAMETER;
1079 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1081 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1082 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
1084 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1085 RegCloseKey( tmp );
1087 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
1088 return ret;
1092 /******************************************************************************
1093 * RegDeleteKeyW [ADVAPI32.@]
1095 * See RegDeleteKeyA.
1097 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
1099 return RegDeleteKeyExW( hkey, name, 0, 0 );
1103 /******************************************************************************
1104 * RegDeleteKeyExA [ADVAPI32.@]
1106 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1108 DWORD ret;
1109 HKEY tmp;
1111 if (!name) return ERROR_INVALID_PARAMETER;
1113 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1115 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1116 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1118 if (!is_version_nt()) /* win95 does recursive key deletes */
1120 CHAR sub[MAX_PATH];
1122 while(!RegEnumKeyA(tmp, 0, sub, sizeof(sub)))
1124 if(RegDeleteKeyExA(tmp, sub, access, reserved)) /* recurse */
1125 break;
1128 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1129 RegCloseKey( tmp );
1131 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1132 return ret;
1136 /******************************************************************************
1137 * RegDeleteKeyA [ADVAPI32.@]
1139 * Delete a registry key.
1141 * PARAMS
1142 * hkey [I] Handle to parent key containing the key to delete
1143 * name [I] Name of the key user hkey to delete
1145 * NOTES
1147 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1148 * right. In reality, it opens a new handle with DELETE access.
1150 * RETURNS
1151 * Success: ERROR_SUCCESS
1152 * Failure: Error code
1154 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1156 return RegDeleteKeyExA( hkey, name, 0, 0 );
1161 /******************************************************************************
1162 * RegSetValueExW [ADVAPI32.@]
1164 * Set the data and contents of a registry value.
1166 * PARAMS
1167 * hkey [I] Handle of key to set value for
1168 * name [I] Name of value to set
1169 * reserved [I] Reserved, must be zero
1170 * type [I] Type of the value being set
1171 * data [I] The new contents of the value to set
1172 * count [I] Size of data
1174 * RETURNS
1175 * Success: ERROR_SUCCESS
1176 * Failure: Error code
1178 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1179 DWORD type, CONST BYTE *data, DWORD count )
1181 UNICODE_STRING nameW;
1183 /* no need for version check, not implemented on win9x anyway */
1185 if (data && ((ULONG_PTR)data >> 16) == 0) return ERROR_NOACCESS;
1187 if (count && is_string(type))
1189 LPCWSTR str = (LPCWSTR)data;
1190 /* if user forgot to count terminating null, add it (yes NT does this) */
1191 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1192 count += sizeof(WCHAR);
1194 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1196 RtlInitUnicodeString( &nameW, name );
1197 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1201 /******************************************************************************
1202 * RegSetValueExA [ADVAPI32.@]
1204 * See RegSetValueExW.
1206 * NOTES
1207 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1208 * NT does definitely care (aj)
1210 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1211 CONST BYTE *data, DWORD count )
1213 ANSI_STRING nameA;
1214 UNICODE_STRING nameW;
1215 WCHAR *dataW = NULL;
1216 NTSTATUS status;
1218 if (!is_version_nt()) /* win95 */
1220 if (type == REG_SZ)
1222 if (!data) return ERROR_INVALID_PARAMETER;
1223 count = strlen((const char *)data) + 1;
1226 else if (count && is_string(type))
1228 /* if user forgot to count terminating null, add it (yes NT does this) */
1229 if (data[count-1] && !data[count]) count++;
1232 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1234 if (is_string( type )) /* need to convert to Unicode */
1236 DWORD lenW;
1237 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1238 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1239 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1240 count = lenW;
1241 data = (BYTE *)dataW;
1244 RtlInitAnsiString( &nameA, name );
1245 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1247 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1248 RtlFreeUnicodeString( &nameW );
1250 HeapFree( GetProcessHeap(), 0, dataW );
1251 return RtlNtStatusToDosError( status );
1255 /******************************************************************************
1256 * RegSetValueW [ADVAPI32.@]
1258 * Sets the data for the default or unnamed value of a reg key.
1260 * PARAMS
1261 * hKey [I] Handle to an open key.
1262 * lpSubKey [I] Name of a subkey of hKey.
1263 * dwType [I] Type of information to store.
1264 * lpData [I] String that contains the data to set for the default value.
1265 * cbData [I] Ignored.
1267 * RETURNS
1268 * Success: ERROR_SUCCESS
1269 * Failure: nonzero error code from Winerror.h
1271 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1273 HKEY subkey = hkey;
1274 DWORD ret;
1276 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1278 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1280 if (name && name[0]) /* need to create the subkey */
1282 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1285 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1286 (strlenW( data ) + 1) * sizeof(WCHAR) );
1287 if (subkey != hkey) RegCloseKey( subkey );
1288 return ret;
1292 /******************************************************************************
1293 * RegSetValueA [ADVAPI32.@]
1295 * See RegSetValueW.
1297 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1299 HKEY subkey = hkey;
1300 DWORD ret;
1302 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1304 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1306 if (name && name[0]) /* need to create the subkey */
1308 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1310 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1311 if (subkey != hkey) RegCloseKey( subkey );
1312 return ret;
1317 /******************************************************************************
1318 * RegQueryValueExW [ADVAPI32.@]
1320 * See RegQueryValueExA.
1322 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1323 LPBYTE data, LPDWORD count )
1325 NTSTATUS status;
1326 UNICODE_STRING name_str;
1327 DWORD total_size;
1328 char buffer[256], *buf_ptr = buffer;
1329 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1330 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1332 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1333 hkey, debugstr_w(name), reserved, type, data, count,
1334 (count && data) ? *count : 0 );
1336 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1337 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1339 RtlInitUnicodeString( &name_str, name );
1341 if (data) total_size = min( sizeof(buffer), *count + info_size );
1342 else
1344 total_size = info_size;
1345 if (count) *count = 0;
1348 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1349 buffer, total_size, &total_size );
1350 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1352 if (data)
1354 /* retry with a dynamically allocated buffer */
1355 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1357 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1358 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1359 return ERROR_NOT_ENOUGH_MEMORY;
1360 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1361 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1362 buf_ptr, total_size, &total_size );
1365 if (!status)
1367 memcpy( data, buf_ptr + info_size, total_size - info_size );
1368 /* if the type is REG_SZ and data is not 0-terminated
1369 * and there is enough space in the buffer NT appends a \0 */
1370 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1372 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1373 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1376 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1378 else status = STATUS_SUCCESS;
1380 if (type) *type = info->Type;
1381 if (count) *count = total_size - info_size;
1383 done:
1384 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1385 return RtlNtStatusToDosError(status);
1389 /******************************************************************************
1390 * RegQueryValueExA [ADVAPI32.@]
1392 * Get the type and contents of a specified value under with a key.
1394 * PARAMS
1395 * hkey [I] Handle of the key to query
1396 * name [I] Name of value under hkey to query
1397 * reserved [I] Reserved - must be NULL
1398 * type [O] Destination for the value type, or NULL if not required
1399 * data [O] Destination for the values contents, or NULL if not required
1400 * count [I/O] Size of data, updated with the number of bytes returned
1402 * RETURNS
1403 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1404 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1405 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1406 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1408 * NOTES
1409 * MSDN states that if data is too small it is partially filled. In reality
1410 * it remains untouched.
1412 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1413 LPBYTE data, LPDWORD count )
1415 NTSTATUS status;
1416 ANSI_STRING nameA;
1417 UNICODE_STRING nameW;
1418 DWORD total_size, datalen = 0;
1419 char buffer[256], *buf_ptr = buffer;
1420 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1421 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1423 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1424 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1426 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1427 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1429 if (count) datalen = *count;
1430 if (!data && count) *count = 0;
1432 /* this matches Win9x behaviour - NT sets *type to a random value */
1433 if (type) *type = REG_NONE;
1435 RtlInitAnsiString( &nameA, name );
1436 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1437 return RtlNtStatusToDosError(status);
1439 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1440 buffer, sizeof(buffer), &total_size );
1441 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1443 /* we need to fetch the contents for a string type even if not requested,
1444 * because we need to compute the length of the ASCII string. */
1445 if (data || is_string(info->Type))
1447 /* retry with a dynamically allocated buffer */
1448 while (status == STATUS_BUFFER_OVERFLOW)
1450 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1451 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1453 status = STATUS_NO_MEMORY;
1454 goto done;
1456 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1457 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1458 buf_ptr, total_size, &total_size );
1461 if (status) goto done;
1463 if (is_string(info->Type))
1465 DWORD len;
1467 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1468 total_size - info_size );
1469 if (data && len)
1471 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1472 else
1474 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1475 total_size - info_size );
1476 /* if the type is REG_SZ and data is not 0-terminated
1477 * and there is enough space in the buffer NT appends a \0 */
1478 if (len < datalen && data[len-1]) data[len] = 0;
1481 total_size = len + info_size;
1483 else if (data)
1485 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1486 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1489 else status = STATUS_SUCCESS;
1491 if (type) *type = info->Type;
1492 if (count) *count = total_size - info_size;
1494 done:
1495 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1496 RtlFreeUnicodeString( &nameW );
1497 return RtlNtStatusToDosError(status);
1501 /******************************************************************************
1502 * RegQueryValueW [ADVAPI32.@]
1504 * Retrieves the data associated with the default or unnamed value of a key.
1506 * PARAMS
1507 * hkey [I] Handle to an open key.
1508 * name [I] Name of the subkey of hKey.
1509 * data [O] Receives the string associated with the default value
1510 * of the key.
1511 * count [I/O] Size of lpValue in bytes.
1513 * RETURNS
1514 * Success: ERROR_SUCCESS
1515 * Failure: nonzero error code from Winerror.h
1517 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1519 DWORD ret;
1520 HKEY subkey = hkey;
1522 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1524 if (name && name[0])
1526 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1528 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1529 if (subkey != hkey) RegCloseKey( subkey );
1530 if (ret == ERROR_FILE_NOT_FOUND)
1532 /* return empty string if default value not found */
1533 if (data) *data = 0;
1534 if (count) *count = sizeof(WCHAR);
1535 ret = ERROR_SUCCESS;
1537 return ret;
1541 /******************************************************************************
1542 * RegQueryValueA [ADVAPI32.@]
1544 * See RegQueryValueW.
1546 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1548 DWORD ret;
1549 HKEY subkey = hkey;
1551 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1553 if (name && name[0])
1555 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1557 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1558 if (subkey != hkey) RegCloseKey( subkey );
1559 if (ret == ERROR_FILE_NOT_FOUND)
1561 /* return empty string if default value not found */
1562 if (data) *data = 0;
1563 if (count) *count = 1;
1564 ret = ERROR_SUCCESS;
1566 return ret;
1570 /******************************************************************************
1571 * ADVAPI_ApplyRestrictions [internal]
1573 * Helper function for RegGetValueA/W.
1575 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1576 DWORD cbData, PLONG ret )
1578 /* Check if the type is restricted by the passed flags */
1579 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1581 DWORD dwMask = 0;
1583 switch (dwType)
1585 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1586 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1587 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1588 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1589 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1590 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1591 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1594 if (dwFlags & dwMask)
1596 /* Type is not restricted, check for size mismatch */
1597 if (dwType == REG_BINARY)
1599 DWORD cbExpect = 0;
1601 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1602 cbExpect = 4;
1603 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1604 cbExpect = 8;
1606 if (cbExpect && cbData != cbExpect)
1607 *ret = ERROR_DATATYPE_MISMATCH;
1610 else *ret = ERROR_UNSUPPORTED_TYPE;
1615 /******************************************************************************
1616 * RegGetValueW [ADVAPI32.@]
1618 * Retrieves the type and data for a value name associated with a key,
1619 * optionally expanding its content and restricting its type.
1621 * PARAMS
1622 * hKey [I] Handle to an open key.
1623 * pszSubKey [I] Name of the subkey of hKey.
1624 * pszValue [I] Name of value under hKey/szSubKey to query.
1625 * dwFlags [I] Flags restricting the value type to retrieve.
1626 * pdwType [O] Destination for the values type, may be NULL.
1627 * pvData [O] Destination for the values content, may be NULL.
1628 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1629 * retrieve the whole content, including the trailing '\0'
1630 * for strings.
1632 * RETURNS
1633 * Success: ERROR_SUCCESS
1634 * Failure: nonzero error code from Winerror.h
1636 * NOTES
1637 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1638 * expanded and pdwType is set to REG_SZ instead.
1639 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1640 * without RRF_NOEXPAND is thus not allowed.
1641 * An exception is the case where RRF_RT_ANY is specified, because then
1642 * RRF_NOEXPAND is allowed.
1644 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1645 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1646 LPDWORD pcbData )
1648 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1649 PVOID pvBuf = NULL;
1650 LONG ret;
1652 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1653 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1654 pvData, pcbData, cbData);
1656 if (pvData && !pcbData)
1657 return ERROR_INVALID_PARAMETER;
1658 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1659 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1660 return ERROR_INVALID_PARAMETER;
1662 if (pszSubKey && pszSubKey[0])
1664 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1665 if (ret != ERROR_SUCCESS) return ret;
1668 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1670 /* If we are going to expand we need to read in the whole the value even
1671 * if the passed buffer was too small as the expanded string might be
1672 * smaller than the unexpanded one and could fit into cbData bytes. */
1673 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1674 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1676 do {
1677 HeapFree(GetProcessHeap(), 0, pvBuf);
1679 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1680 if (!pvBuf)
1682 ret = ERROR_NOT_ENOUGH_MEMORY;
1683 break;
1686 if (ret == ERROR_MORE_DATA || !pvData)
1687 ret = RegQueryValueExW(hKey, pszValue, NULL,
1688 &dwType, pvBuf, &cbData);
1689 else
1691 /* Even if cbData was large enough we have to copy the
1692 * string since ExpandEnvironmentStrings can't handle
1693 * overlapping buffers. */
1694 CopyMemory(pvBuf, pvData, cbData);
1697 /* Both the type or the value itself could have been modified in
1698 * between so we have to keep retrying until the buffer is large
1699 * enough or we no longer have to expand the value. */
1700 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1702 if (ret == ERROR_SUCCESS)
1704 /* Recheck dwType in case it changed since the first call */
1705 if (dwType == REG_EXPAND_SZ)
1707 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1708 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1709 dwType = REG_SZ;
1710 if(pvData && pcbData && cbData > *pcbData)
1711 ret = ERROR_MORE_DATA;
1713 else if (pvData)
1714 CopyMemory(pvData, pvBuf, *pcbData);
1717 HeapFree(GetProcessHeap(), 0, pvBuf);
1720 if (pszSubKey && pszSubKey[0])
1721 RegCloseKey(hKey);
1723 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1725 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1726 ZeroMemory(pvData, *pcbData);
1728 if (pdwType) *pdwType = dwType;
1729 if (pcbData) *pcbData = cbData;
1731 return ret;
1735 /******************************************************************************
1736 * RegGetValueA [ADVAPI32.@]
1738 * See RegGetValueW.
1740 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1741 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1742 LPDWORD pcbData )
1744 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1745 PVOID pvBuf = NULL;
1746 LONG ret;
1748 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1749 hKey, debugstr_a(pszSubKey), debugstr_a(pszValue), dwFlags,
1750 pdwType, pvData, pcbData, cbData);
1752 if (pvData && !pcbData)
1753 return ERROR_INVALID_PARAMETER;
1754 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1755 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1756 return ERROR_INVALID_PARAMETER;
1758 if (pszSubKey && pszSubKey[0])
1760 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1761 if (ret != ERROR_SUCCESS) return ret;
1764 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1766 /* If we are going to expand we need to read in the whole the value even
1767 * if the passed buffer was too small as the expanded string might be
1768 * smaller than the unexpanded one and could fit into cbData bytes. */
1769 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1770 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1772 do {
1773 HeapFree(GetProcessHeap(), 0, pvBuf);
1775 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1776 if (!pvBuf)
1778 ret = ERROR_NOT_ENOUGH_MEMORY;
1779 break;
1782 if (ret == ERROR_MORE_DATA || !pvData)
1783 ret = RegQueryValueExA(hKey, pszValue, NULL,
1784 &dwType, pvBuf, &cbData);
1785 else
1787 /* Even if cbData was large enough we have to copy the
1788 * string since ExpandEnvironmentStrings can't handle
1789 * overlapping buffers. */
1790 CopyMemory(pvBuf, pvData, cbData);
1793 /* Both the type or the value itself could have been modified in
1794 * between so we have to keep retrying until the buffer is large
1795 * enough or we no longer have to expand the value. */
1796 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1798 if (ret == ERROR_SUCCESS)
1800 /* Recheck dwType in case it changed since the first call */
1801 if (dwType == REG_EXPAND_SZ)
1803 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1804 pcbData ? *pcbData : 0);
1805 dwType = REG_SZ;
1806 if(pvData && pcbData && cbData > *pcbData)
1807 ret = ERROR_MORE_DATA;
1809 else if (pvData)
1810 CopyMemory(pvData, pvBuf, *pcbData);
1813 HeapFree(GetProcessHeap(), 0, pvBuf);
1816 if (pszSubKey && pszSubKey[0])
1817 RegCloseKey(hKey);
1819 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1821 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1822 ZeroMemory(pvData, *pcbData);
1824 if (pdwType) *pdwType = dwType;
1825 if (pcbData) *pcbData = cbData;
1827 return ret;
1831 /******************************************************************************
1832 * RegEnumValueW [ADVAPI32.@]
1834 * Enumerates the values for the specified open registry key.
1836 * PARAMS
1837 * hkey [I] Handle to key to query
1838 * index [I] Index of value to query
1839 * value [O] Value string
1840 * val_count [I/O] Size of value buffer (in wchars)
1841 * reserved [I] Reserved
1842 * type [O] Type code
1843 * data [O] Value data
1844 * count [I/O] Size of data buffer (in bytes)
1846 * RETURNS
1847 * Success: ERROR_SUCCESS
1848 * Failure: nonzero error code from Winerror.h
1851 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1852 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1854 NTSTATUS status;
1855 DWORD total_size;
1856 char buffer[256], *buf_ptr = buffer;
1857 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1858 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1860 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1861 hkey, index, value, val_count, reserved, type, data, count );
1863 /* NT only checks count, not val_count */
1864 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1865 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1867 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1868 if (data) total_size += *count;
1869 total_size = min( sizeof(buffer), total_size );
1871 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1872 buffer, total_size, &total_size );
1873 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1875 if (value || data)
1877 /* retry with a dynamically allocated buffer */
1878 while (status == STATUS_BUFFER_OVERFLOW)
1880 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1881 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1882 return ERROR_NOT_ENOUGH_MEMORY;
1883 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1884 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1885 buf_ptr, total_size, &total_size );
1888 if (status) goto done;
1890 if (value)
1892 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1894 status = STATUS_BUFFER_OVERFLOW;
1895 goto overflow;
1897 memcpy( value, info->Name, info->NameLength );
1898 *val_count = info->NameLength / sizeof(WCHAR);
1899 value[*val_count] = 0;
1902 if (data)
1904 if (total_size - info->DataOffset > *count)
1906 status = STATUS_BUFFER_OVERFLOW;
1907 goto overflow;
1909 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1910 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1912 /* if the type is REG_SZ and data is not 0-terminated
1913 * and there is enough space in the buffer NT appends a \0 */
1914 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1915 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1919 else status = STATUS_SUCCESS;
1921 overflow:
1922 if (type) *type = info->Type;
1923 if (count) *count = info->DataLength;
1925 done:
1926 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1927 return RtlNtStatusToDosError(status);
1931 /******************************************************************************
1932 * RegEnumValueA [ADVAPI32.@]
1934 * See RegEnumValueW.
1936 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1937 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1939 NTSTATUS status;
1940 DWORD total_size;
1941 char buffer[256], *buf_ptr = buffer;
1942 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1943 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1945 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1946 hkey, index, value, val_count, reserved, type, data, count );
1948 /* NT only checks count, not val_count */
1949 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1950 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1952 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1953 if (data) total_size += *count;
1954 total_size = min( sizeof(buffer), total_size );
1956 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1957 buffer, total_size, &total_size );
1958 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1960 /* we need to fetch the contents for a string type even if not requested,
1961 * because we need to compute the length of the ASCII string. */
1962 if (value || data || is_string(info->Type))
1964 /* retry with a dynamically allocated buffer */
1965 while (status == STATUS_BUFFER_OVERFLOW)
1967 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1968 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1969 return ERROR_NOT_ENOUGH_MEMORY;
1970 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1971 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1972 buf_ptr, total_size, &total_size );
1975 if (status) goto done;
1977 if (is_string(info->Type))
1979 DWORD len;
1980 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1981 total_size - info->DataOffset );
1982 if (data && len)
1984 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1985 else
1987 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1988 total_size - info->DataOffset );
1989 /* if the type is REG_SZ and data is not 0-terminated
1990 * and there is enough space in the buffer NT appends a \0 */
1991 if (len < *count && data[len-1]) data[len] = 0;
1994 info->DataLength = len;
1996 else if (data)
1998 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1999 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2002 if (value && !status)
2004 DWORD len;
2006 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2007 if (len >= *val_count)
2009 status = STATUS_BUFFER_OVERFLOW;
2010 if (*val_count)
2012 len = *val_count - 1;
2013 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2014 value[len] = 0;
2017 else
2019 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2020 value[len] = 0;
2021 *val_count = len;
2025 else status = STATUS_SUCCESS;
2027 if (type) *type = info->Type;
2028 if (count) *count = info->DataLength;
2030 done:
2031 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2032 return RtlNtStatusToDosError(status);
2037 /******************************************************************************
2038 * RegDeleteValueW [ADVAPI32.@]
2040 * See RegDeleteValueA.
2042 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2044 UNICODE_STRING nameW;
2046 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2048 RtlInitUnicodeString( &nameW, name );
2049 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2053 /******************************************************************************
2054 * RegDeleteValueA [ADVAPI32.@]
2056 * Delete a value from the registry.
2058 * PARAMS
2059 * hkey [I] Registry handle of the key holding the value
2060 * name [I] Name of the value under hkey to delete
2062 * RETURNS
2063 * Success: ERROR_SUCCESS
2064 * Failure: nonzero error code from Winerror.h
2066 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2068 ANSI_STRING nameA;
2069 UNICODE_STRING nameW;
2070 NTSTATUS status;
2072 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2074 RtlInitAnsiString( &nameA, name );
2075 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2077 status = NtDeleteValueKey( hkey, &nameW );
2078 RtlFreeUnicodeString( &nameW );
2080 return RtlNtStatusToDosError( status );
2084 /******************************************************************************
2085 * RegLoadKeyW [ADVAPI32.@]
2087 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2088 * registration information from a specified file into that subkey.
2090 * PARAMS
2091 * hkey [I] Handle of open key
2092 * subkey [I] Address of name of subkey
2093 * filename [I] Address of filename for registry information
2095 * RETURNS
2096 * Success: ERROR_SUCCESS
2097 * Failure: nonzero error code from Winerror.h
2099 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2101 OBJECT_ATTRIBUTES destkey, file;
2102 UNICODE_STRING subkeyW, filenameW;
2103 NTSTATUS status;
2105 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
2107 destkey.Length = sizeof(destkey);
2108 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2109 destkey.ObjectName = &subkeyW; /* name of the key */
2110 destkey.Attributes = 0;
2111 destkey.SecurityDescriptor = NULL;
2112 destkey.SecurityQualityOfService = NULL;
2113 RtlInitUnicodeString(&subkeyW, subkey);
2115 file.Length = sizeof(file);
2116 file.RootDirectory = NULL;
2117 file.ObjectName = &filenameW; /* file containing the hive */
2118 file.Attributes = OBJ_CASE_INSENSITIVE;
2119 file.SecurityDescriptor = NULL;
2120 file.SecurityQualityOfService = NULL;
2121 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2123 status = NtLoadKey(&destkey, &file);
2124 RtlFreeUnicodeString(&filenameW);
2125 return RtlNtStatusToDosError( status );
2129 /******************************************************************************
2130 * RegLoadKeyA [ADVAPI32.@]
2132 * See RegLoadKeyW.
2134 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2136 UNICODE_STRING subkeyW, filenameW;
2137 STRING subkeyA, filenameA;
2138 NTSTATUS status;
2139 LONG ret;
2141 RtlInitAnsiString(&subkeyA, subkey);
2142 RtlInitAnsiString(&filenameA, filename);
2144 RtlInitUnicodeString(&subkeyW, NULL);
2145 RtlInitUnicodeString(&filenameW, NULL);
2146 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2147 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2149 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2151 else ret = RtlNtStatusToDosError(status);
2152 RtlFreeUnicodeString(&subkeyW);
2153 RtlFreeUnicodeString(&filenameW);
2154 return ret;
2158 /******************************************************************************
2159 * RegSaveKeyW [ADVAPI32.@]
2161 * Save a key and all of its subkeys and values to a new file in the standard format.
2163 * PARAMS
2164 * hkey [I] Handle of key where save begins
2165 * lpFile [I] Address of filename to save to
2166 * sa [I] Address of security structure
2168 * RETURNS
2169 * Success: ERROR_SUCCESS
2170 * Failure: nonzero error code from Winerror.h
2172 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2174 static const WCHAR format[] =
2175 {'r','e','g','%','0','4','x','.','t','m','p',0};
2176 WCHAR buffer[MAX_PATH];
2177 int count = 0;
2178 LPWSTR nameW;
2179 DWORD ret, err;
2180 HANDLE handle;
2182 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2184 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2185 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2187 err = GetLastError();
2188 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2190 for (;;)
2192 snprintfW( nameW, 16, format, count++ );
2193 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2194 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2195 if (handle != INVALID_HANDLE_VALUE) break;
2196 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2198 /* Something gone haywire ? Please report if this happens abnormally */
2199 if (count >= 100)
2200 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);
2203 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2205 CloseHandle( handle );
2206 if (!ret)
2208 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2210 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2211 debugstr_w(file) );
2212 ret = GetLastError();
2215 if (ret) DeleteFileW( buffer );
2217 done:
2218 SetLastError( err ); /* restore last error code */
2219 return ret;
2223 /******************************************************************************
2224 * RegSaveKeyA [ADVAPI32.@]
2226 * See RegSaveKeyW.
2228 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2230 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2231 NTSTATUS status;
2232 STRING fileA;
2234 RtlInitAnsiString(&fileA, file);
2235 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2236 return RtlNtStatusToDosError( status );
2237 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2241 /******************************************************************************
2242 * RegRestoreKeyW [ADVAPI32.@]
2244 * Read the registry information from a file and copy it over a key.
2246 * PARAMS
2247 * hkey [I] Handle of key where restore begins
2248 * lpFile [I] Address of filename containing saved tree
2249 * dwFlags [I] Optional flags
2251 * RETURNS
2252 * Success: ERROR_SUCCESS
2253 * Failure: nonzero error code from Winerror.h
2255 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2257 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2259 /* It seems to do this check before the hkey check */
2260 if (!lpFile || !*lpFile)
2261 return ERROR_INVALID_PARAMETER;
2263 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2265 /* Check for file existence */
2267 return ERROR_SUCCESS;
2271 /******************************************************************************
2272 * RegRestoreKeyA [ADVAPI32.@]
2274 * See RegRestoreKeyW.
2276 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2278 UNICODE_STRING lpFileW;
2279 LONG ret;
2281 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2282 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2283 RtlFreeUnicodeString( &lpFileW );
2284 return ret;
2288 /******************************************************************************
2289 * RegUnLoadKeyW [ADVAPI32.@]
2291 * Unload a registry key and its subkeys from the registry.
2293 * PARAMS
2294 * hkey [I] Handle of open key
2295 * lpSubKey [I] Address of name of subkey to unload
2297 * RETURNS
2298 * Success: ERROR_SUCCESS
2299 * Failure: nonzero error code from Winerror.h
2301 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2303 DWORD ret;
2304 HKEY shkey;
2305 OBJECT_ATTRIBUTES attr;
2306 UNICODE_STRING subkey;
2308 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2310 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2311 if( ret )
2312 return ERROR_INVALID_PARAMETER;
2314 RtlInitUnicodeString(&subkey, lpSubKey);
2315 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2316 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2318 RegCloseKey(shkey);
2320 return ret;
2324 /******************************************************************************
2325 * RegUnLoadKeyA [ADVAPI32.@]
2327 * See RegUnLoadKeyW.
2329 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2331 UNICODE_STRING lpSubKeyW;
2332 LONG ret;
2334 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2335 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2336 RtlFreeUnicodeString( &lpSubKeyW );
2337 return ret;
2341 /******************************************************************************
2342 * RegReplaceKeyW [ADVAPI32.@]
2344 * Replace the file backing a registry key and all its subkeys with another file.
2346 * PARAMS
2347 * hkey [I] Handle of open key
2348 * lpSubKey [I] Address of name of subkey
2349 * lpNewFile [I] Address of filename for file with new data
2350 * lpOldFile [I] Address of filename for backup file
2352 * RETURNS
2353 * Success: ERROR_SUCCESS
2354 * Failure: nonzero error code from Winerror.h
2356 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2357 LPCWSTR lpOldFile )
2359 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2360 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2361 return ERROR_SUCCESS;
2365 /******************************************************************************
2366 * RegReplaceKeyA [ADVAPI32.@]
2368 * See RegReplaceKeyW.
2370 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2371 LPCSTR lpOldFile )
2373 UNICODE_STRING lpSubKeyW;
2374 UNICODE_STRING lpNewFileW;
2375 UNICODE_STRING lpOldFileW;
2376 LONG ret;
2378 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2379 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2380 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2381 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2382 RtlFreeUnicodeString( &lpOldFileW );
2383 RtlFreeUnicodeString( &lpNewFileW );
2384 RtlFreeUnicodeString( &lpSubKeyW );
2385 return ret;
2389 /******************************************************************************
2390 * RegSetKeySecurity [ADVAPI32.@]
2392 * Set the security of an open registry key.
2394 * PARAMS
2395 * hkey [I] Open handle of key to set
2396 * SecurityInfo [I] Descriptor contents
2397 * pSecurityDesc [I] Address of descriptor for key
2399 * RETURNS
2400 * Success: ERROR_SUCCESS
2401 * Failure: nonzero error code from Winerror.h
2403 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2404 PSECURITY_DESCRIPTOR pSecurityDesc )
2406 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2408 /* It seems to perform this check before the hkey check */
2409 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2410 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2411 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2412 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2413 /* Param OK */
2414 } else
2415 return ERROR_INVALID_PARAMETER;
2417 if (!pSecurityDesc)
2418 return ERROR_INVALID_PARAMETER;
2420 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2422 return ERROR_SUCCESS;
2426 /******************************************************************************
2427 * RegGetKeySecurity [ADVAPI32.@]
2429 * Get a copy of the security descriptor for a given registry key.
2431 * PARAMS
2432 * hkey [I] Open handle of key to set
2433 * SecurityInformation [I] Descriptor contents
2434 * pSecurityDescriptor [O] Address of descriptor for key
2435 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2437 * RETURNS
2438 * Success: ERROR_SUCCESS
2439 * Failure: Error code
2441 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2442 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2443 LPDWORD lpcbSecurityDescriptor )
2445 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2446 *lpcbSecurityDescriptor);
2448 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2450 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2451 SecurityInformation, pSecurityDescriptor,
2452 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2456 /******************************************************************************
2457 * RegFlushKey [ADVAPI32.@]
2459 * Immediately write a registry key to registry.
2461 * PARAMS
2462 * hkey [I] Handle of key to write
2464 * RETURNS
2465 * Success: ERROR_SUCCESS
2466 * Failure: Error code
2468 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2470 hkey = get_special_root_hkey( hkey );
2471 if (!hkey) return ERROR_INVALID_HANDLE;
2473 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2477 /******************************************************************************
2478 * RegConnectRegistryW [ADVAPI32.@]
2480 * Establish a connection to a predefined registry key on another computer.
2482 * PARAMS
2483 * lpMachineName [I] Address of name of remote computer
2484 * hHey [I] Predefined registry handle
2485 * phkResult [I] Address of buffer for remote registry handle
2487 * RETURNS
2488 * Success: ERROR_SUCCESS
2489 * Failure: nonzero error code from Winerror.h
2491 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2492 PHKEY phkResult )
2494 LONG ret;
2496 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName), hKey, phkResult);
2498 if (!lpMachineName || !*lpMachineName) {
2499 /* Use the local machine name */
2500 ret = RegOpenKeyW( hKey, NULL, phkResult );
2502 else {
2503 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2504 DWORD len = sizeof(compName) / sizeof(WCHAR);
2506 /* MSDN says lpMachineName must start with \\ : not so */
2507 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2508 lpMachineName += 2;
2509 if (GetComputerNameW(compName, &len))
2511 if (!strcmpiW(lpMachineName, compName))
2512 ret = RegOpenKeyW(hKey, NULL, phkResult);
2513 else
2515 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2516 ret = ERROR_BAD_NETPATH;
2519 else
2520 ret = GetLastError();
2522 return ret;
2526 /******************************************************************************
2527 * RegConnectRegistryA [ADVAPI32.@]
2529 * See RegConnectRegistryW.
2531 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2533 UNICODE_STRING machineW;
2534 LONG ret;
2536 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2537 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2538 RtlFreeUnicodeString( &machineW );
2539 return ret;
2543 /******************************************************************************
2544 * RegNotifyChangeKeyValue [ADVAPI32.@]
2546 * Notify the caller about changes to the attributes or contents of a registry key.
2548 * PARAMS
2549 * hkey [I] Handle of key to watch
2550 * fWatchSubTree [I] Flag for subkey notification
2551 * fdwNotifyFilter [I] Changes to be reported
2552 * hEvent [I] Handle of signaled event
2553 * fAsync [I] Flag for asynchronous reporting
2555 * RETURNS
2556 * Success: ERROR_SUCCESS
2557 * Failure: nonzero error code from Winerror.h
2559 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2560 DWORD fdwNotifyFilter, HANDLE hEvent,
2561 BOOL fAsync )
2563 NTSTATUS status;
2564 IO_STATUS_BLOCK iosb;
2566 hkey = get_special_root_hkey( hkey );
2567 if (!hkey) return ERROR_INVALID_HANDLE;
2569 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2570 hEvent, fAsync);
2572 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2573 fdwNotifyFilter, fAsync, NULL, 0,
2574 fWatchSubTree);
2576 if (status && status != STATUS_TIMEOUT)
2577 return RtlNtStatusToDosError( status );
2579 return ERROR_SUCCESS;
2582 /******************************************************************************
2583 * RegOpenUserClassesRoot [ADVAPI32.@]
2585 * Open the HKEY_CLASSES_ROOT key for a user.
2587 * PARAMS
2588 * hToken [I] Handle of token representing the user
2589 * dwOptions [I] Reserved, must be 0
2590 * samDesired [I] Desired access rights
2591 * phkResult [O] Destination for the resulting key handle
2593 * RETURNS
2594 * Success: ERROR_SUCCESS
2595 * Failure: nonzero error code from Winerror.h
2597 * NOTES
2598 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2599 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2600 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2602 LSTATUS WINAPI RegOpenUserClassesRoot(
2603 HANDLE hToken,
2604 DWORD dwOptions,
2605 REGSAM samDesired,
2606 PHKEY phkResult
2609 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2611 *phkResult = HKEY_CLASSES_ROOT;
2612 return ERROR_SUCCESS;
2615 /******************************************************************************
2616 * load_string [Internal]
2618 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2619 * avoid importing user32, which is higher level than advapi32. Helper for
2620 * RegLoadMUIString.
2622 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2624 HGLOBAL hMemory;
2625 HRSRC hResource;
2626 WCHAR *pString;
2627 int idxString;
2629 /* Negative values have to be inverted. */
2630 if (HIWORD(resId) == 0xffff)
2631 resId = (UINT)(-((INT)resId));
2633 /* Load the resource into memory and get a pointer to it. */
2634 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2635 if (!hResource) return 0;
2636 hMemory = LoadResource(hModule, hResource);
2637 if (!hMemory) return 0;
2638 pString = LockResource(hMemory);
2640 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2641 idxString = resId & 0xf;
2642 while (idxString--) pString += *pString + 1;
2644 /* If no buffer is given, return length of the string. */
2645 if (!pwszBuffer) return *pString;
2647 /* Else copy over the string, respecting the buffer size. */
2648 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2649 if (cMaxChars >= 0) {
2650 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2651 pwszBuffer[cMaxChars] = '\0';
2654 return cMaxChars;
2657 /******************************************************************************
2658 * RegLoadMUIStringW [ADVAPI32.@]
2660 * Load the localized version of a string resource from some PE, respective
2661 * id and path of which are given in the registry value in the format
2662 * @[path]\dllname,-resourceId
2664 * PARAMS
2665 * hKey [I] Key, of which to load the string value from.
2666 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2667 * pszBuffer [O] Buffer to store the localized string in.
2668 * cbBuffer [I] Size of the destination buffer in bytes.
2669 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2670 * dwFlags [I] None supported yet.
2671 * pszBaseDir [I] Not supported yet.
2673 * RETURNS
2674 * Success: ERROR_SUCCESS,
2675 * Failure: nonzero error code from winerror.h
2677 * NOTES
2678 * This is an API of Windows Vista, which wasn't available at the time this code
2679 * was written. We have to check for the correct behaviour once it's available.
2681 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2682 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2684 DWORD dwValueType, cbData;
2685 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2686 LONG result;
2688 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2689 "dwFlags = %d, pwszBaseDir = %s)\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2690 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2692 /* Parameter sanity checks. */
2693 if (!hKey || !pwszBuffer)
2694 return ERROR_INVALID_PARAMETER;
2696 if (pwszBaseDir && *pwszBaseDir) {
2697 FIXME("BaseDir parameter not yet supported!\n");
2698 return ERROR_INVALID_PARAMETER;
2701 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2702 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2703 if (result != ERROR_SUCCESS) goto cleanup;
2704 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2705 result = ERROR_FILE_NOT_FOUND;
2706 goto cleanup;
2708 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2709 if (!pwszTempBuffer) {
2710 result = ERROR_NOT_ENOUGH_MEMORY;
2711 goto cleanup;
2713 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2714 if (result != ERROR_SUCCESS) goto cleanup;
2716 /* Expand environment variables, if appropriate, or copy the original string over. */
2717 if (dwValueType == REG_EXPAND_SZ) {
2718 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2719 if (!cbData) goto cleanup;
2720 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2721 if (!pwszExpandedBuffer) {
2722 result = ERROR_NOT_ENOUGH_MEMORY;
2723 goto cleanup;
2725 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2726 } else {
2727 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2728 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2731 /* If the value references a resource based string, parse the value and load the string.
2732 * Else just copy over the original value. */
2733 result = ERROR_SUCCESS;
2734 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2735 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2736 } else {
2737 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2738 UINT uiStringId;
2739 HMODULE hModule;
2741 /* Format of the expanded value is 'path_to_dll,-resId' */
2742 if (!pComma || pComma[1] != '-') {
2743 result = ERROR_BADKEY;
2744 goto cleanup;
2747 uiStringId = atoiW(pComma+2);
2748 *pComma = '\0';
2750 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2751 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2752 result = ERROR_BADKEY;
2753 FreeLibrary(hModule);
2756 cleanup:
2757 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2758 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2759 return result;
2762 /******************************************************************************
2763 * RegLoadMUIStringA [ADVAPI32.@]
2765 * See RegLoadMUIStringW
2767 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2768 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2770 UNICODE_STRING valueW, baseDirW;
2771 WCHAR *pwszBuffer;
2772 DWORD cbData = cbBuffer * sizeof(WCHAR);
2773 LONG result;
2775 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2776 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2777 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2778 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2780 result = ERROR_NOT_ENOUGH_MEMORY;
2781 goto cleanup;
2784 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2785 baseDirW.Buffer);
2787 if (result == ERROR_SUCCESS) {
2788 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2789 if (pcbData)
2790 *pcbData = cbData;
2793 cleanup:
2794 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2795 RtlFreeUnicodeString(&baseDirW);
2796 RtlFreeUnicodeString(&valueW);
2798 return result;
2801 /******************************************************************************
2802 * RegDisablePredefinedCache [ADVAPI32.@]
2804 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2806 * PARAMS
2807 * None.
2809 * RETURNS
2810 * Success: ERROR_SUCCESS
2811 * Failure: nonzero error code from Winerror.h
2813 * NOTES
2814 * This is useful for services that use impersonation.
2816 LSTATUS WINAPI RegDisablePredefinedCache(void)
2818 HKEY hkey_current_user;
2819 int idx = HandleToUlong(HKEY_CURRENT_USER) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
2821 /* prevent caching of future requests */
2822 hkcu_cache_disabled = TRUE;
2824 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2826 if (hkey_current_user)
2827 NtClose( hkey_current_user );
2829 return ERROR_SUCCESS;
2832 /******************************************************************************
2833 * RegDeleteTreeW [ADVAPI32.@]
2836 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2838 LONG ret;
2839 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2840 DWORD dwMaxLen, dwSize;
2841 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2842 HKEY hSubKey = hKey;
2844 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2846 if(lpszSubKey)
2848 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2849 if (ret) return ret;
2852 /* Get highest length for keys, values */
2853 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2854 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2855 if (ret) goto cleanup;
2857 dwMaxSubkeyLen++;
2858 dwMaxValueLen++;
2859 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2860 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2862 /* Name too big: alloc a buffer for it */
2863 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2865 ret = ERROR_NOT_ENOUGH_MEMORY;
2866 goto cleanup;
2871 /* Recursively delete all the subkeys */
2872 while (TRUE)
2874 dwSize = dwMaxLen;
2875 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2876 NULL, NULL, NULL)) break;
2878 ret = RegDeleteTreeW(hSubKey, lpszName);
2879 if (ret) goto cleanup;
2882 if (lpszSubKey)
2883 ret = RegDeleteKeyW(hKey, lpszSubKey);
2884 else
2885 while (TRUE)
2887 dwSize = dwMaxLen;
2888 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2889 NULL, NULL, NULL, NULL)) break;
2891 ret = RegDeleteValueW(hKey, lpszName);
2892 if (ret) goto cleanup;
2895 cleanup:
2896 /* Free buffer if allocated */
2897 if (lpszName != szNameBuf)
2898 HeapFree( GetProcessHeap(), 0, lpszName);
2899 if(lpszSubKey)
2900 RegCloseKey(hSubKey);
2901 return ret;
2904 /******************************************************************************
2905 * RegDeleteTreeA [ADVAPI32.@]
2908 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2910 LONG ret;
2911 UNICODE_STRING lpszSubKeyW;
2913 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2914 else lpszSubKeyW.Buffer = NULL;
2915 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2916 RtlFreeUnicodeString( &lpszSubKeyW );
2917 return ret;
2920 /******************************************************************************
2921 * RegDisableReflectionKey [ADVAPI32.@]
2924 LONG WINAPI RegDisableReflectionKey(HKEY base)
2926 FIXME("%p: stub\n", base);
2927 return ERROR_SUCCESS;