dbghelp: Restructure internal PDB information.
[wine.git] / dlls / advapi32 / registry.c
blobabaf09d22c5522844a36015af1efcfbad90a27c1
1 /*
2 * Registry management
4 * Copyright (C) 1999 Alexandre Julliard
6 * Based on misc/registry.c code
7 * Copyright (C) 1996 Marcus Meissner
8 * Copyright (C) 1998 Matthew Becker
9 * Copyright (C) 1999 Sylvain St-Germain
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <stdio.h>
30 #include "ntstatus.h"
31 #define WIN32_NO_STATUS
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winreg.h"
35 #include "winerror.h"
36 #include "winternl.h"
37 #include "winuser.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(reg);
44 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
45 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
46 #define NB_SPECIAL_ROOT_KEYS ((UINT_PTR)HKEY_SPECIAL_ROOT_LAST - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST + 1)
48 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
49 static BOOL hkcu_cache_disabled;
51 static const WCHAR name_CLASSES_ROOT[] =
52 {'M','a','c','h','i','n','e','\\',
53 'S','o','f','t','w','a','r','e','\\',
54 'C','l','a','s','s','e','s',0};
55 static const WCHAR name_LOCAL_MACHINE[] =
56 {'M','a','c','h','i','n','e',0};
57 static const WCHAR name_USERS[] =
58 {'U','s','e','r',0};
59 static const WCHAR name_PERFORMANCE_DATA[] =
60 {'P','e','r','f','D','a','t','a',0};
61 static const WCHAR name_CURRENT_CONFIG[] =
62 {'M','a','c','h','i','n','e','\\',
63 'S','y','s','t','e','m','\\',
64 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
65 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
66 'C','u','r','r','e','n','t',0};
67 static const WCHAR name_DYN_DATA[] =
68 {'D','y','n','D','a','t','a',0};
70 static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] =
72 name_CLASSES_ROOT,
73 NULL, /* HKEY_CURRENT_USER is determined dynamically */
74 name_LOCAL_MACHINE,
75 name_USERS,
76 name_PERFORMANCE_DATA,
77 name_CURRENT_CONFIG,
78 name_DYN_DATA
81 static const int is_win64 = (sizeof(void *) > sizeof(int));
83 /* check if value type needs string conversion (Ansi<->Unicode) */
84 static inline int is_string( DWORD type )
86 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
89 /* check if current version is NT or Win95 */
90 static inline int is_version_nt(void)
92 return !(GetVersion() & 0x80000000);
95 static BOOL is_wow6432node( const UNICODE_STRING *name )
97 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e'};
99 return (name->Length == sizeof(wow6432nodeW) &&
100 !memicmpW( name->Buffer, wow6432nodeW, sizeof(wow6432nodeW)/sizeof(WCHAR) ));
103 /* open the Wow6432Node subkey of the specified key */
104 static HANDLE open_wow6432node( HANDLE key, const UNICODE_STRING *name )
106 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
107 OBJECT_ATTRIBUTES attr;
108 UNICODE_STRING nameW;
109 HANDLE ret;
111 attr.Length = sizeof(attr);
112 attr.RootDirectory = key;
113 attr.ObjectName = &nameW;
114 attr.Attributes = 0;
115 attr.SecurityDescriptor = NULL;
116 attr.SecurityQualityOfService = NULL;
117 RtlInitUnicodeString( &nameW, wow6432nodeW );
118 if (NtOpenKey( &ret, MAXIMUM_ALLOWED, &attr )) ret = 0;
119 return ret;
122 /* wrapper for NtCreateKey that creates the key recursively if necessary */
123 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
124 const UNICODE_STRING *class, ULONG options, PULONG dispos )
126 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
127 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
129 if (!force_wow32) status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class, options, dispos );
131 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
133 HANDLE subkey, root = attr->RootDirectory;
134 WCHAR *buffer = attr->ObjectName->Buffer;
135 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
136 UNICODE_STRING str;
138 while (i < len && buffer[i] != '\\') i++;
139 if (i == len && !force_wow32) return status;
141 attrs = attr->Attributes;
142 attr->Attributes &= ~OBJ_OPENLINK;
143 attr->ObjectName = &str;
145 while (i < len)
147 str.Buffer = buffer + pos;
148 str.Length = (i - pos) * sizeof(WCHAR);
149 if (force_wow32 && pos)
151 if (is_wow6432node( &str )) force_wow32 = FALSE;
152 else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
154 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
155 attr->RootDirectory = subkey;
156 force_wow32 = FALSE;
159 status = NtCreateKey( &subkey, access, attr, 0, class,
160 options & ~REG_OPTION_CREATE_LINK, dispos );
161 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
162 if (status) return status;
163 attr->RootDirectory = subkey;
164 while (i < len && buffer[i] == '\\') i++;
165 pos = i;
166 while (i < len && buffer[i] != '\\') i++;
168 str.Buffer = buffer + pos;
169 str.Length = (i - pos) * sizeof(WCHAR);
170 attr->Attributes = attrs;
171 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, class, options, dispos );
172 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
174 return status;
177 /* wrapper for NtOpenKey to handle Wow6432 nodes */
178 static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
180 NTSTATUS status;
181 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
182 HANDLE subkey, root = attr->RootDirectory;
183 WCHAR *buffer = attr->ObjectName->Buffer;
184 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
185 UNICODE_STRING str;
187 if (!force_wow32) return NtOpenKey( (HANDLE *)retkey, access, attr );
189 if (len && buffer[0] == '\\') return STATUS_OBJECT_PATH_INVALID;
190 while (i < len && buffer[i] != '\\') i++;
191 attrs = attr->Attributes;
192 attr->Attributes &= ~OBJ_OPENLINK;
193 attr->ObjectName = &str;
195 while (i < len)
197 str.Buffer = buffer + pos;
198 str.Length = (i - pos) * sizeof(WCHAR);
199 if (force_wow32 && pos)
201 if (is_wow6432node( &str )) force_wow32 = FALSE;
202 else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
204 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
205 attr->RootDirectory = subkey;
206 force_wow32 = FALSE;
209 status = NtOpenKey( &subkey, access, attr );
210 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
211 if (status) return status;
212 attr->RootDirectory = subkey;
213 while (i < len && buffer[i] == '\\') i++;
214 pos = i;
215 while (i < len && buffer[i] != '\\') i++;
217 str.Buffer = buffer + pos;
218 str.Length = (i - pos) * sizeof(WCHAR);
219 attr->Attributes = attrs;
220 status = NtOpenKey( (PHANDLE)retkey, access, attr );
221 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
222 return status;
226 /* create one of the HKEY_* special root keys */
227 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
229 HKEY ret = 0;
230 int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
232 if (hkey == HKEY_CURRENT_USER)
234 if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
235 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
237 /* don't cache the key in the table if caching is disabled */
238 if (hkcu_cache_disabled)
239 return hkey;
241 else
243 OBJECT_ATTRIBUTES attr;
244 UNICODE_STRING name;
246 attr.Length = sizeof(attr);
247 attr.RootDirectory = 0;
248 attr.ObjectName = &name;
249 attr.Attributes = 0;
250 attr.SecurityDescriptor = NULL;
251 attr.SecurityQualityOfService = NULL;
252 RtlInitUnicodeString( &name, root_key_names[idx] );
253 if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0;
254 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
257 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
258 ret = hkey;
259 else
260 NtClose( hkey ); /* somebody beat us to it */
261 return ret;
264 /* map the hkey from special root to normal key if necessary */
265 static inline HKEY get_special_root_hkey( HKEY hkey )
267 HKEY ret = hkey;
269 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
271 if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
272 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED );
274 return ret;
278 /******************************************************************************
279 * RegOverridePredefKey [ADVAPI32.@]
281 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
283 HKEY old_key;
284 int idx;
286 if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST))
287 return ERROR_INVALID_PARAMETER;
288 idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
290 if (override)
292 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
293 GetCurrentProcess(), (HANDLE *)&override,
294 0, 0, DUPLICATE_SAME_ACCESS );
295 if (status) return RtlNtStatusToDosError( status );
298 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
299 if (old_key) NtClose( old_key );
300 return ERROR_SUCCESS;
304 /******************************************************************************
305 * RegCreateKeyExW [ADVAPI32.@]
307 * See RegCreateKeyExA.
309 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
310 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
311 PHKEY retkey, LPDWORD dispos )
313 OBJECT_ATTRIBUTES attr;
314 UNICODE_STRING nameW, classW;
316 if (reserved) return ERROR_INVALID_PARAMETER;
317 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
319 attr.Length = sizeof(attr);
320 attr.RootDirectory = hkey;
321 attr.ObjectName = &nameW;
322 attr.Attributes = 0;
323 attr.SecurityDescriptor = NULL;
324 attr.SecurityQualityOfService = NULL;
325 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
326 RtlInitUnicodeString( &nameW, name );
327 RtlInitUnicodeString( &classW, class );
329 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
333 /******************************************************************************
334 * RegCreateKeyExA [ADVAPI32.@]
336 * Open a registry key, creating it if it doesn't exist.
338 * PARAMS
339 * hkey [I] Handle of the parent registry key
340 * name [I] Name of the new key to open or create
341 * reserved [I] Reserved, pass 0
342 * class [I] The object type of the new key
343 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
344 * access [I] Access level desired
345 * sa [I] Security attributes for the key
346 * retkey [O] Destination for the resulting handle
347 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
349 * RETURNS
350 * Success: ERROR_SUCCESS.
351 * Failure: A standard Win32 error code. retkey remains untouched.
353 * FIXME
354 * MAXIMUM_ALLOWED in access mask not supported by server
356 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
357 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
358 PHKEY retkey, LPDWORD dispos )
360 OBJECT_ATTRIBUTES attr;
361 UNICODE_STRING classW;
362 ANSI_STRING nameA, classA;
363 NTSTATUS status;
365 if (reserved) return ERROR_INVALID_PARAMETER;
366 if (!is_version_nt())
368 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
369 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
371 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
373 attr.Length = sizeof(attr);
374 attr.RootDirectory = hkey;
375 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
376 attr.Attributes = 0;
377 attr.SecurityDescriptor = NULL;
378 attr.SecurityQualityOfService = NULL;
379 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
380 RtlInitAnsiString( &nameA, name );
381 RtlInitAnsiString( &classA, class );
383 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
384 &nameA, FALSE )))
386 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
388 status = create_key( retkey, access, &attr, &classW, options, dispos );
389 RtlFreeUnicodeString( &classW );
392 return RtlNtStatusToDosError( status );
396 /******************************************************************************
397 * RegCreateKeyW [ADVAPI32.@]
399 * Creates the specified reg key.
401 * PARAMS
402 * hKey [I] Handle to an open key.
403 * lpSubKey [I] Name of a key that will be opened or created.
404 * phkResult [O] Receives a handle to the opened or created key.
406 * RETURNS
407 * Success: ERROR_SUCCESS
408 * Failure: nonzero error code defined in Winerror.h
410 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
412 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
413 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
414 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
415 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
419 /******************************************************************************
420 * RegCreateKeyA [ADVAPI32.@]
422 * See RegCreateKeyW.
424 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
426 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
427 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
432 /******************************************************************************
433 * RegOpenKeyExW [ADVAPI32.@]
435 * See RegOpenKeyExA.
437 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
439 OBJECT_ATTRIBUTES attr;
440 UNICODE_STRING nameW;
442 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
443 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
445 if (!retkey) return ERROR_INVALID_PARAMETER;
446 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
448 attr.Length = sizeof(attr);
449 attr.RootDirectory = hkey;
450 attr.ObjectName = &nameW;
451 attr.Attributes = 0;
452 attr.SecurityDescriptor = NULL;
453 attr.SecurityQualityOfService = NULL;
454 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
455 RtlInitUnicodeString( &nameW, name );
456 return RtlNtStatusToDosError( open_key( retkey, access, &attr ) );
460 /******************************************************************************
461 * RegOpenKeyExA [ADVAPI32.@]
463 * Open a registry key.
465 * PARAMS
466 * hkey [I] Handle of open key
467 * name [I] Name of subkey to open
468 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
469 * access [I] Security access mask
470 * retkey [O] Handle to open key
472 * RETURNS
473 * Success: ERROR_SUCCESS
474 * Failure: A standard Win32 error code. retkey is set to 0.
476 * NOTES
477 * Unlike RegCreateKeyExA(), this function will not create the key if it
478 * does not exist.
480 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
482 OBJECT_ATTRIBUTES attr;
483 STRING nameA;
484 NTSTATUS status;
486 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
487 else
489 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
490 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
493 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
495 attr.Length = sizeof(attr);
496 attr.RootDirectory = hkey;
497 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
498 attr.Attributes = 0;
499 attr.SecurityDescriptor = NULL;
500 attr.SecurityQualityOfService = NULL;
501 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
503 RtlInitAnsiString( &nameA, name );
504 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
505 &nameA, FALSE )))
507 status = open_key( retkey, access, &attr );
509 return RtlNtStatusToDosError( status );
513 /******************************************************************************
514 * RegOpenKeyW [ADVAPI32.@]
516 * See RegOpenKeyA.
518 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
520 if (!retkey)
521 return ERROR_INVALID_PARAMETER;
523 if (!name || !*name)
525 *retkey = hkey;
526 return ERROR_SUCCESS;
528 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
532 /******************************************************************************
533 * RegOpenKeyA [ADVAPI32.@]
535 * Open a registry key.
537 * PARAMS
538 * hkey [I] Handle of parent key to open the new key under
539 * name [I] Name of the key under hkey to open
540 * retkey [O] Destination for the resulting Handle
542 * RETURNS
543 * Success: ERROR_SUCCESS
544 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
546 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
548 if (!retkey)
549 return ERROR_INVALID_PARAMETER;
551 if (!name || !*name)
553 *retkey = hkey;
554 return ERROR_SUCCESS;
556 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
560 /******************************************************************************
561 * RegOpenCurrentUser [ADVAPI32.@]
563 * Get a handle to the HKEY_CURRENT_USER key for the user
564 * the current thread is impersonating.
566 * PARAMS
567 * access [I] Desired access rights to the key
568 * retkey [O] Handle to the opened key
570 * RETURNS
571 * Success: ERROR_SUCCESS
572 * Failure: nonzero error code from Winerror.h
574 * FIXME
575 * This function is supposed to retrieve a handle to the
576 * HKEY_CURRENT_USER for the user the current thread is impersonating.
577 * Since Wine does not currently allow threads to impersonate other users,
578 * this stub should work fine.
580 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
582 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
587 /******************************************************************************
588 * RegEnumKeyExW [ADVAPI32.@]
590 * Enumerate subkeys of the specified open registry key.
592 * PARAMS
593 * hkey [I] Handle to key to enumerate
594 * index [I] Index of subkey to enumerate
595 * name [O] Buffer for subkey name
596 * name_len [O] Size of subkey buffer
597 * reserved [I] Reserved
598 * class [O] Buffer for class string
599 * class_len [O] Size of class buffer
600 * ft [O] Time key last written to
602 * RETURNS
603 * Success: ERROR_SUCCESS
604 * Failure: System error code. If there are no more subkeys available, the
605 * function returns ERROR_NO_MORE_ITEMS.
607 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
608 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
610 NTSTATUS status;
611 char buffer[256], *buf_ptr = buffer;
612 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
613 DWORD total_size;
615 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
616 name_len ? *name_len : 0, reserved, class, class_len, ft );
618 if (reserved) return ERROR_INVALID_PARAMETER;
619 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
621 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
622 buffer, sizeof(buffer), &total_size );
624 while (status == STATUS_BUFFER_OVERFLOW)
626 /* retry with a dynamically allocated buffer */
627 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
628 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
629 return ERROR_NOT_ENOUGH_MEMORY;
630 info = (KEY_NODE_INFORMATION *)buf_ptr;
631 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
632 buf_ptr, total_size, &total_size );
635 if (!status)
637 DWORD len = info->NameLength / sizeof(WCHAR);
638 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
640 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
642 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
643 status = STATUS_BUFFER_OVERFLOW;
644 else
646 *name_len = len;
647 memcpy( name, info->Name, info->NameLength );
648 name[len] = 0;
649 if (class_len)
651 *class_len = cls_len;
652 if (class)
654 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
655 class[cls_len] = 0;
661 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
662 return RtlNtStatusToDosError( status );
666 /******************************************************************************
667 * RegEnumKeyExA [ADVAPI32.@]
669 * See RegEnumKeyExW.
671 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
672 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
674 NTSTATUS status;
675 char buffer[256], *buf_ptr = buffer;
676 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
677 DWORD total_size;
679 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
680 name_len ? *name_len : 0, reserved, class, class_len, ft );
682 if (reserved) return ERROR_INVALID_PARAMETER;
683 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
685 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
686 buffer, sizeof(buffer), &total_size );
688 while (status == STATUS_BUFFER_OVERFLOW)
690 /* retry with a dynamically allocated buffer */
691 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
692 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
693 return ERROR_NOT_ENOUGH_MEMORY;
694 info = (KEY_NODE_INFORMATION *)buf_ptr;
695 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
696 buf_ptr, total_size, &total_size );
699 if (!status)
701 DWORD len, cls_len;
703 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
704 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
705 info->ClassLength );
706 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
708 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
709 status = STATUS_BUFFER_OVERFLOW;
710 else
712 *name_len = len;
713 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
714 name[len] = 0;
715 if (class_len)
717 *class_len = cls_len;
718 if (class)
720 RtlUnicodeToMultiByteN( class, cls_len, NULL,
721 (WCHAR *)(buf_ptr + info->ClassOffset),
722 info->ClassLength );
723 class[cls_len] = 0;
729 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
730 return RtlNtStatusToDosError( status );
734 /******************************************************************************
735 * RegEnumKeyW [ADVAPI32.@]
737 * Enumerates subkeys of the specified open reg key.
739 * PARAMS
740 * hKey [I] Handle to an open key.
741 * dwIndex [I] Index of the subkey of hKey to retrieve.
742 * lpName [O] Name of the subkey.
743 * cchName [I] Size of lpName in TCHARS.
745 * RETURNS
746 * Success: ERROR_SUCCESS
747 * Failure: system error code. If there are no more subkeys available, the
748 * function returns ERROR_NO_MORE_ITEMS.
750 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
752 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
756 /******************************************************************************
757 * RegEnumKeyA [ADVAPI32.@]
759 * See RegEnumKeyW.
761 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
763 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
767 /******************************************************************************
768 * RegQueryInfoKeyW [ADVAPI32.@]
770 * Retrieves information about the specified registry key.
772 * PARAMS
773 * hkey [I] Handle to key to query
774 * class [O] Buffer for class string
775 * class_len [O] Size of class string buffer
776 * reserved [I] Reserved
777 * subkeys [O] Buffer for number of subkeys
778 * max_subkey [O] Buffer for longest subkey name length
779 * max_class [O] Buffer for longest class string length
780 * values [O] Buffer for number of value entries
781 * max_value [O] Buffer for longest value name length
782 * max_data [O] Buffer for longest value data length
783 * security [O] Buffer for security descriptor length
784 * modif [O] Modification time
786 * RETURNS
787 * Success: ERROR_SUCCESS
788 * Failure: system error code.
790 * NOTES
791 * - win95 allows class to be valid and class_len to be NULL
792 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
793 * - both allow class to be NULL and class_len to be NULL
794 * (it's hard to test validity, so test !NULL instead)
796 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
797 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
798 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
799 LPDWORD security, FILETIME *modif )
801 NTSTATUS status;
802 char buffer[256], *buf_ptr = buffer;
803 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
804 DWORD total_size;
806 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
807 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
809 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
810 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
812 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
813 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
815 if (class)
817 /* retry with a dynamically allocated buffer */
818 while (status == STATUS_BUFFER_OVERFLOW)
820 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
821 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
822 return ERROR_NOT_ENOUGH_MEMORY;
823 info = (KEY_FULL_INFORMATION *)buf_ptr;
824 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
827 if (status) goto done;
829 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
831 status = STATUS_BUFFER_OVERFLOW;
833 else
835 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
836 class[info->ClassLength/sizeof(WCHAR)] = 0;
839 else status = STATUS_SUCCESS;
841 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
842 if (subkeys) *subkeys = info->SubKeys;
843 if (max_subkey) *max_subkey = info->MaxNameLen;
844 if (max_class) *max_class = info->MaxClassLen;
845 if (values) *values = info->Values;
846 if (max_value) *max_value = info->MaxValueNameLen;
847 if (max_data) *max_data = info->MaxValueDataLen;
848 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
850 done:
851 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
852 return RtlNtStatusToDosError( status );
856 /******************************************************************************
857 * RegQueryMultipleValuesA [ADVAPI32.@]
859 * Retrieves the type and data for a list of value names associated with a key.
861 * PARAMS
862 * hKey [I] Handle to an open key.
863 * val_list [O] Array of VALENT structures that describes the entries.
864 * num_vals [I] Number of elements in val_list.
865 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
866 * ldwTotsize [I/O] Size of lpValueBuf.
868 * RETURNS
869 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
870 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
871 * bytes.
873 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
874 LPSTR lpValueBuf, LPDWORD ldwTotsize )
876 unsigned int i;
877 DWORD maxBytes = *ldwTotsize;
878 HRESULT status;
879 LPSTR bufptr = lpValueBuf;
880 *ldwTotsize = 0;
882 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
884 for(i=0; i < num_vals; ++i)
887 val_list[i].ve_valuelen=0;
888 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
889 if(status != ERROR_SUCCESS)
891 return status;
894 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
896 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
897 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
898 if(status != ERROR_SUCCESS)
900 return status;
903 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
905 bufptr += val_list[i].ve_valuelen;
908 *ldwTotsize += val_list[i].ve_valuelen;
910 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
914 /******************************************************************************
915 * RegQueryMultipleValuesW [ADVAPI32.@]
917 * See RegQueryMultipleValuesA.
919 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
920 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
922 unsigned int i;
923 DWORD maxBytes = *ldwTotsize;
924 HRESULT status;
925 LPSTR bufptr = (LPSTR)lpValueBuf;
926 *ldwTotsize = 0;
928 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
930 for(i=0; i < num_vals; ++i)
932 val_list[i].ve_valuelen=0;
933 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
934 if(status != ERROR_SUCCESS)
936 return status;
939 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
941 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
942 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
943 if(status != ERROR_SUCCESS)
945 return status;
948 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
950 bufptr += val_list[i].ve_valuelen;
953 *ldwTotsize += val_list[i].ve_valuelen;
955 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
958 /******************************************************************************
959 * RegQueryInfoKeyA [ADVAPI32.@]
961 * Retrieves information about a registry key.
963 * PARAMS
964 * hKey [I] Handle to an open key.
965 * lpClass [O] Class string of the key.
966 * lpcClass [I/O] size of lpClass.
967 * lpReserved [I] Reserved; must be NULL.
968 * lpcSubKeys [O] Number of subkeys contained by the key.
969 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
970 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
971 * class in TCHARS.
972 * lpcValues [O] Number of values associated with the key.
973 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
974 * lpcMaxValueLen [O] Longest data component among the key's values
975 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
976 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
978 * RETURNS
979 * Success: ERROR_SUCCESS
980 * Failure: nonzero error code from Winerror.h
982 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
983 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
984 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
985 LPDWORD security, FILETIME *modif )
987 NTSTATUS status;
988 char buffer[256], *buf_ptr = buffer;
989 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
990 DWORD total_size, len;
992 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
993 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
995 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
996 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
998 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
999 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1001 if (class || class_len)
1003 /* retry with a dynamically allocated buffer */
1004 while (status == STATUS_BUFFER_OVERFLOW)
1006 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1007 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1008 return ERROR_NOT_ENOUGH_MEMORY;
1009 info = (KEY_FULL_INFORMATION *)buf_ptr;
1010 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
1013 if (status) goto done;
1015 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
1016 if (class_len)
1018 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
1019 *class_len = len;
1021 if (class && !status)
1023 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
1024 info->ClassLength );
1025 class[len] = 0;
1028 else status = STATUS_SUCCESS;
1030 if (subkeys) *subkeys = info->SubKeys;
1031 if (max_subkey) *max_subkey = info->MaxNameLen;
1032 if (max_class) *max_class = info->MaxClassLen;
1033 if (values) *values = info->Values;
1034 if (max_value) *max_value = info->MaxValueNameLen;
1035 if (max_data) *max_data = info->MaxValueDataLen;
1036 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
1038 done:
1039 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1040 return RtlNtStatusToDosError( status );
1044 /******************************************************************************
1045 * RegCloseKey [ADVAPI32.@]
1047 * Close an open registry key.
1049 * PARAMS
1050 * hkey [I] Handle of key to close
1052 * RETURNS
1053 * Success: ERROR_SUCCESS
1054 * Failure: Error code
1056 LSTATUS WINAPI RegCloseKey( HKEY hkey )
1058 if (!hkey) return ERROR_INVALID_HANDLE;
1059 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
1060 return RtlNtStatusToDosError( NtClose( hkey ) );
1064 /******************************************************************************
1065 * RegDeleteKeyExW [ADVAPI32.@]
1067 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
1069 DWORD ret;
1070 HKEY tmp;
1072 if (!name) return ERROR_INVALID_PARAMETER;
1074 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1076 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1077 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
1079 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1080 RegCloseKey( tmp );
1082 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
1083 return ret;
1087 /******************************************************************************
1088 * RegDeleteKeyW [ADVAPI32.@]
1090 * See RegDeleteKeyA.
1092 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
1094 return RegDeleteKeyExW( hkey, name, 0, 0 );
1098 /******************************************************************************
1099 * RegDeleteKeyExA [ADVAPI32.@]
1101 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1103 DWORD ret;
1104 HKEY tmp;
1106 if (!name) return ERROR_INVALID_PARAMETER;
1108 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1110 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1111 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1113 if (!is_version_nt()) /* win95 does recursive key deletes */
1115 CHAR name[MAX_PATH];
1117 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
1119 if(RegDeleteKeyExA(tmp, name, access, reserved)) /* recurse */
1120 break;
1123 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1124 RegCloseKey( tmp );
1126 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1127 return ret;
1131 /******************************************************************************
1132 * RegDeleteKeyA [ADVAPI32.@]
1134 * Delete a registry key.
1136 * PARAMS
1137 * hkey [I] Handle to parent key containing the key to delete
1138 * name [I] Name of the key user hkey to delete
1140 * NOTES
1142 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1143 * right. In reality, it opens a new handle with DELETE access.
1145 * RETURNS
1146 * Success: ERROR_SUCCESS
1147 * Failure: Error code
1149 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1151 return RegDeleteKeyExA( hkey, name, 0, 0 );
1156 /******************************************************************************
1157 * RegSetValueExW [ADVAPI32.@]
1159 * Set the data and contents of a registry value.
1161 * PARAMS
1162 * hkey [I] Handle of key to set value for
1163 * name [I] Name of value to set
1164 * reserved [I] Reserved, must be zero
1165 * type [I] Type of the value being set
1166 * data [I] The new contents of the value to set
1167 * count [I] Size of data
1169 * RETURNS
1170 * Success: ERROR_SUCCESS
1171 * Failure: Error code
1173 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1174 DWORD type, CONST BYTE *data, DWORD count )
1176 UNICODE_STRING nameW;
1178 /* no need for version check, not implemented on win9x anyway */
1179 if (count && is_string(type))
1181 LPCWSTR str = (LPCWSTR)data;
1182 /* if user forgot to count terminating null, add it (yes NT does this) */
1183 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1184 count += sizeof(WCHAR);
1186 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1188 RtlInitUnicodeString( &nameW, name );
1189 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1193 /******************************************************************************
1194 * RegSetValueExA [ADVAPI32.@]
1196 * See RegSetValueExW.
1198 * NOTES
1199 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1200 * NT does definitely care (aj)
1202 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1203 CONST BYTE *data, DWORD count )
1205 ANSI_STRING nameA;
1206 UNICODE_STRING nameW;
1207 WCHAR *dataW = NULL;
1208 NTSTATUS status;
1210 if (!is_version_nt()) /* win95 */
1212 if (type == REG_SZ)
1214 if (!data) return ERROR_INVALID_PARAMETER;
1215 count = strlen((const char *)data) + 1;
1218 else if (count && is_string(type))
1220 /* if user forgot to count terminating null, add it (yes NT does this) */
1221 if (data[count-1] && !data[count]) count++;
1224 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1226 if (is_string( type )) /* need to convert to Unicode */
1228 DWORD lenW;
1229 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1230 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1231 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1232 count = lenW;
1233 data = (BYTE *)dataW;
1236 RtlInitAnsiString( &nameA, name );
1237 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1239 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1240 RtlFreeUnicodeString( &nameW );
1242 HeapFree( GetProcessHeap(), 0, dataW );
1243 return RtlNtStatusToDosError( status );
1247 /******************************************************************************
1248 * RegSetValueW [ADVAPI32.@]
1250 * Sets the data for the default or unnamed value of a reg key.
1252 * PARAMS
1253 * hKey [I] Handle to an open key.
1254 * lpSubKey [I] Name of a subkey of hKey.
1255 * dwType [I] Type of information to store.
1256 * lpData [I] String that contains the data to set for the default value.
1257 * cbData [I] Ignored.
1259 * RETURNS
1260 * Success: ERROR_SUCCESS
1261 * Failure: nonzero error code from Winerror.h
1263 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1265 HKEY subkey = hkey;
1266 DWORD ret;
1268 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1270 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1272 if (name && name[0]) /* need to create the subkey */
1274 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1277 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1278 (strlenW( data ) + 1) * sizeof(WCHAR) );
1279 if (subkey != hkey) RegCloseKey( subkey );
1280 return ret;
1284 /******************************************************************************
1285 * RegSetValueA [ADVAPI32.@]
1287 * See RegSetValueW.
1289 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1291 HKEY subkey = hkey;
1292 DWORD ret;
1294 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1296 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1298 if (name && name[0]) /* need to create the subkey */
1300 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1302 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1303 if (subkey != hkey) RegCloseKey( subkey );
1304 return ret;
1309 /******************************************************************************
1310 * RegQueryValueExW [ADVAPI32.@]
1312 * See RegQueryValueExA.
1314 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1315 LPBYTE data, LPDWORD count )
1317 NTSTATUS status;
1318 UNICODE_STRING name_str;
1319 DWORD total_size;
1320 char buffer[256], *buf_ptr = buffer;
1321 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1322 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1324 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1325 hkey, debugstr_w(name), reserved, type, data, count,
1326 (count && data) ? *count : 0 );
1328 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1329 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1331 RtlInitUnicodeString( &name_str, name );
1333 if (data) total_size = min( sizeof(buffer), *count + info_size );
1334 else
1336 total_size = info_size;
1337 if (count) *count = 0;
1340 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1341 buffer, total_size, &total_size );
1342 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1344 if (data)
1346 /* retry with a dynamically allocated buffer */
1347 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1349 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1350 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1351 return ERROR_NOT_ENOUGH_MEMORY;
1352 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1353 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1354 buf_ptr, total_size, &total_size );
1357 if (!status)
1359 memcpy( data, buf_ptr + info_size, total_size - info_size );
1360 /* if the type is REG_SZ and data is not 0-terminated
1361 * and there is enough space in the buffer NT appends a \0 */
1362 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1364 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1365 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1368 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1370 else status = STATUS_SUCCESS;
1372 if (type) *type = info->Type;
1373 if (count) *count = total_size - info_size;
1375 done:
1376 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1377 return RtlNtStatusToDosError(status);
1381 /******************************************************************************
1382 * RegQueryValueExA [ADVAPI32.@]
1384 * Get the type and contents of a specified value under with a key.
1386 * PARAMS
1387 * hkey [I] Handle of the key to query
1388 * name [I] Name of value under hkey to query
1389 * reserved [I] Reserved - must be NULL
1390 * type [O] Destination for the value type, or NULL if not required
1391 * data [O] Destination for the values contents, or NULL if not required
1392 * count [I/O] Size of data, updated with the number of bytes returned
1394 * RETURNS
1395 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1396 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1397 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1398 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1400 * NOTES
1401 * MSDN states that if data is too small it is partially filled. In reality
1402 * it remains untouched.
1404 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1405 LPBYTE data, LPDWORD count )
1407 NTSTATUS status;
1408 ANSI_STRING nameA;
1409 UNICODE_STRING nameW;
1410 DWORD total_size, datalen = 0;
1411 char buffer[256], *buf_ptr = buffer;
1412 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1413 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1415 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1416 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1418 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1419 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1421 if (count) datalen = *count;
1422 if (!data && count) *count = 0;
1424 /* this matches Win9x behaviour - NT sets *type to a random value */
1425 if (type) *type = REG_NONE;
1427 RtlInitAnsiString( &nameA, name );
1428 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1429 return RtlNtStatusToDosError(status);
1431 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1432 buffer, sizeof(buffer), &total_size );
1433 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1435 /* we need to fetch the contents for a string type even if not requested,
1436 * because we need to compute the length of the ASCII string. */
1437 if (data || is_string(info->Type))
1439 /* retry with a dynamically allocated buffer */
1440 while (status == STATUS_BUFFER_OVERFLOW)
1442 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1443 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1445 status = STATUS_NO_MEMORY;
1446 goto done;
1448 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1449 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1450 buf_ptr, total_size, &total_size );
1453 if (status) goto done;
1455 if (is_string(info->Type))
1457 DWORD len;
1459 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1460 total_size - info_size );
1461 if (data && len)
1463 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1464 else
1466 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1467 total_size - info_size );
1468 /* if the type is REG_SZ and data is not 0-terminated
1469 * and there is enough space in the buffer NT appends a \0 */
1470 if (len < datalen && data[len-1]) data[len] = 0;
1473 total_size = len + info_size;
1475 else if (data)
1477 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1478 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1481 else status = STATUS_SUCCESS;
1483 if (type) *type = info->Type;
1484 if (count) *count = total_size - info_size;
1486 done:
1487 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1488 RtlFreeUnicodeString( &nameW );
1489 return RtlNtStatusToDosError(status);
1493 /******************************************************************************
1494 * RegQueryValueW [ADVAPI32.@]
1496 * Retrieves the data associated with the default or unnamed value of a key.
1498 * PARAMS
1499 * hkey [I] Handle to an open key.
1500 * name [I] Name of the subkey of hKey.
1501 * data [O] Receives the string associated with the default value
1502 * of the key.
1503 * count [I/O] Size of lpValue in bytes.
1505 * RETURNS
1506 * Success: ERROR_SUCCESS
1507 * Failure: nonzero error code from Winerror.h
1509 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1511 DWORD ret;
1512 HKEY subkey = hkey;
1514 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1516 if (name && name[0])
1518 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1520 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1521 if (subkey != hkey) RegCloseKey( subkey );
1522 if (ret == ERROR_FILE_NOT_FOUND)
1524 /* return empty string if default value not found */
1525 if (data) *data = 0;
1526 if (count) *count = sizeof(WCHAR);
1527 ret = ERROR_SUCCESS;
1529 return ret;
1533 /******************************************************************************
1534 * RegQueryValueA [ADVAPI32.@]
1536 * See RegQueryValueW.
1538 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1540 DWORD ret;
1541 HKEY subkey = hkey;
1543 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1545 if (name && name[0])
1547 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1549 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1550 if (subkey != hkey) RegCloseKey( subkey );
1551 if (ret == ERROR_FILE_NOT_FOUND)
1553 /* return empty string if default value not found */
1554 if (data) *data = 0;
1555 if (count) *count = 1;
1556 ret = ERROR_SUCCESS;
1558 return ret;
1562 /******************************************************************************
1563 * ADVAPI_ApplyRestrictions [internal]
1565 * Helper function for RegGetValueA/W.
1567 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1568 DWORD cbData, PLONG ret )
1570 /* Check if the type is restricted by the passed flags */
1571 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1573 DWORD dwMask = 0;
1575 switch (dwType)
1577 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1578 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1579 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1580 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1581 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1582 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1583 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1586 if (dwFlags & dwMask)
1588 /* Type is not restricted, check for size mismatch */
1589 if (dwType == REG_BINARY)
1591 DWORD cbExpect = 0;
1593 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1594 cbExpect = 4;
1595 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1596 cbExpect = 8;
1598 if (cbExpect && cbData != cbExpect)
1599 *ret = ERROR_DATATYPE_MISMATCH;
1602 else *ret = ERROR_UNSUPPORTED_TYPE;
1607 /******************************************************************************
1608 * RegGetValueW [ADVAPI32.@]
1610 * Retrieves the type and data for a value name associated with a key,
1611 * optionally expanding its content and restricting its type.
1613 * PARAMS
1614 * hKey [I] Handle to an open key.
1615 * pszSubKey [I] Name of the subkey of hKey.
1616 * pszValue [I] Name of value under hKey/szSubKey to query.
1617 * dwFlags [I] Flags restricting the value type to retrieve.
1618 * pdwType [O] Destination for the values type, may be NULL.
1619 * pvData [O] Destination for the values content, may be NULL.
1620 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1621 * retrieve the whole content, including the trailing '\0'
1622 * for strings.
1624 * RETURNS
1625 * Success: ERROR_SUCCESS
1626 * Failure: nonzero error code from Winerror.h
1628 * NOTES
1629 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1630 * expanded and pdwType is set to REG_SZ instead.
1631 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1632 * without RRF_NOEXPAND is thus not allowed.
1633 * An exception is the case where RRF_RT_ANY is specified, because then
1634 * RRF_NOEXPAND is allowed.
1636 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1637 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1638 LPDWORD pcbData )
1640 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1641 PVOID pvBuf = NULL;
1642 LONG ret;
1644 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1645 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1646 pvData, pcbData, cbData);
1648 if (pvData && !pcbData)
1649 return ERROR_INVALID_PARAMETER;
1650 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1651 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1652 return ERROR_INVALID_PARAMETER;
1654 if (pszSubKey && pszSubKey[0])
1656 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1657 if (ret != ERROR_SUCCESS) return ret;
1660 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1662 /* If we are going to expand we need to read in the whole the value even
1663 * if the passed buffer was too small as the expanded string might be
1664 * smaller than the unexpanded one and could fit into cbData bytes. */
1665 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1666 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1668 do {
1669 HeapFree(GetProcessHeap(), 0, pvBuf);
1671 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1672 if (!pvBuf)
1674 ret = ERROR_NOT_ENOUGH_MEMORY;
1675 break;
1678 if (ret == ERROR_MORE_DATA || !pvData)
1679 ret = RegQueryValueExW(hKey, pszValue, NULL,
1680 &dwType, pvBuf, &cbData);
1681 else
1683 /* Even if cbData was large enough we have to copy the
1684 * string since ExpandEnvironmentStrings can't handle
1685 * overlapping buffers. */
1686 CopyMemory(pvBuf, pvData, cbData);
1689 /* Both the type or the value itself could have been modified in
1690 * between so we have to keep retrying until the buffer is large
1691 * enough or we no longer have to expand the value. */
1692 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1694 if (ret == ERROR_SUCCESS)
1696 /* Recheck dwType in case it changed since the first call */
1697 if (dwType == REG_EXPAND_SZ)
1699 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1700 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1701 dwType = REG_SZ;
1702 if(pvData && pcbData && cbData > *pcbData)
1703 ret = ERROR_MORE_DATA;
1705 else if (pvData)
1706 CopyMemory(pvData, pvBuf, *pcbData);
1709 HeapFree(GetProcessHeap(), 0, pvBuf);
1712 if (pszSubKey && pszSubKey[0])
1713 RegCloseKey(hKey);
1715 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1717 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1718 ZeroMemory(pvData, *pcbData);
1720 if (pdwType) *pdwType = dwType;
1721 if (pcbData) *pcbData = cbData;
1723 return ret;
1727 /******************************************************************************
1728 * RegGetValueA [ADVAPI32.@]
1730 * See RegGetValueW.
1732 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1733 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1734 LPDWORD pcbData )
1736 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1737 PVOID pvBuf = NULL;
1738 LONG ret;
1740 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1741 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1742 cbData);
1744 if (pvData && !pcbData)
1745 return ERROR_INVALID_PARAMETER;
1746 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1747 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1748 return ERROR_INVALID_PARAMETER;
1750 if (pszSubKey && pszSubKey[0])
1752 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1753 if (ret != ERROR_SUCCESS) return ret;
1756 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1758 /* If we are going to expand we need to read in the whole the value even
1759 * if the passed buffer was too small as the expanded string might be
1760 * smaller than the unexpanded one and could fit into cbData bytes. */
1761 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1762 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1764 do {
1765 HeapFree(GetProcessHeap(), 0, pvBuf);
1767 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1768 if (!pvBuf)
1770 ret = ERROR_NOT_ENOUGH_MEMORY;
1771 break;
1774 if (ret == ERROR_MORE_DATA || !pvData)
1775 ret = RegQueryValueExA(hKey, pszValue, NULL,
1776 &dwType, pvBuf, &cbData);
1777 else
1779 /* Even if cbData was large enough we have to copy the
1780 * string since ExpandEnvironmentStrings can't handle
1781 * overlapping buffers. */
1782 CopyMemory(pvBuf, pvData, cbData);
1785 /* Both the type or the value itself could have been modified in
1786 * between so we have to keep retrying until the buffer is large
1787 * enough or we no longer have to expand the value. */
1788 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1790 if (ret == ERROR_SUCCESS)
1792 /* Recheck dwType in case it changed since the first call */
1793 if (dwType == REG_EXPAND_SZ)
1795 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1796 pcbData ? *pcbData : 0);
1797 dwType = REG_SZ;
1798 if(pvData && pcbData && cbData > *pcbData)
1799 ret = ERROR_MORE_DATA;
1801 else if (pvData)
1802 CopyMemory(pvData, pvBuf, *pcbData);
1805 HeapFree(GetProcessHeap(), 0, pvBuf);
1808 if (pszSubKey && pszSubKey[0])
1809 RegCloseKey(hKey);
1811 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1813 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1814 ZeroMemory(pvData, *pcbData);
1816 if (pdwType) *pdwType = dwType;
1817 if (pcbData) *pcbData = cbData;
1819 return ret;
1823 /******************************************************************************
1824 * RegEnumValueW [ADVAPI32.@]
1826 * Enumerates the values for the specified open registry key.
1828 * PARAMS
1829 * hkey [I] Handle to key to query
1830 * index [I] Index of value to query
1831 * value [O] Value string
1832 * val_count [I/O] Size of value buffer (in wchars)
1833 * reserved [I] Reserved
1834 * type [O] Type code
1835 * data [O] Value data
1836 * count [I/O] Size of data buffer (in bytes)
1838 * RETURNS
1839 * Success: ERROR_SUCCESS
1840 * Failure: nonzero error code from Winerror.h
1843 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1844 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1846 NTSTATUS status;
1847 DWORD total_size;
1848 char buffer[256], *buf_ptr = buffer;
1849 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1850 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1852 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1853 hkey, index, value, val_count, reserved, type, data, count );
1855 /* NT only checks count, not val_count */
1856 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1857 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1859 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1860 if (data) total_size += *count;
1861 total_size = min( sizeof(buffer), total_size );
1863 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1864 buffer, total_size, &total_size );
1865 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1867 if (value || data)
1869 /* retry with a dynamically allocated buffer */
1870 while (status == STATUS_BUFFER_OVERFLOW)
1872 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1873 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1874 return ERROR_NOT_ENOUGH_MEMORY;
1875 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1876 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1877 buf_ptr, total_size, &total_size );
1880 if (status) goto done;
1882 if (value)
1884 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1886 status = STATUS_BUFFER_OVERFLOW;
1887 goto overflow;
1889 memcpy( value, info->Name, info->NameLength );
1890 *val_count = info->NameLength / sizeof(WCHAR);
1891 value[*val_count] = 0;
1894 if (data)
1896 if (total_size - info->DataOffset > *count)
1898 status = STATUS_BUFFER_OVERFLOW;
1899 goto overflow;
1901 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1902 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1904 /* if the type is REG_SZ and data is not 0-terminated
1905 * and there is enough space in the buffer NT appends a \0 */
1906 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1907 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1911 else status = STATUS_SUCCESS;
1913 overflow:
1914 if (type) *type = info->Type;
1915 if (count) *count = info->DataLength;
1917 done:
1918 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1919 return RtlNtStatusToDosError(status);
1923 /******************************************************************************
1924 * RegEnumValueA [ADVAPI32.@]
1926 * See RegEnumValueW.
1928 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1929 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1931 NTSTATUS status;
1932 DWORD total_size;
1933 char buffer[256], *buf_ptr = buffer;
1934 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1935 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1937 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1938 hkey, index, value, val_count, reserved, type, data, count );
1940 /* NT only checks count, not val_count */
1941 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1942 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1944 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1945 if (data) total_size += *count;
1946 total_size = min( sizeof(buffer), total_size );
1948 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1949 buffer, total_size, &total_size );
1950 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1952 /* we need to fetch the contents for a string type even if not requested,
1953 * because we need to compute the length of the ASCII string. */
1954 if (value || data || is_string(info->Type))
1956 /* retry with a dynamically allocated buffer */
1957 while (status == STATUS_BUFFER_OVERFLOW)
1959 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1960 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1961 return ERROR_NOT_ENOUGH_MEMORY;
1962 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1963 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1964 buf_ptr, total_size, &total_size );
1967 if (status) goto done;
1969 if (is_string(info->Type))
1971 DWORD len;
1972 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1973 total_size - info->DataOffset );
1974 if (data && len)
1976 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1977 else
1979 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1980 total_size - info->DataOffset );
1981 /* if the type is REG_SZ and data is not 0-terminated
1982 * and there is enough space in the buffer NT appends a \0 */
1983 if (len < *count && data[len-1]) data[len] = 0;
1986 info->DataLength = len;
1988 else if (data)
1990 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1991 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1994 if (value && !status)
1996 DWORD len;
1998 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1999 if (len >= *val_count)
2001 status = STATUS_BUFFER_OVERFLOW;
2002 if (*val_count)
2004 len = *val_count - 1;
2005 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2006 value[len] = 0;
2009 else
2011 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2012 value[len] = 0;
2013 *val_count = len;
2017 else status = STATUS_SUCCESS;
2019 if (type) *type = info->Type;
2020 if (count) *count = info->DataLength;
2022 done:
2023 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2024 return RtlNtStatusToDosError(status);
2029 /******************************************************************************
2030 * RegDeleteValueW [ADVAPI32.@]
2032 * See RegDeleteValueA.
2034 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2036 UNICODE_STRING nameW;
2038 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2040 RtlInitUnicodeString( &nameW, name );
2041 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2045 /******************************************************************************
2046 * RegDeleteValueA [ADVAPI32.@]
2048 * Delete a value from the registry.
2050 * PARAMS
2051 * hkey [I] Registry handle of the key holding the value
2052 * name [I] Name of the value under hkey to delete
2054 * RETURNS
2055 * Success: ERROR_SUCCESS
2056 * Failure: nonzero error code from Winerror.h
2058 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2060 ANSI_STRING nameA;
2061 UNICODE_STRING nameW;
2062 NTSTATUS status;
2064 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2066 RtlInitAnsiString( &nameA, name );
2067 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2069 status = NtDeleteValueKey( hkey, &nameW );
2070 RtlFreeUnicodeString( &nameW );
2072 return RtlNtStatusToDosError( status );
2076 /******************************************************************************
2077 * RegLoadKeyW [ADVAPI32.@]
2079 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2080 * registration information from a specified file into that subkey.
2082 * PARAMS
2083 * hkey [I] Handle of open key
2084 * subkey [I] Address of name of subkey
2085 * filename [I] Address of filename for registry information
2087 * RETURNS
2088 * Success: ERROR_SUCCESS
2089 * Failure: nonzero error code from Winerror.h
2091 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2093 OBJECT_ATTRIBUTES destkey, file;
2094 UNICODE_STRING subkeyW, filenameW;
2095 NTSTATUS status;
2097 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
2099 destkey.Length = sizeof(destkey);
2100 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2101 destkey.ObjectName = &subkeyW; /* name of the key */
2102 destkey.Attributes = 0;
2103 destkey.SecurityDescriptor = NULL;
2104 destkey.SecurityQualityOfService = NULL;
2105 RtlInitUnicodeString(&subkeyW, subkey);
2107 file.Length = sizeof(file);
2108 file.RootDirectory = NULL;
2109 file.ObjectName = &filenameW; /* file containing the hive */
2110 file.Attributes = OBJ_CASE_INSENSITIVE;
2111 file.SecurityDescriptor = NULL;
2112 file.SecurityQualityOfService = NULL;
2113 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2115 status = NtLoadKey(&destkey, &file);
2116 RtlFreeUnicodeString(&filenameW);
2117 return RtlNtStatusToDosError( status );
2121 /******************************************************************************
2122 * RegLoadKeyA [ADVAPI32.@]
2124 * See RegLoadKeyW.
2126 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2128 UNICODE_STRING subkeyW, filenameW;
2129 STRING subkeyA, filenameA;
2130 NTSTATUS status;
2131 LONG ret;
2133 RtlInitAnsiString(&subkeyA, subkey);
2134 RtlInitAnsiString(&filenameA, filename);
2136 RtlInitUnicodeString(&subkeyW, NULL);
2137 RtlInitUnicodeString(&filenameW, NULL);
2138 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2139 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2141 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2143 else ret = RtlNtStatusToDosError(status);
2144 RtlFreeUnicodeString(&subkeyW);
2145 RtlFreeUnicodeString(&filenameW);
2146 return ret;
2150 /******************************************************************************
2151 * RegSaveKeyW [ADVAPI32.@]
2153 * Save a key and all of its subkeys and values to a new file in the standard format.
2155 * PARAMS
2156 * hkey [I] Handle of key where save begins
2157 * lpFile [I] Address of filename to save to
2158 * sa [I] Address of security structure
2160 * RETURNS
2161 * Success: ERROR_SUCCESS
2162 * Failure: nonzero error code from Winerror.h
2164 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2166 static const WCHAR format[] =
2167 {'r','e','g','%','0','4','x','.','t','m','p',0};
2168 WCHAR buffer[MAX_PATH];
2169 int count = 0;
2170 LPWSTR nameW;
2171 DWORD ret, err;
2172 HANDLE handle;
2174 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2176 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2177 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2179 err = GetLastError();
2180 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2182 for (;;)
2184 snprintfW( nameW, 16, format, count++ );
2185 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2186 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2187 if (handle != INVALID_HANDLE_VALUE) break;
2188 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2190 /* Something gone haywire ? Please report if this happens abnormally */
2191 if (count >= 100)
2192 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);
2195 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2197 CloseHandle( handle );
2198 if (!ret)
2200 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2202 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2203 debugstr_w(file) );
2204 ret = GetLastError();
2207 if (ret) DeleteFileW( buffer );
2209 done:
2210 SetLastError( err ); /* restore last error code */
2211 return ret;
2215 /******************************************************************************
2216 * RegSaveKeyA [ADVAPI32.@]
2218 * See RegSaveKeyW.
2220 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2222 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2223 NTSTATUS status;
2224 STRING fileA;
2226 RtlInitAnsiString(&fileA, file);
2227 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2228 return RtlNtStatusToDosError( status );
2229 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2233 /******************************************************************************
2234 * RegRestoreKeyW [ADVAPI32.@]
2236 * Read the registry information from a file and copy it over a key.
2238 * PARAMS
2239 * hkey [I] Handle of key where restore begins
2240 * lpFile [I] Address of filename containing saved tree
2241 * dwFlags [I] Optional flags
2243 * RETURNS
2244 * Success: ERROR_SUCCESS
2245 * Failure: nonzero error code from Winerror.h
2247 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2249 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2251 /* It seems to do this check before the hkey check */
2252 if (!lpFile || !*lpFile)
2253 return ERROR_INVALID_PARAMETER;
2255 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2257 /* Check for file existence */
2259 return ERROR_SUCCESS;
2263 /******************************************************************************
2264 * RegRestoreKeyA [ADVAPI32.@]
2266 * See RegRestoreKeyW.
2268 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2270 UNICODE_STRING lpFileW;
2271 LONG ret;
2273 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2274 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2275 RtlFreeUnicodeString( &lpFileW );
2276 return ret;
2280 /******************************************************************************
2281 * RegUnLoadKeyW [ADVAPI32.@]
2283 * Unload a registry key and its subkeys from the registry.
2285 * PARAMS
2286 * hkey [I] Handle of open key
2287 * lpSubKey [I] Address of name of subkey to unload
2289 * RETURNS
2290 * Success: ERROR_SUCCESS
2291 * Failure: nonzero error code from Winerror.h
2293 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2295 DWORD ret;
2296 HKEY shkey;
2297 OBJECT_ATTRIBUTES attr;
2298 UNICODE_STRING subkey;
2300 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2302 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2303 if( ret )
2304 return ERROR_INVALID_PARAMETER;
2306 RtlInitUnicodeString(&subkey, lpSubKey);
2307 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2308 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2310 RegCloseKey(shkey);
2312 return ret;
2316 /******************************************************************************
2317 * RegUnLoadKeyA [ADVAPI32.@]
2319 * See RegUnLoadKeyW.
2321 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2323 UNICODE_STRING lpSubKeyW;
2324 LONG ret;
2326 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2327 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2328 RtlFreeUnicodeString( &lpSubKeyW );
2329 return ret;
2333 /******************************************************************************
2334 * RegReplaceKeyW [ADVAPI32.@]
2336 * Replace the file backing a registry key and all its subkeys with another file.
2338 * PARAMS
2339 * hkey [I] Handle of open key
2340 * lpSubKey [I] Address of name of subkey
2341 * lpNewFile [I] Address of filename for file with new data
2342 * lpOldFile [I] Address of filename for backup file
2344 * RETURNS
2345 * Success: ERROR_SUCCESS
2346 * Failure: nonzero error code from Winerror.h
2348 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2349 LPCWSTR lpOldFile )
2351 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2352 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2353 return ERROR_SUCCESS;
2357 /******************************************************************************
2358 * RegReplaceKeyA [ADVAPI32.@]
2360 * See RegReplaceKeyW.
2362 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2363 LPCSTR lpOldFile )
2365 UNICODE_STRING lpSubKeyW;
2366 UNICODE_STRING lpNewFileW;
2367 UNICODE_STRING lpOldFileW;
2368 LONG ret;
2370 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2371 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2372 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2373 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2374 RtlFreeUnicodeString( &lpOldFileW );
2375 RtlFreeUnicodeString( &lpNewFileW );
2376 RtlFreeUnicodeString( &lpSubKeyW );
2377 return ret;
2381 /******************************************************************************
2382 * RegSetKeySecurity [ADVAPI32.@]
2384 * Set the security of an open registry key.
2386 * PARAMS
2387 * hkey [I] Open handle of key to set
2388 * SecurityInfo [I] Descriptor contents
2389 * pSecurityDesc [I] Address of descriptor for key
2391 * RETURNS
2392 * Success: ERROR_SUCCESS
2393 * Failure: nonzero error code from Winerror.h
2395 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2396 PSECURITY_DESCRIPTOR pSecurityDesc )
2398 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2400 /* It seems to perform this check before the hkey check */
2401 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2402 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2403 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2404 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2405 /* Param OK */
2406 } else
2407 return ERROR_INVALID_PARAMETER;
2409 if (!pSecurityDesc)
2410 return ERROR_INVALID_PARAMETER;
2412 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2414 return ERROR_SUCCESS;
2418 /******************************************************************************
2419 * RegGetKeySecurity [ADVAPI32.@]
2421 * Get a copy of the security descriptor for a given registry key.
2423 * PARAMS
2424 * hkey [I] Open handle of key to set
2425 * SecurityInformation [I] Descriptor contents
2426 * pSecurityDescriptor [O] Address of descriptor for key
2427 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2429 * RETURNS
2430 * Success: ERROR_SUCCESS
2431 * Failure: Error code
2433 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2434 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2435 LPDWORD lpcbSecurityDescriptor )
2437 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2438 *lpcbSecurityDescriptor);
2440 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2442 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2443 SecurityInformation, pSecurityDescriptor,
2444 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2448 /******************************************************************************
2449 * RegFlushKey [ADVAPI32.@]
2451 * Immediately write a registry key to registry.
2453 * PARAMS
2454 * hkey [I] Handle of key to write
2456 * RETURNS
2457 * Success: ERROR_SUCCESS
2458 * Failure: Error code
2460 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2462 hkey = get_special_root_hkey( hkey );
2463 if (!hkey) return ERROR_INVALID_HANDLE;
2465 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2469 /******************************************************************************
2470 * RegConnectRegistryW [ADVAPI32.@]
2472 * Establish a connection to a predefined registry key on another computer.
2474 * PARAMS
2475 * lpMachineName [I] Address of name of remote computer
2476 * hHey [I] Predefined registry handle
2477 * phkResult [I] Address of buffer for remote registry handle
2479 * RETURNS
2480 * Success: ERROR_SUCCESS
2481 * Failure: nonzero error code from Winerror.h
2483 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2484 PHKEY phkResult )
2486 LONG ret;
2488 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2490 if (!lpMachineName || !*lpMachineName) {
2491 /* Use the local machine name */
2492 ret = RegOpenKeyW( hKey, NULL, phkResult );
2494 else {
2495 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2496 DWORD len = sizeof(compName) / sizeof(WCHAR);
2498 /* MSDN says lpMachineName must start with \\ : not so */
2499 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2500 lpMachineName += 2;
2501 if (GetComputerNameW(compName, &len))
2503 if (!strcmpiW(lpMachineName, compName))
2504 ret = RegOpenKeyW(hKey, NULL, phkResult);
2505 else
2507 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2508 ret = ERROR_BAD_NETPATH;
2511 else
2512 ret = GetLastError();
2514 return ret;
2518 /******************************************************************************
2519 * RegConnectRegistryA [ADVAPI32.@]
2521 * See RegConnectRegistryW.
2523 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2525 UNICODE_STRING machineW;
2526 LONG ret;
2528 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2529 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2530 RtlFreeUnicodeString( &machineW );
2531 return ret;
2535 /******************************************************************************
2536 * RegNotifyChangeKeyValue [ADVAPI32.@]
2538 * Notify the caller about changes to the attributes or contents of a registry key.
2540 * PARAMS
2541 * hkey [I] Handle of key to watch
2542 * fWatchSubTree [I] Flag for subkey notification
2543 * fdwNotifyFilter [I] Changes to be reported
2544 * hEvent [I] Handle of signaled event
2545 * fAsync [I] Flag for asynchronous reporting
2547 * RETURNS
2548 * Success: ERROR_SUCCESS
2549 * Failure: nonzero error code from Winerror.h
2551 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2552 DWORD fdwNotifyFilter, HANDLE hEvent,
2553 BOOL fAsync )
2555 NTSTATUS status;
2556 IO_STATUS_BLOCK iosb;
2558 hkey = get_special_root_hkey( hkey );
2559 if (!hkey) return ERROR_INVALID_HANDLE;
2561 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2562 hEvent, fAsync);
2564 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2565 fdwNotifyFilter, fAsync, NULL, 0,
2566 fWatchSubTree);
2568 if (status && status != STATUS_TIMEOUT)
2569 return RtlNtStatusToDosError( status );
2571 return ERROR_SUCCESS;
2574 /******************************************************************************
2575 * RegOpenUserClassesRoot [ADVAPI32.@]
2577 * Open the HKEY_CLASSES_ROOT key for a user.
2579 * PARAMS
2580 * hToken [I] Handle of token representing the user
2581 * dwOptions [I] Reserved, must be 0
2582 * samDesired [I] Desired access rights
2583 * phkResult [O] Destination for the resulting key handle
2585 * RETURNS
2586 * Success: ERROR_SUCCESS
2587 * Failure: nonzero error code from Winerror.h
2589 * NOTES
2590 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2591 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2592 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2594 LSTATUS WINAPI RegOpenUserClassesRoot(
2595 HANDLE hToken,
2596 DWORD dwOptions,
2597 REGSAM samDesired,
2598 PHKEY phkResult
2601 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2603 *phkResult = HKEY_CLASSES_ROOT;
2604 return ERROR_SUCCESS;
2607 /******************************************************************************
2608 * load_string [Internal]
2610 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2611 * avoid importing user32, which is higher level than advapi32. Helper for
2612 * RegLoadMUIString.
2614 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2616 HGLOBAL hMemory;
2617 HRSRC hResource;
2618 WCHAR *pString;
2619 int idxString;
2621 /* Negative values have to be inverted. */
2622 if (HIWORD(resId) == 0xffff)
2623 resId = (UINT)(-((INT)resId));
2625 /* Load the resource into memory and get a pointer to it. */
2626 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2627 if (!hResource) return 0;
2628 hMemory = LoadResource(hModule, hResource);
2629 if (!hMemory) return 0;
2630 pString = LockResource(hMemory);
2632 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2633 idxString = resId & 0xf;
2634 while (idxString--) pString += *pString + 1;
2636 /* If no buffer is given, return length of the string. */
2637 if (!pwszBuffer) return *pString;
2639 /* Else copy over the string, respecting the buffer size. */
2640 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2641 if (cMaxChars >= 0) {
2642 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2643 pwszBuffer[cMaxChars] = '\0';
2646 return cMaxChars;
2649 /******************************************************************************
2650 * RegLoadMUIStringW [ADVAPI32.@]
2652 * Load the localized version of a string resource from some PE, respective
2653 * id and path of which are given in the registry value in the format
2654 * @[path]\dllname,-resourceId
2656 * PARAMS
2657 * hKey [I] Key, of which to load the string value from.
2658 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2659 * pszBuffer [O] Buffer to store the localized string in.
2660 * cbBuffer [I] Size of the destination buffer in bytes.
2661 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2662 * dwFlags [I] None supported yet.
2663 * pszBaseDir [I] Not supported yet.
2665 * RETURNS
2666 * Success: ERROR_SUCCESS,
2667 * Failure: nonzero error code from winerror.h
2669 * NOTES
2670 * This is an API of Windows Vista, which wasn't available at the time this code
2671 * was written. We have to check for the correct behaviour once it's available.
2673 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2674 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2676 DWORD dwValueType, cbData;
2677 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2678 LONG result;
2680 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2681 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2682 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2684 /* Parameter sanity checks. */
2685 if (!hKey || !pwszBuffer)
2686 return ERROR_INVALID_PARAMETER;
2688 if (pwszBaseDir && *pwszBaseDir) {
2689 FIXME("BaseDir parameter not yet supported!\n");
2690 return ERROR_INVALID_PARAMETER;
2693 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2694 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2695 if (result != ERROR_SUCCESS) goto cleanup;
2696 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2697 result = ERROR_FILE_NOT_FOUND;
2698 goto cleanup;
2700 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2701 if (!pwszTempBuffer) {
2702 result = ERROR_NOT_ENOUGH_MEMORY;
2703 goto cleanup;
2705 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2706 if (result != ERROR_SUCCESS) goto cleanup;
2708 /* Expand environment variables, if appropriate, or copy the original string over. */
2709 if (dwValueType == REG_EXPAND_SZ) {
2710 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2711 if (!cbData) goto cleanup;
2712 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2713 if (!pwszExpandedBuffer) {
2714 result = ERROR_NOT_ENOUGH_MEMORY;
2715 goto cleanup;
2717 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2718 } else {
2719 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2720 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2723 /* If the value references a resource based string, parse the value and load the string.
2724 * Else just copy over the original value. */
2725 result = ERROR_SUCCESS;
2726 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2727 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2728 } else {
2729 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2730 UINT uiStringId;
2731 HMODULE hModule;
2733 /* Format of the expanded value is 'path_to_dll,-resId' */
2734 if (!pComma || pComma[1] != '-') {
2735 result = ERROR_BADKEY;
2736 goto cleanup;
2739 uiStringId = atoiW(pComma+2);
2740 *pComma = '\0';
2742 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2743 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2744 result = ERROR_BADKEY;
2745 FreeLibrary(hModule);
2748 cleanup:
2749 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2750 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2751 return result;
2754 /******************************************************************************
2755 * RegLoadMUIStringA [ADVAPI32.@]
2757 * See RegLoadMUIStringW
2759 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2760 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2762 UNICODE_STRING valueW, baseDirW;
2763 WCHAR *pwszBuffer;
2764 DWORD cbData = cbBuffer * sizeof(WCHAR);
2765 LONG result;
2767 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2768 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2769 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2770 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2772 result = ERROR_NOT_ENOUGH_MEMORY;
2773 goto cleanup;
2776 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2777 baseDirW.Buffer);
2779 if (result == ERROR_SUCCESS) {
2780 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2781 if (pcbData)
2782 *pcbData = cbData;
2785 cleanup:
2786 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2787 RtlFreeUnicodeString(&baseDirW);
2788 RtlFreeUnicodeString(&valueW);
2790 return result;
2793 /******************************************************************************
2794 * RegDisablePredefinedCache [ADVAPI32.@]
2796 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2798 * PARAMS
2799 * None.
2801 * RETURNS
2802 * Success: ERROR_SUCCESS
2803 * Failure: nonzero error code from Winerror.h
2805 * NOTES
2806 * This is useful for services that use impersonation.
2808 LSTATUS WINAPI RegDisablePredefinedCache(void)
2810 HKEY hkey_current_user;
2811 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2813 /* prevent caching of future requests */
2814 hkcu_cache_disabled = TRUE;
2816 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2818 if (hkey_current_user)
2819 NtClose( hkey_current_user );
2821 return ERROR_SUCCESS;
2824 /******************************************************************************
2825 * RegDeleteTreeW [ADVAPI32.@]
2828 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2830 LONG ret;
2831 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2832 DWORD dwMaxLen, dwSize;
2833 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2834 HKEY hSubKey = hKey;
2836 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2838 if(lpszSubKey)
2840 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2841 if (ret) return ret;
2844 /* Get highest length for keys, values */
2845 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2846 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2847 if (ret) goto cleanup;
2849 dwMaxSubkeyLen++;
2850 dwMaxValueLen++;
2851 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2852 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2854 /* Name too big: alloc a buffer for it */
2855 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2857 ret = ERROR_NOT_ENOUGH_MEMORY;
2858 goto cleanup;
2863 /* Recursively delete all the subkeys */
2864 while (TRUE)
2866 dwSize = dwMaxLen;
2867 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2868 NULL, NULL, NULL)) break;
2870 ret = RegDeleteTreeW(hSubKey, lpszName);
2871 if (ret) goto cleanup;
2874 if (lpszSubKey)
2875 ret = RegDeleteKeyW(hKey, lpszSubKey);
2876 else
2877 while (TRUE)
2879 dwSize = dwMaxLen;
2880 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2881 NULL, NULL, NULL, NULL)) break;
2883 ret = RegDeleteValueW(hKey, lpszName);
2884 if (ret) goto cleanup;
2887 cleanup:
2888 /* Free buffer if allocated */
2889 if (lpszName != szNameBuf)
2890 HeapFree( GetProcessHeap(), 0, lpszName);
2891 if(lpszSubKey)
2892 RegCloseKey(hSubKey);
2893 return ret;
2896 /******************************************************************************
2897 * RegDeleteTreeA [ADVAPI32.@]
2900 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2902 LONG ret;
2903 UNICODE_STRING lpszSubKeyW;
2905 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2906 else lpszSubKeyW.Buffer = NULL;
2907 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2908 RtlFreeUnicodeString( &lpszSubKeyW );
2909 return ret;