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