advapi32: Add support for the KEY_WOW64_32KEY flag in RegCreateKey on 64-bit.
[wine/multimedia.git] / dlls / advapi32 / registry.c
blobba9d9a77a40a762b984a381e68410bf3d33bb519
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
46 #define NB_SPECIAL_ROOT_KEYS ((UINT_PTR)HKEY_SPECIAL_ROOT_LAST - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST + 1)
48 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
49 static BOOL hkcu_cache_disabled;
51 static const WCHAR name_CLASSES_ROOT[] =
52 {'M','a','c','h','i','n','e','\\',
53 'S','o','f','t','w','a','r','e','\\',
54 'C','l','a','s','s','e','s',0};
55 static const WCHAR name_LOCAL_MACHINE[] =
56 {'M','a','c','h','i','n','e',0};
57 static const WCHAR name_USERS[] =
58 {'U','s','e','r',0};
59 static const WCHAR name_PERFORMANCE_DATA[] =
60 {'P','e','r','f','D','a','t','a',0};
61 static const WCHAR name_CURRENT_CONFIG[] =
62 {'M','a','c','h','i','n','e','\\',
63 'S','y','s','t','e','m','\\',
64 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
65 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
66 'C','u','r','r','e','n','t',0};
67 static const WCHAR name_DYN_DATA[] =
68 {'D','y','n','D','a','t','a',0};
70 static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] =
72 name_CLASSES_ROOT,
73 NULL, /* HKEY_CURRENT_USER is determined dynamically */
74 name_LOCAL_MACHINE,
75 name_USERS,
76 name_PERFORMANCE_DATA,
77 name_CURRENT_CONFIG,
78 name_DYN_DATA
81 static const int is_win64 = (sizeof(void *) > sizeof(int));
83 /* check if value type needs string conversion (Ansi<->Unicode) */
84 static inline int is_string( DWORD type )
86 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
89 /* check if current version is NT or Win95 */
90 static inline int is_version_nt(void)
92 return !(GetVersion() & 0x80000000);
95 static BOOL is_wow6432node( const UNICODE_STRING *name )
97 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e'};
99 return (name->Length == sizeof(wow6432nodeW) &&
100 !memicmpW( name->Buffer, wow6432nodeW, sizeof(wow6432nodeW)/sizeof(WCHAR) ));
103 /* open the Wow6432Node subkey of the specified key */
104 static HANDLE open_wow6432node( HANDLE key, const UNICODE_STRING *name )
106 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
107 OBJECT_ATTRIBUTES attr;
108 UNICODE_STRING nameW;
109 HANDLE ret;
111 attr.Length = sizeof(attr);
112 attr.RootDirectory = key;
113 attr.ObjectName = &nameW;
114 attr.Attributes = 0;
115 attr.SecurityDescriptor = NULL;
116 attr.SecurityQualityOfService = NULL;
117 RtlInitUnicodeString( &nameW, wow6432nodeW );
118 if (NtOpenKey( &ret, MAXIMUM_ALLOWED, &attr )) ret = 0;
119 return ret;
122 /* wrapper for NtCreateKey that creates the key recursively if necessary */
123 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
124 const UNICODE_STRING *class, ULONG options, PULONG dispos )
126 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
127 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
129 if (!force_wow32) status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class, options, dispos );
131 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
133 HANDLE subkey, root = attr->RootDirectory;
134 WCHAR *buffer = attr->ObjectName->Buffer;
135 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
136 UNICODE_STRING str;
138 while (i < len && buffer[i] != '\\') i++;
139 if (i == len && !force_wow32) return status;
141 attrs = attr->Attributes;
142 attr->Attributes &= ~OBJ_OPENLINK;
143 attr->ObjectName = &str;
145 while (i < len)
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 status = NtCreateKey( &subkey, access, attr, 0, class,
160 options & ~REG_OPTION_CREATE_LINK, dispos );
161 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
162 if (status) return status;
163 attr->RootDirectory = subkey;
164 while (i < len && buffer[i] == '\\') i++;
165 pos = i;
166 while (i < len && buffer[i] != '\\') i++;
168 str.Buffer = buffer + pos;
169 str.Length = (i - pos) * sizeof(WCHAR);
170 attr->Attributes = attrs;
171 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, class, options, dispos );
172 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
174 return status;
177 /* create one of the HKEY_* special root keys */
178 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
180 HKEY ret = 0;
181 int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
183 if (hkey == HKEY_CURRENT_USER)
185 if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
186 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
188 /* don't cache the key in the table if caching is disabled */
189 if (hkcu_cache_disabled)
190 return hkey;
192 else
194 OBJECT_ATTRIBUTES attr;
195 UNICODE_STRING name;
197 attr.Length = sizeof(attr);
198 attr.RootDirectory = 0;
199 attr.ObjectName = &name;
200 attr.Attributes = 0;
201 attr.SecurityDescriptor = NULL;
202 attr.SecurityQualityOfService = NULL;
203 RtlInitUnicodeString( &name, root_key_names[idx] );
204 if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0;
205 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
208 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
209 ret = hkey;
210 else
211 NtClose( hkey ); /* somebody beat us to it */
212 return ret;
215 /* map the hkey from special root to normal key if necessary */
216 static inline HKEY get_special_root_hkey( HKEY hkey )
218 HKEY ret = hkey;
220 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
222 if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
223 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED );
225 return ret;
229 /******************************************************************************
230 * RegOverridePredefKey [ADVAPI32.@]
232 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
234 HKEY old_key;
235 int idx;
237 if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST))
238 return ERROR_INVALID_PARAMETER;
239 idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
241 if (override)
243 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
244 GetCurrentProcess(), (HANDLE *)&override,
245 0, 0, DUPLICATE_SAME_ACCESS );
246 if (status) return RtlNtStatusToDosError( status );
249 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
250 if (old_key) NtClose( old_key );
251 return ERROR_SUCCESS;
255 /******************************************************************************
256 * RegCreateKeyExW [ADVAPI32.@]
258 * See RegCreateKeyExA.
260 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
261 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
262 PHKEY retkey, LPDWORD dispos )
264 OBJECT_ATTRIBUTES attr;
265 UNICODE_STRING nameW, classW;
267 if (reserved) return ERROR_INVALID_PARAMETER;
268 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
270 attr.Length = sizeof(attr);
271 attr.RootDirectory = hkey;
272 attr.ObjectName = &nameW;
273 attr.Attributes = 0;
274 attr.SecurityDescriptor = NULL;
275 attr.SecurityQualityOfService = NULL;
276 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
277 RtlInitUnicodeString( &nameW, name );
278 RtlInitUnicodeString( &classW, class );
280 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
284 /******************************************************************************
285 * RegCreateKeyExA [ADVAPI32.@]
287 * Open a registry key, creating it if it doesn't exist.
289 * PARAMS
290 * hkey [I] Handle of the parent registry key
291 * name [I] Name of the new key to open or create
292 * reserved [I] Reserved, pass 0
293 * class [I] The object type of the new key
294 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
295 * access [I] Access level desired
296 * sa [I] Security attributes for the key
297 * retkey [O] Destination for the resulting handle
298 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
300 * RETURNS
301 * Success: ERROR_SUCCESS.
302 * Failure: A standard Win32 error code. retkey remains untouched.
304 * FIXME
305 * MAXIMUM_ALLOWED in access mask not supported by server
307 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
308 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
309 PHKEY retkey, LPDWORD dispos )
311 OBJECT_ATTRIBUTES attr;
312 UNICODE_STRING classW;
313 ANSI_STRING nameA, classA;
314 NTSTATUS status;
316 if (reserved) return ERROR_INVALID_PARAMETER;
317 if (!is_version_nt())
319 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
320 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
322 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
324 attr.Length = sizeof(attr);
325 attr.RootDirectory = hkey;
326 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
327 attr.Attributes = 0;
328 attr.SecurityDescriptor = NULL;
329 attr.SecurityQualityOfService = NULL;
330 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
331 RtlInitAnsiString( &nameA, name );
332 RtlInitAnsiString( &classA, class );
334 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
335 &nameA, FALSE )))
337 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
339 status = create_key( retkey, access, &attr, &classW, options, dispos );
340 RtlFreeUnicodeString( &classW );
343 return RtlNtStatusToDosError( status );
347 /******************************************************************************
348 * RegCreateKeyW [ADVAPI32.@]
350 * Creates the specified reg key.
352 * PARAMS
353 * hKey [I] Handle to an open key.
354 * lpSubKey [I] Name of a key that will be opened or created.
355 * phkResult [O] Receives a handle to the opened or created key.
357 * RETURNS
358 * Success: ERROR_SUCCESS
359 * Failure: nonzero error code defined in Winerror.h
361 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
363 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
364 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
365 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
366 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
370 /******************************************************************************
371 * RegCreateKeyA [ADVAPI32.@]
373 * See RegCreateKeyW.
375 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
377 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
378 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
383 /******************************************************************************
384 * RegOpenKeyExW [ADVAPI32.@]
386 * See RegOpenKeyExA.
388 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
390 OBJECT_ATTRIBUTES attr;
391 UNICODE_STRING nameW;
393 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
394 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
396 if (!retkey) return ERROR_INVALID_PARAMETER;
397 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
399 attr.Length = sizeof(attr);
400 attr.RootDirectory = hkey;
401 attr.ObjectName = &nameW;
402 attr.Attributes = 0;
403 attr.SecurityDescriptor = NULL;
404 attr.SecurityQualityOfService = NULL;
405 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
406 RtlInitUnicodeString( &nameW, name );
407 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE)retkey, access, &attr ) );
411 /******************************************************************************
412 * RegOpenKeyExA [ADVAPI32.@]
414 * Open a registry key.
416 * PARAMS
417 * hkey [I] Handle of open key
418 * name [I] Name of subkey to open
419 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
420 * access [I] Security access mask
421 * retkey [O] Handle to open key
423 * RETURNS
424 * Success: ERROR_SUCCESS
425 * Failure: A standard Win32 error code. retkey is set to 0.
427 * NOTES
428 * Unlike RegCreateKeyExA(), this function will not create the key if it
429 * does not exist.
431 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
433 OBJECT_ATTRIBUTES attr;
434 STRING nameA;
435 NTSTATUS status;
437 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
438 else
440 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
441 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
444 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
446 attr.Length = sizeof(attr);
447 attr.RootDirectory = hkey;
448 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
449 attr.Attributes = 0;
450 attr.SecurityDescriptor = NULL;
451 attr.SecurityQualityOfService = NULL;
452 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
454 RtlInitAnsiString( &nameA, name );
455 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
456 &nameA, FALSE )))
458 status = NtOpenKey( (PHANDLE)retkey, access, &attr );
460 return RtlNtStatusToDosError( status );
464 /******************************************************************************
465 * RegOpenKeyW [ADVAPI32.@]
467 * See RegOpenKeyA.
469 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
471 if (!retkey)
472 return ERROR_INVALID_PARAMETER;
474 if (!name || !*name)
476 *retkey = hkey;
477 return ERROR_SUCCESS;
479 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
483 /******************************************************************************
484 * RegOpenKeyA [ADVAPI32.@]
486 * Open a registry key.
488 * PARAMS
489 * hkey [I] Handle of parent key to open the new key under
490 * name [I] Name of the key under hkey to open
491 * retkey [O] Destination for the resulting Handle
493 * RETURNS
494 * Success: ERROR_SUCCESS
495 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
497 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
499 if (!retkey)
500 return ERROR_INVALID_PARAMETER;
502 if (!name || !*name)
504 *retkey = hkey;
505 return ERROR_SUCCESS;
507 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
511 /******************************************************************************
512 * RegOpenCurrentUser [ADVAPI32.@]
514 * Get a handle to the HKEY_CURRENT_USER key for the user
515 * the current thread is impersonating.
517 * PARAMS
518 * access [I] Desired access rights to the key
519 * retkey [O] Handle to the opened key
521 * RETURNS
522 * Success: ERROR_SUCCESS
523 * Failure: nonzero error code from Winerror.h
525 * FIXME
526 * This function is supposed to retrieve a handle to the
527 * HKEY_CURRENT_USER for the user the current thread is impersonating.
528 * Since Wine does not currently allow threads to impersonate other users,
529 * this stub should work fine.
531 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
533 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
538 /******************************************************************************
539 * RegEnumKeyExW [ADVAPI32.@]
541 * Enumerate subkeys of the specified open registry key.
543 * PARAMS
544 * hkey [I] Handle to key to enumerate
545 * index [I] Index of subkey to enumerate
546 * name [O] Buffer for subkey name
547 * name_len [O] Size of subkey buffer
548 * reserved [I] Reserved
549 * class [O] Buffer for class string
550 * class_len [O] Size of class buffer
551 * ft [O] Time key last written to
553 * RETURNS
554 * Success: ERROR_SUCCESS
555 * Failure: System error code. If there are no more subkeys available, the
556 * function returns ERROR_NO_MORE_ITEMS.
558 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
559 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
561 NTSTATUS status;
562 char buffer[256], *buf_ptr = buffer;
563 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
564 DWORD total_size;
566 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
567 name_len ? *name_len : 0, reserved, class, class_len, ft );
569 if (reserved) return ERROR_INVALID_PARAMETER;
570 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
572 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
573 buffer, sizeof(buffer), &total_size );
575 while (status == STATUS_BUFFER_OVERFLOW)
577 /* retry with a dynamically allocated buffer */
578 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
579 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
580 return ERROR_NOT_ENOUGH_MEMORY;
581 info = (KEY_NODE_INFORMATION *)buf_ptr;
582 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
583 buf_ptr, total_size, &total_size );
586 if (!status)
588 DWORD len = info->NameLength / sizeof(WCHAR);
589 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
591 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
593 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
594 status = STATUS_BUFFER_OVERFLOW;
595 else
597 *name_len = len;
598 memcpy( name, info->Name, info->NameLength );
599 name[len] = 0;
600 if (class_len)
602 *class_len = cls_len;
603 if (class)
605 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
606 class[cls_len] = 0;
612 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
613 return RtlNtStatusToDosError( status );
617 /******************************************************************************
618 * RegEnumKeyExA [ADVAPI32.@]
620 * See RegEnumKeyExW.
622 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
623 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
625 NTSTATUS status;
626 char buffer[256], *buf_ptr = buffer;
627 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
628 DWORD total_size;
630 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
631 name_len ? *name_len : 0, reserved, class, class_len, ft );
633 if (reserved) return ERROR_INVALID_PARAMETER;
634 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
636 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
637 buffer, sizeof(buffer), &total_size );
639 while (status == STATUS_BUFFER_OVERFLOW)
641 /* retry with a dynamically allocated buffer */
642 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
643 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
644 return ERROR_NOT_ENOUGH_MEMORY;
645 info = (KEY_NODE_INFORMATION *)buf_ptr;
646 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
647 buf_ptr, total_size, &total_size );
650 if (!status)
652 DWORD len, cls_len;
654 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
655 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
656 info->ClassLength );
657 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
659 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
660 status = STATUS_BUFFER_OVERFLOW;
661 else
663 *name_len = len;
664 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
665 name[len] = 0;
666 if (class_len)
668 *class_len = cls_len;
669 if (class)
671 RtlUnicodeToMultiByteN( class, cls_len, NULL,
672 (WCHAR *)(buf_ptr + info->ClassOffset),
673 info->ClassLength );
674 class[cls_len] = 0;
680 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
681 return RtlNtStatusToDosError( status );
685 /******************************************************************************
686 * RegEnumKeyW [ADVAPI32.@]
688 * Enumerates subkeys of the specified open reg key.
690 * PARAMS
691 * hKey [I] Handle to an open key.
692 * dwIndex [I] Index of the subkey of hKey to retrieve.
693 * lpName [O] Name of the subkey.
694 * cchName [I] Size of lpName in TCHARS.
696 * RETURNS
697 * Success: ERROR_SUCCESS
698 * Failure: system error code. If there are no more subkeys available, the
699 * function returns ERROR_NO_MORE_ITEMS.
701 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
703 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
707 /******************************************************************************
708 * RegEnumKeyA [ADVAPI32.@]
710 * See RegEnumKeyW.
712 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
714 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
718 /******************************************************************************
719 * RegQueryInfoKeyW [ADVAPI32.@]
721 * Retrieves information about the specified registry key.
723 * PARAMS
724 * hkey [I] Handle to key to query
725 * class [O] Buffer for class string
726 * class_len [O] Size of class string buffer
727 * reserved [I] Reserved
728 * subkeys [O] Buffer for number of subkeys
729 * max_subkey [O] Buffer for longest subkey name length
730 * max_class [O] Buffer for longest class string length
731 * values [O] Buffer for number of value entries
732 * max_value [O] Buffer for longest value name length
733 * max_data [O] Buffer for longest value data length
734 * security [O] Buffer for security descriptor length
735 * modif [O] Modification time
737 * RETURNS
738 * Success: ERROR_SUCCESS
739 * Failure: system error code.
741 * NOTES
742 * - win95 allows class to be valid and class_len to be NULL
743 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
744 * - both allow class to be NULL and class_len to be NULL
745 * (it's hard to test validity, so test !NULL instead)
747 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
748 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
749 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
750 LPDWORD security, FILETIME *modif )
752 NTSTATUS status;
753 char buffer[256], *buf_ptr = buffer;
754 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
755 DWORD total_size;
757 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
758 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
760 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
761 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
763 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
764 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
766 if (class)
768 /* retry with a dynamically allocated buffer */
769 while (status == STATUS_BUFFER_OVERFLOW)
771 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
772 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
773 return ERROR_NOT_ENOUGH_MEMORY;
774 info = (KEY_FULL_INFORMATION *)buf_ptr;
775 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
778 if (status) goto done;
780 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
782 status = STATUS_BUFFER_OVERFLOW;
784 else
786 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
787 class[info->ClassLength/sizeof(WCHAR)] = 0;
790 else status = STATUS_SUCCESS;
792 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
793 if (subkeys) *subkeys = info->SubKeys;
794 if (max_subkey) *max_subkey = info->MaxNameLen;
795 if (max_class) *max_class = info->MaxClassLen;
796 if (values) *values = info->Values;
797 if (max_value) *max_value = info->MaxValueNameLen;
798 if (max_data) *max_data = info->MaxValueDataLen;
799 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
801 done:
802 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
803 return RtlNtStatusToDosError( status );
807 /******************************************************************************
808 * RegQueryMultipleValuesA [ADVAPI32.@]
810 * Retrieves the type and data for a list of value names associated with a key.
812 * PARAMS
813 * hKey [I] Handle to an open key.
814 * val_list [O] Array of VALENT structures that describes the entries.
815 * num_vals [I] Number of elements in val_list.
816 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
817 * ldwTotsize [I/O] Size of lpValueBuf.
819 * RETURNS
820 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
821 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
822 * bytes.
824 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
825 LPSTR lpValueBuf, LPDWORD ldwTotsize )
827 unsigned int i;
828 DWORD maxBytes = *ldwTotsize;
829 HRESULT status;
830 LPSTR bufptr = lpValueBuf;
831 *ldwTotsize = 0;
833 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
835 for(i=0; i < num_vals; ++i)
838 val_list[i].ve_valuelen=0;
839 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
840 if(status != ERROR_SUCCESS)
842 return status;
845 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
847 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
848 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
849 if(status != ERROR_SUCCESS)
851 return status;
854 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
856 bufptr += val_list[i].ve_valuelen;
859 *ldwTotsize += val_list[i].ve_valuelen;
861 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
865 /******************************************************************************
866 * RegQueryMultipleValuesW [ADVAPI32.@]
868 * See RegQueryMultipleValuesA.
870 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
871 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
873 unsigned int i;
874 DWORD maxBytes = *ldwTotsize;
875 HRESULT status;
876 LPSTR bufptr = (LPSTR)lpValueBuf;
877 *ldwTotsize = 0;
879 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
881 for(i=0; i < num_vals; ++i)
883 val_list[i].ve_valuelen=0;
884 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
885 if(status != ERROR_SUCCESS)
887 return status;
890 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
892 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
893 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
894 if(status != ERROR_SUCCESS)
896 return status;
899 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
901 bufptr += val_list[i].ve_valuelen;
904 *ldwTotsize += val_list[i].ve_valuelen;
906 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
909 /******************************************************************************
910 * RegQueryInfoKeyA [ADVAPI32.@]
912 * Retrieves information about a registry key.
914 * PARAMS
915 * hKey [I] Handle to an open key.
916 * lpClass [O] Class string of the key.
917 * lpcClass [I/O] size of lpClass.
918 * lpReserved [I] Reserved; must be NULL.
919 * lpcSubKeys [O] Number of subkeys contained by the key.
920 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
921 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
922 * class in TCHARS.
923 * lpcValues [O] Number of values associated with the key.
924 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
925 * lpcMaxValueLen [O] Longest data component among the key's values
926 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
927 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
929 * RETURNS
930 * Success: ERROR_SUCCESS
931 * Failure: nonzero error code from Winerror.h
933 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
934 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
935 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
936 LPDWORD security, FILETIME *modif )
938 NTSTATUS status;
939 char buffer[256], *buf_ptr = buffer;
940 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
941 DWORD total_size, len;
943 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
944 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
946 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
947 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
949 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
950 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
952 if (class || class_len)
954 /* retry with a dynamically allocated buffer */
955 while (status == STATUS_BUFFER_OVERFLOW)
957 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
958 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
959 return ERROR_NOT_ENOUGH_MEMORY;
960 info = (KEY_FULL_INFORMATION *)buf_ptr;
961 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
964 if (status) goto done;
966 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
967 if (class_len)
969 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
970 *class_len = len;
972 if (class && !status)
974 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
975 info->ClassLength );
976 class[len] = 0;
979 else status = STATUS_SUCCESS;
981 if (subkeys) *subkeys = info->SubKeys;
982 if (max_subkey) *max_subkey = info->MaxNameLen;
983 if (max_class) *max_class = info->MaxClassLen;
984 if (values) *values = info->Values;
985 if (max_value) *max_value = info->MaxValueNameLen;
986 if (max_data) *max_data = info->MaxValueDataLen;
987 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
989 done:
990 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
991 return RtlNtStatusToDosError( status );
995 /******************************************************************************
996 * RegCloseKey [ADVAPI32.@]
998 * Close an open registry key.
1000 * PARAMS
1001 * hkey [I] Handle of key to close
1003 * RETURNS
1004 * Success: ERROR_SUCCESS
1005 * Failure: Error code
1007 LSTATUS WINAPI RegCloseKey( HKEY hkey )
1009 if (!hkey) return ERROR_INVALID_HANDLE;
1010 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
1011 return RtlNtStatusToDosError( NtClose( hkey ) );
1015 /******************************************************************************
1016 * RegDeleteKeyExW [ADVAPI32.@]
1018 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
1020 DWORD ret;
1021 HKEY tmp;
1023 if (!name) return ERROR_INVALID_PARAMETER;
1025 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1027 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1028 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
1030 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1031 RegCloseKey( tmp );
1033 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
1034 return ret;
1038 /******************************************************************************
1039 * RegDeleteKeyW [ADVAPI32.@]
1041 * See RegDeleteKeyA.
1043 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
1045 return RegDeleteKeyExW( hkey, name, 0, 0 );
1049 /******************************************************************************
1050 * RegDeleteKeyExA [ADVAPI32.@]
1052 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1054 DWORD ret;
1055 HKEY tmp;
1057 if (!name) return ERROR_INVALID_PARAMETER;
1059 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1061 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1062 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1064 if (!is_version_nt()) /* win95 does recursive key deletes */
1066 CHAR name[MAX_PATH];
1068 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
1070 if(RegDeleteKeyExA(tmp, name, access, reserved)) /* recurse */
1071 break;
1074 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1075 RegCloseKey( tmp );
1077 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1078 return ret;
1082 /******************************************************************************
1083 * RegDeleteKeyA [ADVAPI32.@]
1085 * Delete a registry key.
1087 * PARAMS
1088 * hkey [I] Handle to parent key containing the key to delete
1089 * name [I] Name of the key user hkey to delete
1091 * NOTES
1093 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1094 * right. In reality, it opens a new handle with DELETE access.
1096 * RETURNS
1097 * Success: ERROR_SUCCESS
1098 * Failure: Error code
1100 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1102 return RegDeleteKeyExA( hkey, name, 0, 0 );
1107 /******************************************************************************
1108 * RegSetValueExW [ADVAPI32.@]
1110 * Set the data and contents of a registry value.
1112 * PARAMS
1113 * hkey [I] Handle of key to set value for
1114 * name [I] Name of value to set
1115 * reserved [I] Reserved, must be zero
1116 * type [I] Type of the value being set
1117 * data [I] The new contents of the value to set
1118 * count [I] Size of data
1120 * RETURNS
1121 * Success: ERROR_SUCCESS
1122 * Failure: Error code
1124 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1125 DWORD type, CONST BYTE *data, DWORD count )
1127 UNICODE_STRING nameW;
1129 /* no need for version check, not implemented on win9x anyway */
1130 if (count && is_string(type))
1132 LPCWSTR str = (LPCWSTR)data;
1133 /* if user forgot to count terminating null, add it (yes NT does this) */
1134 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1135 count += sizeof(WCHAR);
1137 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1139 RtlInitUnicodeString( &nameW, name );
1140 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1144 /******************************************************************************
1145 * RegSetValueExA [ADVAPI32.@]
1147 * See RegSetValueExW.
1149 * NOTES
1150 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1151 * NT does definitely care (aj)
1153 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1154 CONST BYTE *data, DWORD count )
1156 ANSI_STRING nameA;
1157 UNICODE_STRING nameW;
1158 WCHAR *dataW = NULL;
1159 NTSTATUS status;
1161 if (!is_version_nt()) /* win95 */
1163 if (type == REG_SZ)
1165 if (!data) return ERROR_INVALID_PARAMETER;
1166 count = strlen((const char *)data) + 1;
1169 else if (count && is_string(type))
1171 /* if user forgot to count terminating null, add it (yes NT does this) */
1172 if (data[count-1] && !data[count]) count++;
1175 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1177 if (is_string( type )) /* need to convert to Unicode */
1179 DWORD lenW;
1180 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1181 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1182 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1183 count = lenW;
1184 data = (BYTE *)dataW;
1187 RtlInitAnsiString( &nameA, name );
1188 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1190 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1191 RtlFreeUnicodeString( &nameW );
1193 HeapFree( GetProcessHeap(), 0, dataW );
1194 return RtlNtStatusToDosError( status );
1198 /******************************************************************************
1199 * RegSetValueW [ADVAPI32.@]
1201 * Sets the data for the default or unnamed value of a reg key.
1203 * PARAMS
1204 * hKey [I] Handle to an open key.
1205 * lpSubKey [I] Name of a subkey of hKey.
1206 * dwType [I] Type of information to store.
1207 * lpData [I] String that contains the data to set for the default value.
1208 * cbData [I] Ignored.
1210 * RETURNS
1211 * Success: ERROR_SUCCESS
1212 * Failure: nonzero error code from Winerror.h
1214 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1216 HKEY subkey = hkey;
1217 DWORD ret;
1219 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1221 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1223 if (name && name[0]) /* need to create the subkey */
1225 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1228 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1229 (strlenW( data ) + 1) * sizeof(WCHAR) );
1230 if (subkey != hkey) RegCloseKey( subkey );
1231 return ret;
1235 /******************************************************************************
1236 * RegSetValueA [ADVAPI32.@]
1238 * See RegSetValueW.
1240 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1242 HKEY subkey = hkey;
1243 DWORD ret;
1245 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1247 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1249 if (name && name[0]) /* need to create the subkey */
1251 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1253 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1254 if (subkey != hkey) RegCloseKey( subkey );
1255 return ret;
1260 /******************************************************************************
1261 * RegQueryValueExW [ADVAPI32.@]
1263 * See RegQueryValueExA.
1265 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1266 LPBYTE data, LPDWORD count )
1268 NTSTATUS status;
1269 UNICODE_STRING name_str;
1270 DWORD total_size;
1271 char buffer[256], *buf_ptr = buffer;
1272 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1273 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1275 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1276 hkey, debugstr_w(name), reserved, type, data, count,
1277 (count && data) ? *count : 0 );
1279 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1280 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1282 RtlInitUnicodeString( &name_str, name );
1284 if (data) total_size = min( sizeof(buffer), *count + info_size );
1285 else
1287 total_size = info_size;
1288 if (count) *count = 0;
1291 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1292 buffer, total_size, &total_size );
1293 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1295 if (data)
1297 /* retry with a dynamically allocated buffer */
1298 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1300 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1301 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1302 return ERROR_NOT_ENOUGH_MEMORY;
1303 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1304 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1305 buf_ptr, total_size, &total_size );
1308 if (!status)
1310 memcpy( data, buf_ptr + info_size, total_size - info_size );
1311 /* if the type is REG_SZ and data is not 0-terminated
1312 * and there is enough space in the buffer NT appends a \0 */
1313 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1315 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1316 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1319 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1321 else status = STATUS_SUCCESS;
1323 if (type) *type = info->Type;
1324 if (count) *count = total_size - info_size;
1326 done:
1327 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1328 return RtlNtStatusToDosError(status);
1332 /******************************************************************************
1333 * RegQueryValueExA [ADVAPI32.@]
1335 * Get the type and contents of a specified value under with a key.
1337 * PARAMS
1338 * hkey [I] Handle of the key to query
1339 * name [I] Name of value under hkey to query
1340 * reserved [I] Reserved - must be NULL
1341 * type [O] Destination for the value type, or NULL if not required
1342 * data [O] Destination for the values contents, or NULL if not required
1343 * count [I/O] Size of data, updated with the number of bytes returned
1345 * RETURNS
1346 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1347 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1348 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1349 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1351 * NOTES
1352 * MSDN states that if data is too small it is partially filled. In reality
1353 * it remains untouched.
1355 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1356 LPBYTE data, LPDWORD count )
1358 NTSTATUS status;
1359 ANSI_STRING nameA;
1360 UNICODE_STRING nameW;
1361 DWORD total_size, datalen = 0;
1362 char buffer[256], *buf_ptr = buffer;
1363 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1364 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1366 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1367 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1369 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1370 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1372 if (count) datalen = *count;
1373 if (!data && count) *count = 0;
1375 /* this matches Win9x behaviour - NT sets *type to a random value */
1376 if (type) *type = REG_NONE;
1378 RtlInitAnsiString( &nameA, name );
1379 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1380 return RtlNtStatusToDosError(status);
1382 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1383 buffer, sizeof(buffer), &total_size );
1384 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1386 /* we need to fetch the contents for a string type even if not requested,
1387 * because we need to compute the length of the ASCII string. */
1388 if (data || is_string(info->Type))
1390 /* retry with a dynamically allocated buffer */
1391 while (status == STATUS_BUFFER_OVERFLOW)
1393 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1394 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1396 status = STATUS_NO_MEMORY;
1397 goto done;
1399 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1400 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1401 buf_ptr, total_size, &total_size );
1404 if (status) goto done;
1406 if (is_string(info->Type))
1408 DWORD len;
1410 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1411 total_size - info_size );
1412 if (data && len)
1414 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1415 else
1417 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1418 total_size - info_size );
1419 /* if the type is REG_SZ and data is not 0-terminated
1420 * and there is enough space in the buffer NT appends a \0 */
1421 if (len < datalen && data[len-1]) data[len] = 0;
1424 total_size = len + info_size;
1426 else if (data)
1428 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1429 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1432 else status = STATUS_SUCCESS;
1434 if (type) *type = info->Type;
1435 if (count) *count = total_size - info_size;
1437 done:
1438 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1439 RtlFreeUnicodeString( &nameW );
1440 return RtlNtStatusToDosError(status);
1444 /******************************************************************************
1445 * RegQueryValueW [ADVAPI32.@]
1447 * Retrieves the data associated with the default or unnamed value of a key.
1449 * PARAMS
1450 * hkey [I] Handle to an open key.
1451 * name [I] Name of the subkey of hKey.
1452 * data [O] Receives the string associated with the default value
1453 * of the key.
1454 * count [I/O] Size of lpValue in bytes.
1456 * RETURNS
1457 * Success: ERROR_SUCCESS
1458 * Failure: nonzero error code from Winerror.h
1460 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1462 DWORD ret;
1463 HKEY subkey = hkey;
1465 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1467 if (name && name[0])
1469 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1471 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1472 if (subkey != hkey) RegCloseKey( subkey );
1473 if (ret == ERROR_FILE_NOT_FOUND)
1475 /* return empty string if default value not found */
1476 if (data) *data = 0;
1477 if (count) *count = sizeof(WCHAR);
1478 ret = ERROR_SUCCESS;
1480 return ret;
1484 /******************************************************************************
1485 * RegQueryValueA [ADVAPI32.@]
1487 * See RegQueryValueW.
1489 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1491 DWORD ret;
1492 HKEY subkey = hkey;
1494 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1496 if (name && name[0])
1498 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1500 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1501 if (subkey != hkey) RegCloseKey( subkey );
1502 if (ret == ERROR_FILE_NOT_FOUND)
1504 /* return empty string if default value not found */
1505 if (data) *data = 0;
1506 if (count) *count = 1;
1507 ret = ERROR_SUCCESS;
1509 return ret;
1513 /******************************************************************************
1514 * ADVAPI_ApplyRestrictions [internal]
1516 * Helper function for RegGetValueA/W.
1518 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1519 DWORD cbData, PLONG ret )
1521 /* Check if the type is restricted by the passed flags */
1522 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1524 DWORD dwMask = 0;
1526 switch (dwType)
1528 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1529 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1530 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1531 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1532 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1533 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1534 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1537 if (dwFlags & dwMask)
1539 /* Type is not restricted, check for size mismatch */
1540 if (dwType == REG_BINARY)
1542 DWORD cbExpect = 0;
1544 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1545 cbExpect = 4;
1546 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1547 cbExpect = 8;
1549 if (cbExpect && cbData != cbExpect)
1550 *ret = ERROR_DATATYPE_MISMATCH;
1553 else *ret = ERROR_UNSUPPORTED_TYPE;
1558 /******************************************************************************
1559 * RegGetValueW [ADVAPI32.@]
1561 * Retrieves the type and data for a value name associated with a key,
1562 * optionally expanding its content and restricting its type.
1564 * PARAMS
1565 * hKey [I] Handle to an open key.
1566 * pszSubKey [I] Name of the subkey of hKey.
1567 * pszValue [I] Name of value under hKey/szSubKey to query.
1568 * dwFlags [I] Flags restricting the value type to retrieve.
1569 * pdwType [O] Destination for the values type, may be NULL.
1570 * pvData [O] Destination for the values content, may be NULL.
1571 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1572 * retrieve the whole content, including the trailing '\0'
1573 * for strings.
1575 * RETURNS
1576 * Success: ERROR_SUCCESS
1577 * Failure: nonzero error code from Winerror.h
1579 * NOTES
1580 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1581 * expanded and pdwType is set to REG_SZ instead.
1582 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1583 * without RRF_NOEXPAND is thus not allowed.
1584 * An exception is the case where RRF_RT_ANY is specified, because then
1585 * RRF_NOEXPAND is allowed.
1587 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1588 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1589 LPDWORD pcbData )
1591 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1592 PVOID pvBuf = NULL;
1593 LONG ret;
1595 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1596 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1597 pvData, pcbData, cbData);
1599 if (pvData && !pcbData)
1600 return ERROR_INVALID_PARAMETER;
1601 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1602 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1603 return ERROR_INVALID_PARAMETER;
1605 if (pszSubKey && pszSubKey[0])
1607 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1608 if (ret != ERROR_SUCCESS) return ret;
1611 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1613 /* If we are going to expand we need to read in the whole the value even
1614 * if the passed buffer was too small as the expanded string might be
1615 * smaller than the unexpanded one and could fit into cbData bytes. */
1616 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1617 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1619 do {
1620 HeapFree(GetProcessHeap(), 0, pvBuf);
1622 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1623 if (!pvBuf)
1625 ret = ERROR_NOT_ENOUGH_MEMORY;
1626 break;
1629 if (ret == ERROR_MORE_DATA || !pvData)
1630 ret = RegQueryValueExW(hKey, pszValue, NULL,
1631 &dwType, pvBuf, &cbData);
1632 else
1634 /* Even if cbData was large enough we have to copy the
1635 * string since ExpandEnvironmentStrings can't handle
1636 * overlapping buffers. */
1637 CopyMemory(pvBuf, pvData, cbData);
1640 /* Both the type or the value itself could have been modified in
1641 * between so we have to keep retrying until the buffer is large
1642 * enough or we no longer have to expand the value. */
1643 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1645 if (ret == ERROR_SUCCESS)
1647 /* Recheck dwType in case it changed since the first call */
1648 if (dwType == REG_EXPAND_SZ)
1650 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1651 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1652 dwType = REG_SZ;
1653 if(pvData && pcbData && cbData > *pcbData)
1654 ret = ERROR_MORE_DATA;
1656 else if (pvData)
1657 CopyMemory(pvData, pvBuf, *pcbData);
1660 HeapFree(GetProcessHeap(), 0, pvBuf);
1663 if (pszSubKey && pszSubKey[0])
1664 RegCloseKey(hKey);
1666 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1668 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1669 ZeroMemory(pvData, *pcbData);
1671 if (pdwType) *pdwType = dwType;
1672 if (pcbData) *pcbData = cbData;
1674 return ret;
1678 /******************************************************************************
1679 * RegGetValueA [ADVAPI32.@]
1681 * See RegGetValueW.
1683 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1684 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1685 LPDWORD pcbData )
1687 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1688 PVOID pvBuf = NULL;
1689 LONG ret;
1691 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1692 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1693 cbData);
1695 if (pvData && !pcbData)
1696 return ERROR_INVALID_PARAMETER;
1697 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1698 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1699 return ERROR_INVALID_PARAMETER;
1701 if (pszSubKey && pszSubKey[0])
1703 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1704 if (ret != ERROR_SUCCESS) return ret;
1707 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1709 /* If we are going to expand we need to read in the whole the value even
1710 * if the passed buffer was too small as the expanded string might be
1711 * smaller than the unexpanded one and could fit into cbData bytes. */
1712 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1713 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1715 do {
1716 HeapFree(GetProcessHeap(), 0, pvBuf);
1718 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1719 if (!pvBuf)
1721 ret = ERROR_NOT_ENOUGH_MEMORY;
1722 break;
1725 if (ret == ERROR_MORE_DATA || !pvData)
1726 ret = RegQueryValueExA(hKey, pszValue, NULL,
1727 &dwType, pvBuf, &cbData);
1728 else
1730 /* Even if cbData was large enough we have to copy the
1731 * string since ExpandEnvironmentStrings can't handle
1732 * overlapping buffers. */
1733 CopyMemory(pvBuf, pvData, cbData);
1736 /* Both the type or the value itself could have been modified in
1737 * between so we have to keep retrying until the buffer is large
1738 * enough or we no longer have to expand the value. */
1739 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1741 if (ret == ERROR_SUCCESS)
1743 /* Recheck dwType in case it changed since the first call */
1744 if (dwType == REG_EXPAND_SZ)
1746 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1747 pcbData ? *pcbData : 0);
1748 dwType = REG_SZ;
1749 if(pvData && pcbData && cbData > *pcbData)
1750 ret = ERROR_MORE_DATA;
1752 else if (pvData)
1753 CopyMemory(pvData, pvBuf, *pcbData);
1756 HeapFree(GetProcessHeap(), 0, pvBuf);
1759 if (pszSubKey && pszSubKey[0])
1760 RegCloseKey(hKey);
1762 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1764 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1765 ZeroMemory(pvData, *pcbData);
1767 if (pdwType) *pdwType = dwType;
1768 if (pcbData) *pcbData = cbData;
1770 return ret;
1774 /******************************************************************************
1775 * RegEnumValueW [ADVAPI32.@]
1777 * Enumerates the values for the specified open registry key.
1779 * PARAMS
1780 * hkey [I] Handle to key to query
1781 * index [I] Index of value to query
1782 * value [O] Value string
1783 * val_count [I/O] Size of value buffer (in wchars)
1784 * reserved [I] Reserved
1785 * type [O] Type code
1786 * data [O] Value data
1787 * count [I/O] Size of data buffer (in bytes)
1789 * RETURNS
1790 * Success: ERROR_SUCCESS
1791 * Failure: nonzero error code from Winerror.h
1794 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1795 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1797 NTSTATUS status;
1798 DWORD total_size;
1799 char buffer[256], *buf_ptr = buffer;
1800 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1801 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1803 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1804 hkey, index, value, val_count, reserved, type, data, count );
1806 /* NT only checks count, not val_count */
1807 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1808 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1810 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1811 if (data) total_size += *count;
1812 total_size = min( sizeof(buffer), total_size );
1814 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1815 buffer, total_size, &total_size );
1816 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1818 if (value || data)
1820 /* retry with a dynamically allocated buffer */
1821 while (status == STATUS_BUFFER_OVERFLOW)
1823 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1824 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1825 return ERROR_NOT_ENOUGH_MEMORY;
1826 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1827 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1828 buf_ptr, total_size, &total_size );
1831 if (status) goto done;
1833 if (value)
1835 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1837 status = STATUS_BUFFER_OVERFLOW;
1838 goto overflow;
1840 memcpy( value, info->Name, info->NameLength );
1841 *val_count = info->NameLength / sizeof(WCHAR);
1842 value[*val_count] = 0;
1845 if (data)
1847 if (total_size - info->DataOffset > *count)
1849 status = STATUS_BUFFER_OVERFLOW;
1850 goto overflow;
1852 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1853 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1855 /* if the type is REG_SZ and data is not 0-terminated
1856 * and there is enough space in the buffer NT appends a \0 */
1857 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1858 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1862 else status = STATUS_SUCCESS;
1864 overflow:
1865 if (type) *type = info->Type;
1866 if (count) *count = info->DataLength;
1868 done:
1869 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1870 return RtlNtStatusToDosError(status);
1874 /******************************************************************************
1875 * RegEnumValueA [ADVAPI32.@]
1877 * See RegEnumValueW.
1879 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1880 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1882 NTSTATUS status;
1883 DWORD total_size;
1884 char buffer[256], *buf_ptr = buffer;
1885 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1886 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1888 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1889 hkey, index, value, val_count, reserved, type, data, count );
1891 /* NT only checks count, not val_count */
1892 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1893 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1895 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1896 if (data) total_size += *count;
1897 total_size = min( sizeof(buffer), total_size );
1899 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1900 buffer, total_size, &total_size );
1901 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1903 /* we need to fetch the contents for a string type even if not requested,
1904 * because we need to compute the length of the ASCII string. */
1905 if (value || data || is_string(info->Type))
1907 /* retry with a dynamically allocated buffer */
1908 while (status == STATUS_BUFFER_OVERFLOW)
1910 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1911 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1912 return ERROR_NOT_ENOUGH_MEMORY;
1913 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1914 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1915 buf_ptr, total_size, &total_size );
1918 if (status) goto done;
1920 if (is_string(info->Type))
1922 DWORD len;
1923 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1924 total_size - info->DataOffset );
1925 if (data && len)
1927 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1928 else
1930 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1931 total_size - info->DataOffset );
1932 /* if the type is REG_SZ and data is not 0-terminated
1933 * and there is enough space in the buffer NT appends a \0 */
1934 if (len < *count && data[len-1]) data[len] = 0;
1937 info->DataLength = len;
1939 else if (data)
1941 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1942 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1945 if (value && !status)
1947 DWORD len;
1949 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1950 if (len >= *val_count)
1952 status = STATUS_BUFFER_OVERFLOW;
1953 if (*val_count)
1955 len = *val_count - 1;
1956 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1957 value[len] = 0;
1960 else
1962 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1963 value[len] = 0;
1964 *val_count = len;
1968 else status = STATUS_SUCCESS;
1970 if (type) *type = info->Type;
1971 if (count) *count = info->DataLength;
1973 done:
1974 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1975 return RtlNtStatusToDosError(status);
1980 /******************************************************************************
1981 * RegDeleteValueW [ADVAPI32.@]
1983 * See RegDeleteValueA.
1985 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1987 UNICODE_STRING nameW;
1989 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1991 RtlInitUnicodeString( &nameW, name );
1992 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1996 /******************************************************************************
1997 * RegDeleteValueA [ADVAPI32.@]
1999 * Delete a value from the registry.
2001 * PARAMS
2002 * hkey [I] Registry handle of the key holding the value
2003 * name [I] Name of the value under hkey to delete
2005 * RETURNS
2006 * Success: ERROR_SUCCESS
2007 * Failure: nonzero error code from Winerror.h
2009 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2011 ANSI_STRING nameA;
2012 UNICODE_STRING nameW;
2013 NTSTATUS status;
2015 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2017 RtlInitAnsiString( &nameA, name );
2018 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2020 status = NtDeleteValueKey( hkey, &nameW );
2021 RtlFreeUnicodeString( &nameW );
2023 return RtlNtStatusToDosError( status );
2027 /******************************************************************************
2028 * RegLoadKeyW [ADVAPI32.@]
2030 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2031 * registration information from a specified file into that subkey.
2033 * PARAMS
2034 * hkey [I] Handle of open key
2035 * subkey [I] Address of name of subkey
2036 * filename [I] Address of filename for registry information
2038 * RETURNS
2039 * Success: ERROR_SUCCESS
2040 * Failure: nonzero error code from Winerror.h
2042 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2044 OBJECT_ATTRIBUTES destkey, file;
2045 UNICODE_STRING subkeyW, filenameW;
2046 NTSTATUS status;
2048 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
2050 destkey.Length = sizeof(destkey);
2051 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2052 destkey.ObjectName = &subkeyW; /* name of the key */
2053 destkey.Attributes = 0;
2054 destkey.SecurityDescriptor = NULL;
2055 destkey.SecurityQualityOfService = NULL;
2056 RtlInitUnicodeString(&subkeyW, subkey);
2058 file.Length = sizeof(file);
2059 file.RootDirectory = NULL;
2060 file.ObjectName = &filenameW; /* file containing the hive */
2061 file.Attributes = OBJ_CASE_INSENSITIVE;
2062 file.SecurityDescriptor = NULL;
2063 file.SecurityQualityOfService = NULL;
2064 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2066 status = NtLoadKey(&destkey, &file);
2067 RtlFreeUnicodeString(&filenameW);
2068 return RtlNtStatusToDosError( status );
2072 /******************************************************************************
2073 * RegLoadKeyA [ADVAPI32.@]
2075 * See RegLoadKeyW.
2077 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2079 UNICODE_STRING subkeyW, filenameW;
2080 STRING subkeyA, filenameA;
2081 NTSTATUS status;
2082 LONG ret;
2084 RtlInitAnsiString(&subkeyA, subkey);
2085 RtlInitAnsiString(&filenameA, filename);
2087 RtlInitUnicodeString(&subkeyW, NULL);
2088 RtlInitUnicodeString(&filenameW, NULL);
2089 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2090 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2092 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2094 else ret = RtlNtStatusToDosError(status);
2095 RtlFreeUnicodeString(&subkeyW);
2096 RtlFreeUnicodeString(&filenameW);
2097 return ret;
2101 /******************************************************************************
2102 * RegSaveKeyW [ADVAPI32.@]
2104 * Save a key and all of its subkeys and values to a new file in the standard format.
2106 * PARAMS
2107 * hkey [I] Handle of key where save begins
2108 * lpFile [I] Address of filename to save to
2109 * sa [I] Address of security structure
2111 * RETURNS
2112 * Success: ERROR_SUCCESS
2113 * Failure: nonzero error code from Winerror.h
2115 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2117 static const WCHAR format[] =
2118 {'r','e','g','%','0','4','x','.','t','m','p',0};
2119 WCHAR buffer[MAX_PATH];
2120 int count = 0;
2121 LPWSTR nameW;
2122 DWORD ret, err;
2123 HANDLE handle;
2125 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2127 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2128 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2130 err = GetLastError();
2131 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2133 for (;;)
2135 snprintfW( nameW, 16, format, count++ );
2136 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2137 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2138 if (handle != INVALID_HANDLE_VALUE) break;
2139 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2141 /* Something gone haywire ? Please report if this happens abnormally */
2142 if (count >= 100)
2143 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);
2146 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2148 CloseHandle( handle );
2149 if (!ret)
2151 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2153 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2154 debugstr_w(file) );
2155 ret = GetLastError();
2158 if (ret) DeleteFileW( buffer );
2160 done:
2161 SetLastError( err ); /* restore last error code */
2162 return ret;
2166 /******************************************************************************
2167 * RegSaveKeyA [ADVAPI32.@]
2169 * See RegSaveKeyW.
2171 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2173 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2174 NTSTATUS status;
2175 STRING fileA;
2177 RtlInitAnsiString(&fileA, file);
2178 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2179 return RtlNtStatusToDosError( status );
2180 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2184 /******************************************************************************
2185 * RegRestoreKeyW [ADVAPI32.@]
2187 * Read the registry information from a file and copy it over a key.
2189 * PARAMS
2190 * hkey [I] Handle of key where restore begins
2191 * lpFile [I] Address of filename containing saved tree
2192 * dwFlags [I] Optional flags
2194 * RETURNS
2195 * Success: ERROR_SUCCESS
2196 * Failure: nonzero error code from Winerror.h
2198 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2200 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2202 /* It seems to do this check before the hkey check */
2203 if (!lpFile || !*lpFile)
2204 return ERROR_INVALID_PARAMETER;
2206 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2208 /* Check for file existence */
2210 return ERROR_SUCCESS;
2214 /******************************************************************************
2215 * RegRestoreKeyA [ADVAPI32.@]
2217 * See RegRestoreKeyW.
2219 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2221 UNICODE_STRING lpFileW;
2222 LONG ret;
2224 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2225 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2226 RtlFreeUnicodeString( &lpFileW );
2227 return ret;
2231 /******************************************************************************
2232 * RegUnLoadKeyW [ADVAPI32.@]
2234 * Unload a registry key and its subkeys from the registry.
2236 * PARAMS
2237 * hkey [I] Handle of open key
2238 * lpSubKey [I] Address of name of subkey to unload
2240 * RETURNS
2241 * Success: ERROR_SUCCESS
2242 * Failure: nonzero error code from Winerror.h
2244 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2246 DWORD ret;
2247 HKEY shkey;
2248 OBJECT_ATTRIBUTES attr;
2249 UNICODE_STRING subkey;
2251 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2253 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2254 if( ret )
2255 return ERROR_INVALID_PARAMETER;
2257 RtlInitUnicodeString(&subkey, lpSubKey);
2258 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2259 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2261 RegCloseKey(shkey);
2263 return ret;
2267 /******************************************************************************
2268 * RegUnLoadKeyA [ADVAPI32.@]
2270 * See RegUnLoadKeyW.
2272 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2274 UNICODE_STRING lpSubKeyW;
2275 LONG ret;
2277 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2278 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2279 RtlFreeUnicodeString( &lpSubKeyW );
2280 return ret;
2284 /******************************************************************************
2285 * RegReplaceKeyW [ADVAPI32.@]
2287 * Replace the file backing a registry key and all its subkeys with another file.
2289 * PARAMS
2290 * hkey [I] Handle of open key
2291 * lpSubKey [I] Address of name of subkey
2292 * lpNewFile [I] Address of filename for file with new data
2293 * lpOldFile [I] Address of filename for backup file
2295 * RETURNS
2296 * Success: ERROR_SUCCESS
2297 * Failure: nonzero error code from Winerror.h
2299 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2300 LPCWSTR lpOldFile )
2302 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2303 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2304 return ERROR_SUCCESS;
2308 /******************************************************************************
2309 * RegReplaceKeyA [ADVAPI32.@]
2311 * See RegReplaceKeyW.
2313 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2314 LPCSTR lpOldFile )
2316 UNICODE_STRING lpSubKeyW;
2317 UNICODE_STRING lpNewFileW;
2318 UNICODE_STRING lpOldFileW;
2319 LONG ret;
2321 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2322 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2323 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2324 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2325 RtlFreeUnicodeString( &lpOldFileW );
2326 RtlFreeUnicodeString( &lpNewFileW );
2327 RtlFreeUnicodeString( &lpSubKeyW );
2328 return ret;
2332 /******************************************************************************
2333 * RegSetKeySecurity [ADVAPI32.@]
2335 * Set the security of an open registry key.
2337 * PARAMS
2338 * hkey [I] Open handle of key to set
2339 * SecurityInfo [I] Descriptor contents
2340 * pSecurityDesc [I] Address of descriptor for key
2342 * RETURNS
2343 * Success: ERROR_SUCCESS
2344 * Failure: nonzero error code from Winerror.h
2346 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2347 PSECURITY_DESCRIPTOR pSecurityDesc )
2349 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2351 /* It seems to perform this check before the hkey check */
2352 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2353 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2354 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2355 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2356 /* Param OK */
2357 } else
2358 return ERROR_INVALID_PARAMETER;
2360 if (!pSecurityDesc)
2361 return ERROR_INVALID_PARAMETER;
2363 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2365 return ERROR_SUCCESS;
2369 /******************************************************************************
2370 * RegGetKeySecurity [ADVAPI32.@]
2372 * Get a copy of the security descriptor for a given registry key.
2374 * PARAMS
2375 * hkey [I] Open handle of key to set
2376 * SecurityInformation [I] Descriptor contents
2377 * pSecurityDescriptor [O] Address of descriptor for key
2378 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2380 * RETURNS
2381 * Success: ERROR_SUCCESS
2382 * Failure: Error code
2384 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2385 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2386 LPDWORD lpcbSecurityDescriptor )
2388 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2389 *lpcbSecurityDescriptor);
2391 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2393 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2394 SecurityInformation, pSecurityDescriptor,
2395 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2399 /******************************************************************************
2400 * RegFlushKey [ADVAPI32.@]
2402 * Immediately write a registry key to registry.
2404 * PARAMS
2405 * hkey [I] Handle of key to write
2407 * RETURNS
2408 * Success: ERROR_SUCCESS
2409 * Failure: Error code
2411 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2413 hkey = get_special_root_hkey( hkey );
2414 if (!hkey) return ERROR_INVALID_HANDLE;
2416 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2420 /******************************************************************************
2421 * RegConnectRegistryW [ADVAPI32.@]
2423 * Establish a connection to a predefined registry key on another computer.
2425 * PARAMS
2426 * lpMachineName [I] Address of name of remote computer
2427 * hHey [I] Predefined registry handle
2428 * phkResult [I] Address of buffer for remote registry handle
2430 * RETURNS
2431 * Success: ERROR_SUCCESS
2432 * Failure: nonzero error code from Winerror.h
2434 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2435 PHKEY phkResult )
2437 LONG ret;
2439 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2441 if (!lpMachineName || !*lpMachineName) {
2442 /* Use the local machine name */
2443 ret = RegOpenKeyW( hKey, NULL, phkResult );
2445 else {
2446 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2447 DWORD len = sizeof(compName) / sizeof(WCHAR);
2449 /* MSDN says lpMachineName must start with \\ : not so */
2450 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2451 lpMachineName += 2;
2452 if (GetComputerNameW(compName, &len))
2454 if (!strcmpiW(lpMachineName, compName))
2455 ret = RegOpenKeyW(hKey, NULL, phkResult);
2456 else
2458 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2459 ret = ERROR_BAD_NETPATH;
2462 else
2463 ret = GetLastError();
2465 return ret;
2469 /******************************************************************************
2470 * RegConnectRegistryA [ADVAPI32.@]
2472 * See RegConnectRegistryW.
2474 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2476 UNICODE_STRING machineW;
2477 LONG ret;
2479 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2480 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2481 RtlFreeUnicodeString( &machineW );
2482 return ret;
2486 /******************************************************************************
2487 * RegNotifyChangeKeyValue [ADVAPI32.@]
2489 * Notify the caller about changes to the attributes or contents of a registry key.
2491 * PARAMS
2492 * hkey [I] Handle of key to watch
2493 * fWatchSubTree [I] Flag for subkey notification
2494 * fdwNotifyFilter [I] Changes to be reported
2495 * hEvent [I] Handle of signaled event
2496 * fAsync [I] Flag for asynchronous reporting
2498 * RETURNS
2499 * Success: ERROR_SUCCESS
2500 * Failure: nonzero error code from Winerror.h
2502 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2503 DWORD fdwNotifyFilter, HANDLE hEvent,
2504 BOOL fAsync )
2506 NTSTATUS status;
2507 IO_STATUS_BLOCK iosb;
2509 hkey = get_special_root_hkey( hkey );
2510 if (!hkey) return ERROR_INVALID_HANDLE;
2512 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2513 hEvent, fAsync);
2515 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2516 fdwNotifyFilter, fAsync, NULL, 0,
2517 fWatchSubTree);
2519 if (status && status != STATUS_TIMEOUT)
2520 return RtlNtStatusToDosError( status );
2522 return ERROR_SUCCESS;
2525 /******************************************************************************
2526 * RegOpenUserClassesRoot [ADVAPI32.@]
2528 * Open the HKEY_CLASSES_ROOT key for a user.
2530 * PARAMS
2531 * hToken [I] Handle of token representing the user
2532 * dwOptions [I] Reserved, must be 0
2533 * samDesired [I] Desired access rights
2534 * phkResult [O] Destination for the resulting key handle
2536 * RETURNS
2537 * Success: ERROR_SUCCESS
2538 * Failure: nonzero error code from Winerror.h
2540 * NOTES
2541 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2542 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2543 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2545 LSTATUS WINAPI RegOpenUserClassesRoot(
2546 HANDLE hToken,
2547 DWORD dwOptions,
2548 REGSAM samDesired,
2549 PHKEY phkResult
2552 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2554 *phkResult = HKEY_CLASSES_ROOT;
2555 return ERROR_SUCCESS;
2558 /******************************************************************************
2559 * load_string [Internal]
2561 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2562 * avoid importing user32, which is higher level than advapi32. Helper for
2563 * RegLoadMUIString.
2565 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2567 HGLOBAL hMemory;
2568 HRSRC hResource;
2569 WCHAR *pString;
2570 int idxString;
2572 /* Negative values have to be inverted. */
2573 if (HIWORD(resId) == 0xffff)
2574 resId = (UINT)(-((INT)resId));
2576 /* Load the resource into memory and get a pointer to it. */
2577 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2578 if (!hResource) return 0;
2579 hMemory = LoadResource(hModule, hResource);
2580 if (!hMemory) return 0;
2581 pString = LockResource(hMemory);
2583 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2584 idxString = resId & 0xf;
2585 while (idxString--) pString += *pString + 1;
2587 /* If no buffer is given, return length of the string. */
2588 if (!pwszBuffer) return *pString;
2590 /* Else copy over the string, respecting the buffer size. */
2591 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2592 if (cMaxChars >= 0) {
2593 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2594 pwszBuffer[cMaxChars] = '\0';
2597 return cMaxChars;
2600 /******************************************************************************
2601 * RegLoadMUIStringW [ADVAPI32.@]
2603 * Load the localized version of a string resource from some PE, respective
2604 * id and path of which are given in the registry value in the format
2605 * @[path]\dllname,-resourceId
2607 * PARAMS
2608 * hKey [I] Key, of which to load the string value from.
2609 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2610 * pszBuffer [O] Buffer to store the localized string in.
2611 * cbBuffer [I] Size of the destination buffer in bytes.
2612 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2613 * dwFlags [I] None supported yet.
2614 * pszBaseDir [I] Not supported yet.
2616 * RETURNS
2617 * Success: ERROR_SUCCESS,
2618 * Failure: nonzero error code from winerror.h
2620 * NOTES
2621 * This is an API of Windows Vista, which wasn't available at the time this code
2622 * was written. We have to check for the correct behaviour once it's available.
2624 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2625 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2627 DWORD dwValueType, cbData;
2628 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2629 LONG result;
2631 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2632 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2633 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2635 /* Parameter sanity checks. */
2636 if (!hKey || !pwszBuffer)
2637 return ERROR_INVALID_PARAMETER;
2639 if (pwszBaseDir && *pwszBaseDir) {
2640 FIXME("BaseDir parameter not yet supported!\n");
2641 return ERROR_INVALID_PARAMETER;
2644 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2645 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2646 if (result != ERROR_SUCCESS) goto cleanup;
2647 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2648 result = ERROR_FILE_NOT_FOUND;
2649 goto cleanup;
2651 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2652 if (!pwszTempBuffer) {
2653 result = ERROR_NOT_ENOUGH_MEMORY;
2654 goto cleanup;
2656 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2657 if (result != ERROR_SUCCESS) goto cleanup;
2659 /* Expand environment variables, if appropriate, or copy the original string over. */
2660 if (dwValueType == REG_EXPAND_SZ) {
2661 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2662 if (!cbData) goto cleanup;
2663 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2664 if (!pwszExpandedBuffer) {
2665 result = ERROR_NOT_ENOUGH_MEMORY;
2666 goto cleanup;
2668 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2669 } else {
2670 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2671 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2674 /* If the value references a resource based string, parse the value and load the string.
2675 * Else just copy over the original value. */
2676 result = ERROR_SUCCESS;
2677 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2678 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2679 } else {
2680 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2681 UINT uiStringId;
2682 HMODULE hModule;
2684 /* Format of the expanded value is 'path_to_dll,-resId' */
2685 if (!pComma || pComma[1] != '-') {
2686 result = ERROR_BADKEY;
2687 goto cleanup;
2690 uiStringId = atoiW(pComma+2);
2691 *pComma = '\0';
2693 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2694 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2695 result = ERROR_BADKEY;
2696 FreeLibrary(hModule);
2699 cleanup:
2700 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2701 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2702 return result;
2705 /******************************************************************************
2706 * RegLoadMUIStringA [ADVAPI32.@]
2708 * See RegLoadMUIStringW
2710 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2711 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2713 UNICODE_STRING valueW, baseDirW;
2714 WCHAR *pwszBuffer;
2715 DWORD cbData = cbBuffer * sizeof(WCHAR);
2716 LONG result;
2718 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2719 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2720 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2721 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2723 result = ERROR_NOT_ENOUGH_MEMORY;
2724 goto cleanup;
2727 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2728 baseDirW.Buffer);
2730 if (result == ERROR_SUCCESS) {
2731 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2732 if (pcbData)
2733 *pcbData = cbData;
2736 cleanup:
2737 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2738 RtlFreeUnicodeString(&baseDirW);
2739 RtlFreeUnicodeString(&valueW);
2741 return result;
2744 /******************************************************************************
2745 * RegDisablePredefinedCache [ADVAPI32.@]
2747 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2749 * PARAMS
2750 * None.
2752 * RETURNS
2753 * Success: ERROR_SUCCESS
2754 * Failure: nonzero error code from Winerror.h
2756 * NOTES
2757 * This is useful for services that use impersonation.
2759 LSTATUS WINAPI RegDisablePredefinedCache(void)
2761 HKEY hkey_current_user;
2762 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2764 /* prevent caching of future requests */
2765 hkcu_cache_disabled = TRUE;
2767 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2769 if (hkey_current_user)
2770 NtClose( hkey_current_user );
2772 return ERROR_SUCCESS;
2775 /******************************************************************************
2776 * RegDeleteTreeW [ADVAPI32.@]
2779 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2781 LONG ret;
2782 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2783 DWORD dwMaxLen, dwSize;
2784 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2785 HKEY hSubKey = hKey;
2787 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2789 if(lpszSubKey)
2791 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2792 if (ret) return ret;
2795 /* Get highest length for keys, values */
2796 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2797 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2798 if (ret) goto cleanup;
2800 dwMaxSubkeyLen++;
2801 dwMaxValueLen++;
2802 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2803 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2805 /* Name too big: alloc a buffer for it */
2806 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2808 ret = ERROR_NOT_ENOUGH_MEMORY;
2809 goto cleanup;
2814 /* Recursively delete all the subkeys */
2815 while (TRUE)
2817 dwSize = dwMaxLen;
2818 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2819 NULL, NULL, NULL)) break;
2821 ret = RegDeleteTreeW(hSubKey, lpszName);
2822 if (ret) goto cleanup;
2825 if (lpszSubKey)
2826 ret = RegDeleteKeyW(hKey, lpszSubKey);
2827 else
2828 while (TRUE)
2830 dwSize = dwMaxLen;
2831 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2832 NULL, NULL, NULL, NULL)) break;
2834 ret = RegDeleteValueW(hKey, lpszName);
2835 if (ret) goto cleanup;
2838 cleanup:
2839 /* Free buffer if allocated */
2840 if (lpszName != szNameBuf)
2841 HeapFree( GetProcessHeap(), 0, lpszName);
2842 if(lpszSubKey)
2843 RegCloseKey(hSubKey);
2844 return ret;
2847 /******************************************************************************
2848 * RegDeleteTreeA [ADVAPI32.@]
2851 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2853 LONG ret;
2854 UNICODE_STRING lpszSubKeyW;
2856 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2857 else lpszSubKeyW.Buffer = NULL;
2858 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2859 RtlFreeUnicodeString( &lpszSubKeyW );
2860 return ret;