dbghelp: Ignore a few more symbol ids.
[wine/multimedia.git] / dlls / advapi32 / registry.c
blobbb68b3dcde0a1ae2aacd51b4de60f8ad20476b6d
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 * subkey [I] Name of a subkey of hKey.
1281 * type [I] Type of information to store.
1282 * data [I] String that contains the data to set for the default value.
1283 * count [I] Ignored.
1285 * RETURNS
1286 * Success: ERROR_SUCCESS
1287 * Failure: nonzero error code from Winerror.h
1289 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR subkey, DWORD type, LPCWSTR data, DWORD count )
1291 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(subkey), type, debugstr_w(data), count );
1293 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1295 return RegSetKeyValueW( hkey, subkey, NULL, type, data, (strlenW(data) + 1)*sizeof(WCHAR) );
1298 /******************************************************************************
1299 * RegSetValueA [ADVAPI32.@]
1301 * See RegSetValueW.
1303 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR subkey, DWORD type, LPCSTR data, DWORD count )
1305 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(subkey), type, debugstr_a(data), count );
1307 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1309 return RegSetKeyValueA( hkey, subkey, NULL, type, data, strlen(data) + 1 );
1312 /******************************************************************************
1313 * RegSetKeyValueW [ADVAPI32.@]
1315 LONG WINAPI RegSetKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name, DWORD type, const void *data, DWORD len )
1317 HKEY hsubkey = NULL;
1318 DWORD ret;
1320 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey, debugstr_w(subkey), debugstr_w(name), type, data, len );
1322 if (subkey && subkey[0]) /* need to create the subkey */
1324 if ((ret = RegCreateKeyW( hkey, subkey, &hsubkey )) != ERROR_SUCCESS) return ret;
1325 hkey = hsubkey;
1328 ret = RegSetValueExW( hkey, name, 0, type, (const BYTE*)data, len );
1329 if (hsubkey) RegCloseKey( hsubkey );
1330 return ret;
1333 /******************************************************************************
1334 * RegSetKeyValueA [ADVAPI32.@]
1336 LONG WINAPI RegSetKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name, DWORD type, const void *data, DWORD len )
1338 HKEY hsubkey = NULL;
1339 DWORD ret;
1341 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey, debugstr_a(subkey), debugstr_a(name), type, data, len );
1343 if (subkey && subkey[0]) /* need to create the subkey */
1345 if ((ret = RegCreateKeyA( hkey, subkey, &hsubkey )) != ERROR_SUCCESS) return ret;
1346 hkey = hsubkey;
1349 ret = RegSetValueExA( hkey, name, 0, type, (const BYTE*)data, len );
1350 if (hsubkey) RegCloseKey( hsubkey );
1351 return ret;
1354 /******************************************************************************
1355 * RegQueryValueExW [ADVAPI32.@]
1357 * See RegQueryValueExA.
1359 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1360 LPBYTE data, LPDWORD count )
1362 NTSTATUS status;
1363 UNICODE_STRING name_str;
1364 DWORD total_size;
1365 char buffer[256], *buf_ptr = buffer;
1366 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1367 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1369 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1370 hkey, debugstr_w(name), reserved, type, data, count,
1371 (count && data) ? *count : 0 );
1373 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1374 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1376 RtlInitUnicodeString( &name_str, name );
1378 if (data) total_size = min( sizeof(buffer), *count + info_size );
1379 else
1381 total_size = info_size;
1382 if (count) *count = 0;
1385 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1386 buffer, total_size, &total_size );
1387 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1389 if (data)
1391 /* retry with a dynamically allocated buffer */
1392 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1394 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1395 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1396 return ERROR_NOT_ENOUGH_MEMORY;
1397 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1398 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1399 buf_ptr, total_size, &total_size );
1402 if (!status)
1404 memcpy( data, buf_ptr + info_size, total_size - info_size );
1405 /* if the type is REG_SZ and data is not 0-terminated
1406 * and there is enough space in the buffer NT appends a \0 */
1407 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1409 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1410 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1413 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1415 else status = STATUS_SUCCESS;
1417 if (type) *type = info->Type;
1418 if (count) *count = total_size - info_size;
1420 done:
1421 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1422 return RtlNtStatusToDosError(status);
1426 /******************************************************************************
1427 * RegQueryValueExA [ADVAPI32.@]
1429 * Get the type and contents of a specified value under with a key.
1431 * PARAMS
1432 * hkey [I] Handle of the key to query
1433 * name [I] Name of value under hkey to query
1434 * reserved [I] Reserved - must be NULL
1435 * type [O] Destination for the value type, or NULL if not required
1436 * data [O] Destination for the values contents, or NULL if not required
1437 * count [I/O] Size of data, updated with the number of bytes returned
1439 * RETURNS
1440 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1441 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1442 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1443 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1445 * NOTES
1446 * MSDN states that if data is too small it is partially filled. In reality
1447 * it remains untouched.
1449 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1450 LPBYTE data, LPDWORD count )
1452 NTSTATUS status;
1453 ANSI_STRING nameA;
1454 UNICODE_STRING nameW;
1455 DWORD total_size, datalen = 0;
1456 char buffer[256], *buf_ptr = buffer;
1457 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1458 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1460 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1461 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1463 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1464 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1466 if (count) datalen = *count;
1467 if (!data && count) *count = 0;
1469 /* this matches Win9x behaviour - NT sets *type to a random value */
1470 if (type) *type = REG_NONE;
1472 RtlInitAnsiString( &nameA, name );
1473 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1474 return RtlNtStatusToDosError(status);
1476 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1477 buffer, sizeof(buffer), &total_size );
1478 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1480 /* we need to fetch the contents for a string type even if not requested,
1481 * because we need to compute the length of the ASCII string. */
1482 if (data || is_string(info->Type))
1484 /* retry with a dynamically allocated buffer */
1485 while (status == STATUS_BUFFER_OVERFLOW)
1487 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1488 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1490 status = STATUS_NO_MEMORY;
1491 goto done;
1493 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1494 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1495 buf_ptr, total_size, &total_size );
1498 if (status) goto done;
1500 if (is_string(info->Type))
1502 DWORD len;
1504 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1505 total_size - info_size );
1506 if (data && len)
1508 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1509 else
1511 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1512 total_size - info_size );
1513 /* if the type is REG_SZ and data is not 0-terminated
1514 * and there is enough space in the buffer NT appends a \0 */
1515 if (len < datalen && data[len-1]) data[len] = 0;
1518 total_size = len + info_size;
1520 else if (data)
1522 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1523 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1526 else status = STATUS_SUCCESS;
1528 if (type) *type = info->Type;
1529 if (count) *count = total_size - info_size;
1531 done:
1532 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1533 RtlFreeUnicodeString( &nameW );
1534 return RtlNtStatusToDosError(status);
1538 /******************************************************************************
1539 * RegQueryValueW [ADVAPI32.@]
1541 * Retrieves the data associated with the default or unnamed value of a key.
1543 * PARAMS
1544 * hkey [I] Handle to an open key.
1545 * name [I] Name of the subkey of hKey.
1546 * data [O] Receives the string associated with the default value
1547 * of the key.
1548 * count [I/O] Size of lpValue in bytes.
1550 * RETURNS
1551 * Success: ERROR_SUCCESS
1552 * Failure: nonzero error code from Winerror.h
1554 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1556 DWORD ret;
1557 HKEY subkey = hkey;
1559 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1561 if (name && name[0])
1563 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1565 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1566 if (subkey != hkey) RegCloseKey( subkey );
1567 if (ret == ERROR_FILE_NOT_FOUND)
1569 /* return empty string if default value not found */
1570 if (data) *data = 0;
1571 if (count) *count = sizeof(WCHAR);
1572 ret = ERROR_SUCCESS;
1574 return ret;
1578 /******************************************************************************
1579 * RegQueryValueA [ADVAPI32.@]
1581 * See RegQueryValueW.
1583 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1585 DWORD ret;
1586 HKEY subkey = hkey;
1588 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1590 if (name && name[0])
1592 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1594 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1595 if (subkey != hkey) RegCloseKey( subkey );
1596 if (ret == ERROR_FILE_NOT_FOUND)
1598 /* return empty string if default value not found */
1599 if (data) *data = 0;
1600 if (count) *count = 1;
1601 ret = ERROR_SUCCESS;
1603 return ret;
1607 /******************************************************************************
1608 * ADVAPI_ApplyRestrictions [internal]
1610 * Helper function for RegGetValueA/W.
1612 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1613 DWORD cbData, PLONG ret )
1615 /* Check if the type is restricted by the passed flags */
1616 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1618 DWORD dwMask = 0;
1620 switch (dwType)
1622 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1623 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1624 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1625 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1626 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1627 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1628 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1631 if (dwFlags & dwMask)
1633 /* Type is not restricted, check for size mismatch */
1634 if (dwType == REG_BINARY)
1636 DWORD cbExpect = 0;
1638 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1639 cbExpect = 4;
1640 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1641 cbExpect = 8;
1643 if (cbExpect && cbData != cbExpect)
1644 *ret = ERROR_DATATYPE_MISMATCH;
1647 else *ret = ERROR_UNSUPPORTED_TYPE;
1652 /******************************************************************************
1653 * RegGetValueW [ADVAPI32.@]
1655 * Retrieves the type and data for a value name associated with a key,
1656 * optionally expanding its content and restricting its type.
1658 * PARAMS
1659 * hKey [I] Handle to an open key.
1660 * pszSubKey [I] Name of the subkey of hKey.
1661 * pszValue [I] Name of value under hKey/szSubKey to query.
1662 * dwFlags [I] Flags restricting the value type to retrieve.
1663 * pdwType [O] Destination for the values type, may be NULL.
1664 * pvData [O] Destination for the values content, may be NULL.
1665 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1666 * retrieve the whole content, including the trailing '\0'
1667 * for strings.
1669 * RETURNS
1670 * Success: ERROR_SUCCESS
1671 * Failure: nonzero error code from Winerror.h
1673 * NOTES
1674 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1675 * expanded and pdwType is set to REG_SZ instead.
1676 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1677 * without RRF_NOEXPAND is thus not allowed.
1678 * An exception is the case where RRF_RT_ANY is specified, because then
1679 * RRF_NOEXPAND is allowed.
1681 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1682 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1683 LPDWORD pcbData )
1685 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1686 PVOID pvBuf = NULL;
1687 LONG ret;
1689 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1690 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1691 pvData, pcbData, cbData);
1693 if (pvData && !pcbData)
1694 return ERROR_INVALID_PARAMETER;
1695 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1696 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1697 return ERROR_INVALID_PARAMETER;
1699 if (pszSubKey && pszSubKey[0])
1701 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1702 if (ret != ERROR_SUCCESS) return ret;
1705 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1707 /* If we are going to expand we need to read in the whole the value even
1708 * if the passed buffer was too small as the expanded string might be
1709 * smaller than the unexpanded one and could fit into cbData bytes. */
1710 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1711 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1713 do {
1714 HeapFree(GetProcessHeap(), 0, pvBuf);
1716 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1717 if (!pvBuf)
1719 ret = ERROR_NOT_ENOUGH_MEMORY;
1720 break;
1723 if (ret == ERROR_MORE_DATA || !pvData)
1724 ret = RegQueryValueExW(hKey, pszValue, NULL,
1725 &dwType, pvBuf, &cbData);
1726 else
1728 /* Even if cbData was large enough we have to copy the
1729 * string since ExpandEnvironmentStrings can't handle
1730 * overlapping buffers. */
1731 CopyMemory(pvBuf, pvData, cbData);
1734 /* Both the type or the value itself could have been modified in
1735 * between so we have to keep retrying until the buffer is large
1736 * enough or we no longer have to expand the value. */
1737 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1739 if (ret == ERROR_SUCCESS)
1741 /* Recheck dwType in case it changed since the first call */
1742 if (dwType == REG_EXPAND_SZ)
1744 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1745 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1746 dwType = REG_SZ;
1747 if(pvData && pcbData && cbData > *pcbData)
1748 ret = ERROR_MORE_DATA;
1750 else if (pvData)
1751 CopyMemory(pvData, pvBuf, *pcbData);
1754 HeapFree(GetProcessHeap(), 0, pvBuf);
1757 if (pszSubKey && pszSubKey[0])
1758 RegCloseKey(hKey);
1760 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1762 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1763 ZeroMemory(pvData, *pcbData);
1765 if (pdwType) *pdwType = dwType;
1766 if (pcbData) *pcbData = cbData;
1768 return ret;
1772 /******************************************************************************
1773 * RegGetValueA [ADVAPI32.@]
1775 * See RegGetValueW.
1777 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1778 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1779 LPDWORD pcbData )
1781 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1782 PVOID pvBuf = NULL;
1783 LONG ret;
1785 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1786 hKey, debugstr_a(pszSubKey), debugstr_a(pszValue), dwFlags,
1787 pdwType, pvData, pcbData, cbData);
1789 if (pvData && !pcbData)
1790 return ERROR_INVALID_PARAMETER;
1791 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1792 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1793 return ERROR_INVALID_PARAMETER;
1795 if (pszSubKey && pszSubKey[0])
1797 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1798 if (ret != ERROR_SUCCESS) return ret;
1801 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1803 /* If we are going to expand we need to read in the whole the value even
1804 * if the passed buffer was too small as the expanded string might be
1805 * smaller than the unexpanded one and could fit into cbData bytes. */
1806 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1807 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1809 do {
1810 HeapFree(GetProcessHeap(), 0, pvBuf);
1812 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1813 if (!pvBuf)
1815 ret = ERROR_NOT_ENOUGH_MEMORY;
1816 break;
1819 if (ret == ERROR_MORE_DATA || !pvData)
1820 ret = RegQueryValueExA(hKey, pszValue, NULL,
1821 &dwType, pvBuf, &cbData);
1822 else
1824 /* Even if cbData was large enough we have to copy the
1825 * string since ExpandEnvironmentStrings can't handle
1826 * overlapping buffers. */
1827 CopyMemory(pvBuf, pvData, cbData);
1830 /* Both the type or the value itself could have been modified in
1831 * between so we have to keep retrying until the buffer is large
1832 * enough or we no longer have to expand the value. */
1833 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1835 if (ret == ERROR_SUCCESS)
1837 /* Recheck dwType in case it changed since the first call */
1838 if (dwType == REG_EXPAND_SZ)
1840 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1841 pcbData ? *pcbData : 0);
1842 dwType = REG_SZ;
1843 if(pvData && pcbData && cbData > *pcbData)
1844 ret = ERROR_MORE_DATA;
1846 else if (pvData)
1847 CopyMemory(pvData, pvBuf, *pcbData);
1850 HeapFree(GetProcessHeap(), 0, pvBuf);
1853 if (pszSubKey && pszSubKey[0])
1854 RegCloseKey(hKey);
1856 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1858 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1859 ZeroMemory(pvData, *pcbData);
1861 if (pdwType) *pdwType = dwType;
1862 if (pcbData) *pcbData = cbData;
1864 return ret;
1868 /******************************************************************************
1869 * RegEnumValueW [ADVAPI32.@]
1871 * Enumerates the values for the specified open registry key.
1873 * PARAMS
1874 * hkey [I] Handle to key to query
1875 * index [I] Index of value to query
1876 * value [O] Value string
1877 * val_count [I/O] Size of value buffer (in wchars)
1878 * reserved [I] Reserved
1879 * type [O] Type code
1880 * data [O] Value data
1881 * count [I/O] Size of data buffer (in bytes)
1883 * RETURNS
1884 * Success: ERROR_SUCCESS
1885 * Failure: nonzero error code from Winerror.h
1888 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1889 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1891 NTSTATUS status;
1892 DWORD total_size;
1893 char buffer[256], *buf_ptr = buffer;
1894 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1895 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1897 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1898 hkey, index, value, val_count, reserved, type, data, count );
1900 /* NT only checks count, not val_count */
1901 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1902 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1904 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1905 if (data) total_size += *count;
1906 total_size = min( sizeof(buffer), total_size );
1908 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1909 buffer, total_size, &total_size );
1910 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1912 if (value || data)
1914 /* retry with a dynamically allocated buffer */
1915 while (status == STATUS_BUFFER_OVERFLOW)
1917 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1918 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1919 return ERROR_NOT_ENOUGH_MEMORY;
1920 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1921 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1922 buf_ptr, total_size, &total_size );
1925 if (status) goto done;
1927 if (value)
1929 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1931 status = STATUS_BUFFER_OVERFLOW;
1932 goto overflow;
1934 memcpy( value, info->Name, info->NameLength );
1935 *val_count = info->NameLength / sizeof(WCHAR);
1936 value[*val_count] = 0;
1939 if (data)
1941 if (total_size - info->DataOffset > *count)
1943 status = STATUS_BUFFER_OVERFLOW;
1944 goto overflow;
1946 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1947 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1949 /* if the type is REG_SZ and data is not 0-terminated
1950 * and there is enough space in the buffer NT appends a \0 */
1951 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1952 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1956 else status = STATUS_SUCCESS;
1958 overflow:
1959 if (type) *type = info->Type;
1960 if (count) *count = info->DataLength;
1962 done:
1963 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1964 return RtlNtStatusToDosError(status);
1968 /******************************************************************************
1969 * RegEnumValueA [ADVAPI32.@]
1971 * See RegEnumValueW.
1973 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1974 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1976 NTSTATUS status;
1977 DWORD total_size;
1978 char buffer[256], *buf_ptr = buffer;
1979 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1980 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1982 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1983 hkey, index, value, val_count, reserved, type, data, count );
1985 /* NT only checks count, not val_count */
1986 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1987 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
1989 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1990 if (data) total_size += *count;
1991 total_size = min( sizeof(buffer), total_size );
1993 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1994 buffer, total_size, &total_size );
1995 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1997 /* we need to fetch the contents for a string type even if not requested,
1998 * because we need to compute the length of the ASCII string. */
1999 if (value || data || is_string(info->Type))
2001 /* retry with a dynamically allocated buffer */
2002 while (status == STATUS_BUFFER_OVERFLOW)
2004 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2005 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
2006 return ERROR_NOT_ENOUGH_MEMORY;
2007 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
2008 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
2009 buf_ptr, total_size, &total_size );
2012 if (status) goto done;
2014 if (is_string(info->Type))
2016 DWORD len;
2017 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
2018 total_size - info->DataOffset );
2019 if (data && len)
2021 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
2022 else
2024 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
2025 total_size - info->DataOffset );
2026 /* if the type is REG_SZ and data is not 0-terminated
2027 * and there is enough space in the buffer NT appends a \0 */
2028 if (len < *count && data[len-1]) data[len] = 0;
2031 info->DataLength = len;
2033 else if (data)
2035 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
2036 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
2039 if (value && !status)
2041 DWORD len;
2043 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2044 if (len >= *val_count)
2046 status = STATUS_BUFFER_OVERFLOW;
2047 if (*val_count)
2049 len = *val_count - 1;
2050 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2051 value[len] = 0;
2054 else
2056 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2057 value[len] = 0;
2058 *val_count = len;
2062 else status = STATUS_SUCCESS;
2064 if (type) *type = info->Type;
2065 if (count) *count = info->DataLength;
2067 done:
2068 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2069 return RtlNtStatusToDosError(status);
2072 /******************************************************************************
2073 * RegDeleteValueW [ADVAPI32.@]
2075 * See RegDeleteValueA.
2077 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2079 return RegDeleteKeyValueW( hkey, NULL, name );
2082 /******************************************************************************
2083 * RegDeleteValueA [ADVAPI32.@]
2085 * Delete a value from the registry.
2087 * PARAMS
2088 * hkey [I] Registry handle of the key holding the value
2089 * name [I] Name of the value under hkey to delete
2091 * RETURNS
2092 * Success: ERROR_SUCCESS
2093 * Failure: nonzero error code from Winerror.h
2095 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2097 return RegDeleteKeyValueA( hkey, NULL, name );
2100 /******************************************************************************
2101 * RegDeleteKeyValueW [ADVAPI32.@]
2103 LONG WINAPI RegDeleteKeyValueW( HKEY hkey, LPCWSTR subkey, LPCWSTR name )
2105 UNICODE_STRING nameW;
2106 HKEY hsubkey = 0;
2107 LONG ret;
2109 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2111 if (subkey)
2113 if ((ret = RegOpenKeyExW( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey )))
2114 return ret;
2115 hkey = hsubkey;
2118 RtlInitUnicodeString( &nameW, name );
2119 ret = RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2120 if (hsubkey) RegCloseKey( hsubkey );
2121 return ret;
2124 /******************************************************************************
2125 * RegDeleteKeyValueA [ADVAPI32.@]
2127 LONG WINAPI RegDeleteKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name )
2129 UNICODE_STRING nameW;
2130 HKEY hsubkey = 0;
2131 ANSI_STRING nameA;
2132 NTSTATUS status;
2134 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2136 if (subkey)
2138 LONG ret = RegOpenKeyExA( hkey, subkey, 0, KEY_SET_VALUE, &hsubkey );
2139 if (ret)
2140 return ret;
2141 hkey = hsubkey;
2144 RtlInitAnsiString( &nameA, name );
2145 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2147 status = NtDeleteValueKey( hkey, &nameW );
2148 RtlFreeUnicodeString( &nameW );
2151 if (hsubkey) RegCloseKey( hsubkey );
2152 return RtlNtStatusToDosError( status );
2155 /******************************************************************************
2156 * RegLoadKeyW [ADVAPI32.@]
2158 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2159 * registration information from a specified file into that subkey.
2161 * PARAMS
2162 * hkey [I] Handle of open key
2163 * subkey [I] Address of name of subkey
2164 * filename [I] Address of filename for registry information
2166 * RETURNS
2167 * Success: ERROR_SUCCESS
2168 * Failure: nonzero error code from Winerror.h
2170 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2172 OBJECT_ATTRIBUTES destkey, file;
2173 UNICODE_STRING subkeyW, filenameW;
2174 NTSTATUS status;
2176 if (!(hkey = get_special_root_hkey(hkey, 0))) return ERROR_INVALID_HANDLE;
2178 destkey.Length = sizeof(destkey);
2179 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2180 destkey.ObjectName = &subkeyW; /* name of the key */
2181 destkey.Attributes = 0;
2182 destkey.SecurityDescriptor = NULL;
2183 destkey.SecurityQualityOfService = NULL;
2184 RtlInitUnicodeString(&subkeyW, subkey);
2186 file.Length = sizeof(file);
2187 file.RootDirectory = NULL;
2188 file.ObjectName = &filenameW; /* file containing the hive */
2189 file.Attributes = OBJ_CASE_INSENSITIVE;
2190 file.SecurityDescriptor = NULL;
2191 file.SecurityQualityOfService = NULL;
2192 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2194 status = NtLoadKey(&destkey, &file);
2195 RtlFreeUnicodeString(&filenameW);
2196 return RtlNtStatusToDosError( status );
2200 /******************************************************************************
2201 * RegLoadKeyA [ADVAPI32.@]
2203 * See RegLoadKeyW.
2205 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2207 UNICODE_STRING subkeyW, filenameW;
2208 STRING subkeyA, filenameA;
2209 NTSTATUS status;
2210 LONG ret;
2212 RtlInitAnsiString(&subkeyA, subkey);
2213 RtlInitAnsiString(&filenameA, filename);
2215 RtlInitUnicodeString(&subkeyW, NULL);
2216 RtlInitUnicodeString(&filenameW, NULL);
2217 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2218 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2220 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2222 else ret = RtlNtStatusToDosError(status);
2223 RtlFreeUnicodeString(&subkeyW);
2224 RtlFreeUnicodeString(&filenameW);
2225 return ret;
2229 /******************************************************************************
2230 * RegSaveKeyW [ADVAPI32.@]
2232 * Save a key and all of its subkeys and values to a new file in the standard format.
2234 * PARAMS
2235 * hkey [I] Handle of key where save begins
2236 * lpFile [I] Address of filename to save to
2237 * sa [I] Address of security structure
2239 * RETURNS
2240 * Success: ERROR_SUCCESS
2241 * Failure: nonzero error code from Winerror.h
2243 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2245 static const WCHAR format[] =
2246 {'r','e','g','%','0','4','x','.','t','m','p',0};
2247 WCHAR buffer[MAX_PATH];
2248 int count = 0;
2249 LPWSTR nameW;
2250 DWORD ret, err;
2251 HANDLE handle;
2253 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2255 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2256 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2258 err = GetLastError();
2259 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2261 for (;;)
2263 snprintfW( nameW, 16, format, count++ );
2264 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2265 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2266 if (handle != INVALID_HANDLE_VALUE) break;
2267 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2269 /* Something gone haywire ? Please report if this happens abnormally */
2270 if (count >= 100)
2271 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);
2274 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2276 CloseHandle( handle );
2277 if (!ret)
2279 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2281 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2282 debugstr_w(file) );
2283 ret = GetLastError();
2286 if (ret) DeleteFileW( buffer );
2288 done:
2289 SetLastError( err ); /* restore last error code */
2290 return ret;
2294 /******************************************************************************
2295 * RegSaveKeyA [ADVAPI32.@]
2297 * See RegSaveKeyW.
2299 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2301 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2302 NTSTATUS status;
2303 STRING fileA;
2305 RtlInitAnsiString(&fileA, file);
2306 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2307 return RtlNtStatusToDosError( status );
2308 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2312 /******************************************************************************
2313 * RegRestoreKeyW [ADVAPI32.@]
2315 * Read the registry information from a file and copy it over a key.
2317 * PARAMS
2318 * hkey [I] Handle of key where restore begins
2319 * lpFile [I] Address of filename containing saved tree
2320 * dwFlags [I] Optional flags
2322 * RETURNS
2323 * Success: ERROR_SUCCESS
2324 * Failure: nonzero error code from Winerror.h
2326 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2328 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2330 /* It seems to do this check before the hkey check */
2331 if (!lpFile || !*lpFile)
2332 return ERROR_INVALID_PARAMETER;
2334 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2336 /* Check for file existence */
2338 return ERROR_SUCCESS;
2342 /******************************************************************************
2343 * RegRestoreKeyA [ADVAPI32.@]
2345 * See RegRestoreKeyW.
2347 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2349 UNICODE_STRING lpFileW;
2350 LONG ret;
2352 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2353 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2354 RtlFreeUnicodeString( &lpFileW );
2355 return ret;
2359 /******************************************************************************
2360 * RegUnLoadKeyW [ADVAPI32.@]
2362 * Unload a registry key and its subkeys from the registry.
2364 * PARAMS
2365 * hkey [I] Handle of open key
2366 * lpSubKey [I] Address of name of subkey to unload
2368 * RETURNS
2369 * Success: ERROR_SUCCESS
2370 * Failure: nonzero error code from Winerror.h
2372 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2374 DWORD ret;
2375 HKEY shkey;
2376 OBJECT_ATTRIBUTES attr;
2377 UNICODE_STRING subkey;
2379 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2381 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2382 if( ret )
2383 return ERROR_INVALID_PARAMETER;
2385 RtlInitUnicodeString(&subkey, lpSubKey);
2386 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2387 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2389 RegCloseKey(shkey);
2391 return ret;
2395 /******************************************************************************
2396 * RegUnLoadKeyA [ADVAPI32.@]
2398 * See RegUnLoadKeyW.
2400 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2402 UNICODE_STRING lpSubKeyW;
2403 LONG ret;
2405 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2406 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2407 RtlFreeUnicodeString( &lpSubKeyW );
2408 return ret;
2412 /******************************************************************************
2413 * RegReplaceKeyW [ADVAPI32.@]
2415 * Replace the file backing a registry key and all its subkeys with another file.
2417 * PARAMS
2418 * hkey [I] Handle of open key
2419 * lpSubKey [I] Address of name of subkey
2420 * lpNewFile [I] Address of filename for file with new data
2421 * lpOldFile [I] Address of filename for backup file
2423 * RETURNS
2424 * Success: ERROR_SUCCESS
2425 * Failure: nonzero error code from Winerror.h
2427 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2428 LPCWSTR lpOldFile )
2430 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2431 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2432 return ERROR_SUCCESS;
2436 /******************************************************************************
2437 * RegReplaceKeyA [ADVAPI32.@]
2439 * See RegReplaceKeyW.
2441 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2442 LPCSTR lpOldFile )
2444 UNICODE_STRING lpSubKeyW;
2445 UNICODE_STRING lpNewFileW;
2446 UNICODE_STRING lpOldFileW;
2447 LONG ret;
2449 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2450 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2451 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2452 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2453 RtlFreeUnicodeString( &lpOldFileW );
2454 RtlFreeUnicodeString( &lpNewFileW );
2455 RtlFreeUnicodeString( &lpSubKeyW );
2456 return ret;
2460 /******************************************************************************
2461 * RegSetKeySecurity [ADVAPI32.@]
2463 * Set the security of an open registry key.
2465 * PARAMS
2466 * hkey [I] Open handle of key to set
2467 * SecurityInfo [I] Descriptor contents
2468 * pSecurityDesc [I] Address of descriptor for key
2470 * RETURNS
2471 * Success: ERROR_SUCCESS
2472 * Failure: nonzero error code from Winerror.h
2474 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2475 PSECURITY_DESCRIPTOR pSecurityDesc )
2477 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2479 /* It seems to perform this check before the hkey check */
2480 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2481 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2482 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2483 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2484 /* Param OK */
2485 } else
2486 return ERROR_INVALID_PARAMETER;
2488 if (!pSecurityDesc)
2489 return ERROR_INVALID_PARAMETER;
2491 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2493 return RtlNtStatusToDosError( NtSetSecurityObject( hkey, SecurityInfo, pSecurityDesc ) );
2497 /******************************************************************************
2498 * RegGetKeySecurity [ADVAPI32.@]
2500 * Get a copy of the security descriptor for a given registry key.
2502 * PARAMS
2503 * hkey [I] Open handle of key to set
2504 * SecurityInformation [I] Descriptor contents
2505 * pSecurityDescriptor [O] Address of descriptor for key
2506 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2508 * RETURNS
2509 * Success: ERROR_SUCCESS
2510 * Failure: Error code
2512 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2513 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2514 LPDWORD lpcbSecurityDescriptor )
2516 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2517 *lpcbSecurityDescriptor);
2519 if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE;
2521 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2522 SecurityInformation, pSecurityDescriptor,
2523 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2527 /******************************************************************************
2528 * RegFlushKey [ADVAPI32.@]
2530 * Immediately write a registry key to registry.
2532 * PARAMS
2533 * hkey [I] Handle of key to write
2535 * RETURNS
2536 * Success: ERROR_SUCCESS
2537 * Failure: Error code
2539 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2541 hkey = get_special_root_hkey( hkey, 0 );
2542 if (!hkey) return ERROR_INVALID_HANDLE;
2544 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2548 /******************************************************************************
2549 * RegConnectRegistryW [ADVAPI32.@]
2551 * Establish a connection to a predefined registry key on another computer.
2553 * PARAMS
2554 * lpMachineName [I] Address of name of remote computer
2555 * hHey [I] Predefined registry handle
2556 * phkResult [I] Address of buffer for remote registry handle
2558 * RETURNS
2559 * Success: ERROR_SUCCESS
2560 * Failure: nonzero error code from Winerror.h
2562 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2563 PHKEY phkResult )
2565 LONG ret;
2567 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName), hKey, phkResult);
2569 if (!lpMachineName || !*lpMachineName) {
2570 /* Use the local machine name */
2571 ret = RegOpenKeyW( hKey, NULL, phkResult );
2573 else {
2574 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2575 DWORD len = sizeof(compName) / sizeof(WCHAR);
2577 /* MSDN says lpMachineName must start with \\ : not so */
2578 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2579 lpMachineName += 2;
2580 if (GetComputerNameW(compName, &len))
2582 if (!strcmpiW(lpMachineName, compName))
2583 ret = RegOpenKeyW(hKey, NULL, phkResult);
2584 else
2586 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2587 ret = ERROR_BAD_NETPATH;
2590 else
2591 ret = GetLastError();
2593 return ret;
2597 /******************************************************************************
2598 * RegConnectRegistryA [ADVAPI32.@]
2600 * See RegConnectRegistryW.
2602 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2604 UNICODE_STRING machineW;
2605 LONG ret;
2607 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2608 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2609 RtlFreeUnicodeString( &machineW );
2610 return ret;
2614 /******************************************************************************
2615 * RegNotifyChangeKeyValue [ADVAPI32.@]
2617 * Notify the caller about changes to the attributes or contents of a registry key.
2619 * PARAMS
2620 * hkey [I] Handle of key to watch
2621 * fWatchSubTree [I] Flag for subkey notification
2622 * fdwNotifyFilter [I] Changes to be reported
2623 * hEvent [I] Handle of signaled event
2624 * fAsync [I] Flag for asynchronous reporting
2626 * RETURNS
2627 * Success: ERROR_SUCCESS
2628 * Failure: nonzero error code from Winerror.h
2630 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2631 DWORD fdwNotifyFilter, HANDLE hEvent,
2632 BOOL fAsync )
2634 NTSTATUS status;
2635 IO_STATUS_BLOCK iosb;
2637 hkey = get_special_root_hkey( hkey, 0 );
2638 if (!hkey) return ERROR_INVALID_HANDLE;
2640 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2641 hEvent, fAsync);
2643 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2644 fdwNotifyFilter, fAsync, NULL, 0,
2645 fWatchSubTree);
2647 if (status && status != STATUS_TIMEOUT)
2648 return RtlNtStatusToDosError( status );
2650 return ERROR_SUCCESS;
2653 /******************************************************************************
2654 * RegOpenUserClassesRoot [ADVAPI32.@]
2656 * Open the HKEY_CLASSES_ROOT key for a user.
2658 * PARAMS
2659 * hToken [I] Handle of token representing the user
2660 * dwOptions [I] Reserved, must be 0
2661 * samDesired [I] Desired access rights
2662 * phkResult [O] Destination for the resulting key handle
2664 * RETURNS
2665 * Success: ERROR_SUCCESS
2666 * Failure: nonzero error code from Winerror.h
2668 * NOTES
2669 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2670 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2671 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2673 LSTATUS WINAPI RegOpenUserClassesRoot(
2674 HANDLE hToken,
2675 DWORD dwOptions,
2676 REGSAM samDesired,
2677 PHKEY phkResult
2680 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2682 *phkResult = HKEY_CLASSES_ROOT;
2683 return ERROR_SUCCESS;
2686 /******************************************************************************
2687 * load_string [Internal]
2689 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2690 * avoid importing user32, which is higher level than advapi32. Helper for
2691 * RegLoadMUIString.
2693 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2695 HGLOBAL hMemory;
2696 HRSRC hResource;
2697 WCHAR *pString;
2698 int idxString;
2700 /* Negative values have to be inverted. */
2701 if (HIWORD(resId) == 0xffff)
2702 resId = (UINT)(-((INT)resId));
2704 /* Load the resource into memory and get a pointer to it. */
2705 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2706 if (!hResource) return 0;
2707 hMemory = LoadResource(hModule, hResource);
2708 if (!hMemory) return 0;
2709 pString = LockResource(hMemory);
2711 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2712 idxString = resId & 0xf;
2713 while (idxString--) pString += *pString + 1;
2715 /* If no buffer is given, return length of the string. */
2716 if (!pwszBuffer) return *pString;
2718 /* Else copy over the string, respecting the buffer size. */
2719 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2720 if (cMaxChars >= 0) {
2721 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2722 pwszBuffer[cMaxChars] = '\0';
2725 return cMaxChars;
2728 /******************************************************************************
2729 * RegLoadMUIStringW [ADVAPI32.@]
2731 * Load the localized version of a string resource from some PE, respective
2732 * id and path of which are given in the registry value in the format
2733 * @[path]\dllname,-resourceId
2735 * PARAMS
2736 * hKey [I] Key, of which to load the string value from.
2737 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2738 * pszBuffer [O] Buffer to store the localized string in.
2739 * cbBuffer [I] Size of the destination buffer in bytes.
2740 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2741 * dwFlags [I] None supported yet.
2742 * pszBaseDir [I] Not supported yet.
2744 * RETURNS
2745 * Success: ERROR_SUCCESS,
2746 * Failure: nonzero error code from winerror.h
2748 * NOTES
2749 * This is an API of Windows Vista, which wasn't available at the time this code
2750 * was written. We have to check for the correct behaviour once it's available.
2752 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2753 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2755 DWORD dwValueType, cbData;
2756 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2757 LONG result;
2759 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2760 "dwFlags = %d, pwszBaseDir = %s)\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2761 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2763 /* Parameter sanity checks. */
2764 if (!hKey || !pwszBuffer)
2765 return ERROR_INVALID_PARAMETER;
2767 if (pwszBaseDir && *pwszBaseDir) {
2768 FIXME("BaseDir parameter not yet supported!\n");
2769 return ERROR_INVALID_PARAMETER;
2772 /* Check for value existence and correctness of its type, allocate a buffer and load it. */
2773 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2774 if (result != ERROR_SUCCESS) goto cleanup;
2775 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2776 result = ERROR_FILE_NOT_FOUND;
2777 goto cleanup;
2779 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2780 if (!pwszTempBuffer) {
2781 result = ERROR_NOT_ENOUGH_MEMORY;
2782 goto cleanup;
2784 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2785 if (result != ERROR_SUCCESS) goto cleanup;
2787 /* Expand environment variables, if appropriate, or copy the original string over. */
2788 if (dwValueType == REG_EXPAND_SZ) {
2789 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2790 if (!cbData) goto cleanup;
2791 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2792 if (!pwszExpandedBuffer) {
2793 result = ERROR_NOT_ENOUGH_MEMORY;
2794 goto cleanup;
2796 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2797 } else {
2798 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2799 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2802 /* If the value references a resource based string, parse the value and load the string.
2803 * Else just copy over the original value. */
2804 result = ERROR_SUCCESS;
2805 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2806 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2807 } else {
2808 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2809 UINT uiStringId;
2810 HMODULE hModule;
2812 /* Format of the expanded value is 'path_to_dll,-resId' */
2813 if (!pComma || pComma[1] != '-') {
2814 result = ERROR_BADKEY;
2815 goto cleanup;
2818 uiStringId = atoiW(pComma+2);
2819 *pComma = '\0';
2821 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2822 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2823 result = ERROR_BADKEY;
2824 FreeLibrary(hModule);
2827 cleanup:
2828 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2829 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2830 return result;
2833 /******************************************************************************
2834 * RegLoadMUIStringA [ADVAPI32.@]
2836 * See RegLoadMUIStringW
2838 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2839 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2841 UNICODE_STRING valueW, baseDirW;
2842 WCHAR *pwszBuffer;
2843 DWORD cbData = cbBuffer * sizeof(WCHAR);
2844 LONG result;
2846 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2847 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2848 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2849 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2851 result = ERROR_NOT_ENOUGH_MEMORY;
2852 goto cleanup;
2855 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2856 baseDirW.Buffer);
2858 if (result == ERROR_SUCCESS) {
2859 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2860 if (pcbData)
2861 *pcbData = cbData;
2864 cleanup:
2865 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2866 RtlFreeUnicodeString(&baseDirW);
2867 RtlFreeUnicodeString(&valueW);
2869 return result;
2872 /******************************************************************************
2873 * RegDisablePredefinedCache [ADVAPI32.@]
2875 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2877 * PARAMS
2878 * None.
2880 * RETURNS
2881 * Success: ERROR_SUCCESS
2882 * Failure: nonzero error code from Winerror.h
2884 * NOTES
2885 * This is useful for services that use impersonation.
2887 LSTATUS WINAPI RegDisablePredefinedCache(void)
2889 HKEY hkey_current_user;
2890 int idx = HandleToUlong(HKEY_CURRENT_USER) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
2892 /* prevent caching of future requests */
2893 hkcu_cache_disabled = TRUE;
2895 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2897 if (hkey_current_user)
2898 NtClose( hkey_current_user );
2900 return ERROR_SUCCESS;
2903 /******************************************************************************
2904 * RegDeleteTreeW [ADVAPI32.@]
2907 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2909 LONG ret;
2910 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2911 DWORD dwMaxLen, dwSize;
2912 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2913 HKEY hSubKey = hKey;
2915 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2917 if(lpszSubKey)
2919 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2920 if (ret) return ret;
2923 /* Get highest length for keys, values */
2924 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2925 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2926 if (ret) goto cleanup;
2928 dwMaxSubkeyLen++;
2929 dwMaxValueLen++;
2930 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2931 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2933 /* Name too big: alloc a buffer for it */
2934 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2936 ret = ERROR_NOT_ENOUGH_MEMORY;
2937 goto cleanup;
2942 /* Recursively delete all the subkeys */
2943 while (TRUE)
2945 dwSize = dwMaxLen;
2946 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2947 NULL, NULL, NULL)) break;
2949 ret = RegDeleteTreeW(hSubKey, lpszName);
2950 if (ret) goto cleanup;
2953 if (lpszSubKey)
2954 ret = RegDeleteKeyW(hKey, lpszSubKey);
2955 else
2956 while (TRUE)
2958 dwSize = dwMaxLen;
2959 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2960 NULL, NULL, NULL, NULL)) break;
2962 ret = RegDeleteValueW(hKey, lpszName);
2963 if (ret) goto cleanup;
2966 cleanup:
2967 /* Free buffer if allocated */
2968 if (lpszName != szNameBuf)
2969 HeapFree( GetProcessHeap(), 0, lpszName);
2970 if(lpszSubKey)
2971 RegCloseKey(hSubKey);
2972 return ret;
2975 /******************************************************************************
2976 * RegDeleteTreeA [ADVAPI32.@]
2979 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2981 LONG ret;
2982 UNICODE_STRING lpszSubKeyW;
2984 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2985 else lpszSubKeyW.Buffer = NULL;
2986 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2987 RtlFreeUnicodeString( &lpszSubKeyW );
2988 return ret;
2991 /******************************************************************************
2992 * RegDisableReflectionKey [ADVAPI32.@]
2995 LONG WINAPI RegDisableReflectionKey(HKEY base)
2997 FIXME("%p: stub\n", base);
2998 return ERROR_SUCCESS;