qmgr: Use proper method macros.
[wine.git] / dlls / advapi32 / registry.c
blobd3b8edf4eb1f694051e6ec62abf3fffd73ce7d36
1 /*
2 * Registry management
4 * Copyright (C) 1999 Alexandre Julliard
6 * Based on misc/registry.c code
7 * Copyright (C) 1996 Marcus Meissner
8 * Copyright (C) 1998 Matthew Becker
9 * Copyright (C) 1999 Sylvain St-Germain
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <stdio.h>
30 #include "ntstatus.h"
31 #define WIN32_NO_STATUS
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winreg.h"
35 #include "winerror.h"
36 #include "winternl.h"
37 #include "winuser.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(reg);
44 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
45 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
47 static const WCHAR name_CLASSES_ROOT[] =
48 {'M','a','c','h','i','n','e','\\',
49 'S','o','f','t','w','a','r','e','\\',
50 'C','l','a','s','s','e','s',0};
51 static const WCHAR name_LOCAL_MACHINE[] =
52 {'M','a','c','h','i','n','e',0};
53 static const WCHAR name_USERS[] =
54 {'U','s','e','r',0};
55 static const WCHAR name_PERFORMANCE_DATA[] =
56 {'P','e','r','f','D','a','t','a',0};
57 static const WCHAR name_CURRENT_CONFIG[] =
58 {'M','a','c','h','i','n','e','\\',
59 'S','y','s','t','e','m','\\',
60 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
61 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
62 'C','u','r','r','e','n','t',0};
63 static const WCHAR name_DYN_DATA[] =
64 {'D','y','n','D','a','t','a',0};
66 static const WCHAR * const root_key_names[] =
68 name_CLASSES_ROOT,
69 NULL, /* HKEY_CURRENT_USER is determined dynamically */
70 name_LOCAL_MACHINE,
71 name_USERS,
72 name_PERFORMANCE_DATA,
73 name_CURRENT_CONFIG,
74 name_DYN_DATA
77 #define NB_SPECIAL_ROOT_KEYS (sizeof(root_key_names)/sizeof(root_key_names[0]))
79 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
80 static BOOL hkcu_cache_disabled;
82 static const int is_win64 = (sizeof(void *) > sizeof(int));
84 /* check if value type needs string conversion (Ansi<->Unicode) */
85 static inline int is_string( DWORD type )
87 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
90 /* check if current version is NT or Win95 */
91 static inline int is_version_nt(void)
93 return !(GetVersion() & 0x80000000);
96 static BOOL is_wow6432node( const UNICODE_STRING *name )
98 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e'};
100 return (name->Length == sizeof(wow6432nodeW) &&
101 !memicmpW( name->Buffer, wow6432nodeW, sizeof(wow6432nodeW)/sizeof(WCHAR) ));
104 /* open the Wow6432Node subkey of the specified key */
105 static HANDLE open_wow6432node( HANDLE key, const UNICODE_STRING *name )
107 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
108 OBJECT_ATTRIBUTES attr;
109 UNICODE_STRING nameW;
110 HANDLE ret;
112 attr.Length = sizeof(attr);
113 attr.RootDirectory = key;
114 attr.ObjectName = &nameW;
115 attr.Attributes = 0;
116 attr.SecurityDescriptor = NULL;
117 attr.SecurityQualityOfService = NULL;
118 RtlInitUnicodeString( &nameW, wow6432nodeW );
119 if (NtOpenKey( &ret, MAXIMUM_ALLOWED, &attr )) ret = 0;
120 return ret;
123 /* wrapper for NtCreateKey that creates the key recursively if necessary */
124 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
125 const UNICODE_STRING *class, ULONG options, PULONG dispos )
127 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
128 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
130 if (!force_wow32) status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class, options, dispos );
132 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
134 HANDLE subkey, root = attr->RootDirectory;
135 WCHAR *buffer = attr->ObjectName->Buffer;
136 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
137 UNICODE_STRING str;
139 while (i < len && buffer[i] != '\\') i++;
140 if (i == len && !force_wow32) return status;
142 attrs = attr->Attributes;
143 attr->Attributes &= ~OBJ_OPENLINK;
144 attr->ObjectName = &str;
146 while (i < len)
148 str.Buffer = buffer + pos;
149 str.Length = (i - pos) * sizeof(WCHAR);
150 if (force_wow32 && pos)
152 if (is_wow6432node( &str )) force_wow32 = FALSE;
153 else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
155 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
156 attr->RootDirectory = subkey;
157 force_wow32 = FALSE;
160 status = NtCreateKey( &subkey, access, attr, 0, class,
161 options & ~REG_OPTION_CREATE_LINK, dispos );
162 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
163 if (status) return status;
164 attr->RootDirectory = subkey;
165 while (i < len && buffer[i] == '\\') i++;
166 pos = i;
167 while (i < len && buffer[i] != '\\') i++;
169 str.Buffer = buffer + pos;
170 str.Length = (i - pos) * sizeof(WCHAR);
171 attr->Attributes = attrs;
172 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, class, options, dispos );
173 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
175 return status;
178 /* wrapper for NtOpenKey to handle Wow6432 nodes */
179 static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
181 NTSTATUS status;
182 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
183 HANDLE subkey, root = attr->RootDirectory;
184 WCHAR *buffer = attr->ObjectName->Buffer;
185 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
186 UNICODE_STRING str;
188 if (!force_wow32) return NtOpenKey( (HANDLE *)retkey, access, attr );
190 if (len && buffer[0] == '\\') return STATUS_OBJECT_PATH_INVALID;
191 while (i < len && buffer[i] != '\\') i++;
192 attrs = attr->Attributes;
193 attr->Attributes &= ~OBJ_OPENLINK;
194 attr->ObjectName = &str;
196 while (i < len)
198 str.Buffer = buffer + pos;
199 str.Length = (i - pos) * sizeof(WCHAR);
200 if (force_wow32 && pos)
202 if (is_wow6432node( &str )) force_wow32 = FALSE;
203 else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
205 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
206 attr->RootDirectory = subkey;
207 force_wow32 = FALSE;
210 status = NtOpenKey( &subkey, access, attr );
211 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
212 if (status) return status;
213 attr->RootDirectory = subkey;
214 while (i < len && buffer[i] == '\\') i++;
215 pos = i;
216 while (i < len && buffer[i] != '\\') i++;
218 str.Buffer = buffer + pos;
219 str.Length = (i - pos) * sizeof(WCHAR);
220 attr->Attributes = attrs;
221 status = NtOpenKey( (PHANDLE)retkey, access, attr );
222 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
223 return status;
227 /* create one of the HKEY_* special root keys */
228 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
230 HKEY ret = 0;
231 int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
233 if (hkey == HKEY_CURRENT_USER)
235 if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
236 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
238 /* don't cache the key in the table if caching is disabled */
239 if (hkcu_cache_disabled)
240 return hkey;
242 else
244 OBJECT_ATTRIBUTES attr;
245 UNICODE_STRING name;
247 attr.Length = sizeof(attr);
248 attr.RootDirectory = 0;
249 attr.ObjectName = &name;
250 attr.Attributes = 0;
251 attr.SecurityDescriptor = NULL;
252 attr.SecurityQualityOfService = NULL;
253 RtlInitUnicodeString( &name, root_key_names[idx] );
254 if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0;
255 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
258 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
259 ret = hkey;
260 else
261 NtClose( hkey ); /* somebody beat us to it */
262 return ret;
265 /* map the hkey from special root to normal key if necessary */
266 static inline HKEY get_special_root_hkey( HKEY hkey )
268 HKEY ret = hkey;
270 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
272 if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
273 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED );
275 return ret;
279 /******************************************************************************
280 * RegOverridePredefKey [ADVAPI32.@]
282 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
284 HKEY old_key;
285 int idx;
287 if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST))
288 return ERROR_INVALID_PARAMETER;
289 idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
291 if (override)
293 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
294 GetCurrentProcess(), (HANDLE *)&override,
295 0, 0, DUPLICATE_SAME_ACCESS );
296 if (status) return RtlNtStatusToDosError( status );
299 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
300 if (old_key) NtClose( old_key );
301 return ERROR_SUCCESS;
305 /******************************************************************************
306 * RegCreateKeyExW [ADVAPI32.@]
308 * See RegCreateKeyExA.
310 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
311 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
312 PHKEY retkey, LPDWORD dispos )
314 OBJECT_ATTRIBUTES attr;
315 UNICODE_STRING nameW, classW;
317 if (reserved) return ERROR_INVALID_PARAMETER;
318 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
320 attr.Length = sizeof(attr);
321 attr.RootDirectory = hkey;
322 attr.ObjectName = &nameW;
323 attr.Attributes = 0;
324 attr.SecurityDescriptor = NULL;
325 attr.SecurityQualityOfService = NULL;
326 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
327 RtlInitUnicodeString( &nameW, name );
328 RtlInitUnicodeString( &classW, class );
330 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
334 /******************************************************************************
335 * RegCreateKeyExA [ADVAPI32.@]
337 * Open a registry key, creating it if it doesn't exist.
339 * PARAMS
340 * hkey [I] Handle of the parent registry key
341 * name [I] Name of the new key to open or create
342 * reserved [I] Reserved, pass 0
343 * class [I] The object type of the new key
344 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
345 * access [I] Access level desired
346 * sa [I] Security attributes for the key
347 * retkey [O] Destination for the resulting handle
348 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
350 * RETURNS
351 * Success: ERROR_SUCCESS.
352 * Failure: A standard Win32 error code. retkey remains untouched.
354 * FIXME
355 * MAXIMUM_ALLOWED in access mask not supported by server
357 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
358 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
359 PHKEY retkey, LPDWORD dispos )
361 OBJECT_ATTRIBUTES attr;
362 UNICODE_STRING classW;
363 ANSI_STRING nameA, classA;
364 NTSTATUS status;
366 if (reserved) return ERROR_INVALID_PARAMETER;
367 if (!is_version_nt())
369 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
370 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
372 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
374 attr.Length = sizeof(attr);
375 attr.RootDirectory = hkey;
376 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
377 attr.Attributes = 0;
378 attr.SecurityDescriptor = NULL;
379 attr.SecurityQualityOfService = NULL;
380 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
381 RtlInitAnsiString( &nameA, name );
382 RtlInitAnsiString( &classA, class );
384 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
385 &nameA, FALSE )))
387 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
389 status = create_key( retkey, access, &attr, &classW, options, dispos );
390 RtlFreeUnicodeString( &classW );
393 return RtlNtStatusToDosError( status );
397 /******************************************************************************
398 * RegCreateKeyW [ADVAPI32.@]
400 * Creates the specified reg key.
402 * PARAMS
403 * hKey [I] Handle to an open key.
404 * lpSubKey [I] Name of a key that will be opened or created.
405 * phkResult [O] Receives a handle to the opened or created key.
407 * RETURNS
408 * Success: ERROR_SUCCESS
409 * Failure: nonzero error code defined in Winerror.h
411 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
413 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
414 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
415 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
416 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
420 /******************************************************************************
421 * RegCreateKeyA [ADVAPI32.@]
423 * See RegCreateKeyW.
425 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
427 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
428 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
433 /******************************************************************************
434 * RegOpenKeyExW [ADVAPI32.@]
436 * See RegOpenKeyExA.
438 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
440 OBJECT_ATTRIBUTES attr;
441 UNICODE_STRING nameW;
443 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
444 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
446 if (!retkey) return ERROR_INVALID_PARAMETER;
447 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
449 attr.Length = sizeof(attr);
450 attr.RootDirectory = hkey;
451 attr.ObjectName = &nameW;
452 attr.Attributes = 0;
453 attr.SecurityDescriptor = NULL;
454 attr.SecurityQualityOfService = NULL;
455 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
456 RtlInitUnicodeString( &nameW, name );
457 return RtlNtStatusToDosError( open_key( retkey, access, &attr ) );
461 /******************************************************************************
462 * RegOpenKeyExA [ADVAPI32.@]
464 * Open a registry key.
466 * PARAMS
467 * hkey [I] Handle of open key
468 * name [I] Name of subkey to open
469 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
470 * access [I] Security access mask
471 * retkey [O] Handle to open key
473 * RETURNS
474 * Success: ERROR_SUCCESS
475 * Failure: A standard Win32 error code. retkey is set to 0.
477 * NOTES
478 * Unlike RegCreateKeyExA(), this function will not create the key if it
479 * does not exist.
481 LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
483 OBJECT_ATTRIBUTES attr;
484 STRING nameA;
485 NTSTATUS status;
487 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
488 else
490 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
491 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
494 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
496 attr.Length = sizeof(attr);
497 attr.RootDirectory = hkey;
498 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
499 attr.Attributes = 0;
500 attr.SecurityDescriptor = NULL;
501 attr.SecurityQualityOfService = NULL;
502 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
504 RtlInitAnsiString( &nameA, name );
505 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
506 &nameA, FALSE )))
508 status = open_key( retkey, access, &attr );
510 return RtlNtStatusToDosError( status );
514 /******************************************************************************
515 * RegOpenKeyW [ADVAPI32.@]
517 * See RegOpenKeyA.
519 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
521 if (!retkey)
522 return ERROR_INVALID_PARAMETER;
524 if (!name || !*name)
526 *retkey = hkey;
527 return ERROR_SUCCESS;
529 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
533 /******************************************************************************
534 * RegOpenKeyA [ADVAPI32.@]
536 * Open a registry key.
538 * PARAMS
539 * hkey [I] Handle of parent key to open the new key under
540 * name [I] Name of the key under hkey to open
541 * retkey [O] Destination for the resulting Handle
543 * RETURNS
544 * Success: ERROR_SUCCESS
545 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
547 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
549 if (!retkey)
550 return ERROR_INVALID_PARAMETER;
552 if (!name || !*name)
554 *retkey = hkey;
555 return ERROR_SUCCESS;
557 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
561 /******************************************************************************
562 * RegOpenCurrentUser [ADVAPI32.@]
564 * Get a handle to the HKEY_CURRENT_USER key for the user
565 * the current thread is impersonating.
567 * PARAMS
568 * access [I] Desired access rights to the key
569 * retkey [O] Handle to the opened key
571 * RETURNS
572 * Success: ERROR_SUCCESS
573 * Failure: nonzero error code from Winerror.h
575 * FIXME
576 * This function is supposed to retrieve a handle to the
577 * HKEY_CURRENT_USER for the user the current thread is impersonating.
578 * Since Wine does not currently allow threads to impersonate other users,
579 * this stub should work fine.
581 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
583 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
588 /******************************************************************************
589 * RegEnumKeyExW [ADVAPI32.@]
591 * Enumerate subkeys of the specified open registry key.
593 * PARAMS
594 * hkey [I] Handle to key to enumerate
595 * index [I] Index of subkey to enumerate
596 * name [O] Buffer for subkey name
597 * name_len [O] Size of subkey buffer
598 * reserved [I] Reserved
599 * class [O] Buffer for class string
600 * class_len [O] Size of class buffer
601 * ft [O] Time key last written to
603 * RETURNS
604 * Success: ERROR_SUCCESS
605 * Failure: System error code. If there are no more subkeys available, the
606 * function returns ERROR_NO_MORE_ITEMS.
608 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
609 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
611 NTSTATUS status;
612 char buffer[256], *buf_ptr = buffer;
613 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
614 DWORD total_size;
616 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
617 name_len ? *name_len : 0, reserved, class, class_len, ft );
619 if (reserved) return ERROR_INVALID_PARAMETER;
620 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
622 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
623 buffer, sizeof(buffer), &total_size );
625 while (status == STATUS_BUFFER_OVERFLOW)
627 /* retry with a dynamically allocated buffer */
628 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
629 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
630 return ERROR_NOT_ENOUGH_MEMORY;
631 info = (KEY_NODE_INFORMATION *)buf_ptr;
632 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
633 buf_ptr, total_size, &total_size );
636 if (!status)
638 DWORD len = info->NameLength / sizeof(WCHAR);
639 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
641 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
643 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
644 status = STATUS_BUFFER_OVERFLOW;
645 else
647 *name_len = len;
648 memcpy( name, info->Name, info->NameLength );
649 name[len] = 0;
650 if (class_len)
652 *class_len = cls_len;
653 if (class)
655 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
656 class[cls_len] = 0;
662 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
663 return RtlNtStatusToDosError( status );
667 /******************************************************************************
668 * RegEnumKeyExA [ADVAPI32.@]
670 * See RegEnumKeyExW.
672 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
673 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
675 NTSTATUS status;
676 char buffer[256], *buf_ptr = buffer;
677 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
678 DWORD total_size;
680 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
681 name_len ? *name_len : 0, reserved, class, class_len, ft );
683 if (reserved) return ERROR_INVALID_PARAMETER;
684 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
686 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
687 buffer, sizeof(buffer), &total_size );
689 while (status == STATUS_BUFFER_OVERFLOW)
691 /* retry with a dynamically allocated buffer */
692 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
693 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
694 return ERROR_NOT_ENOUGH_MEMORY;
695 info = (KEY_NODE_INFORMATION *)buf_ptr;
696 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
697 buf_ptr, total_size, &total_size );
700 if (!status)
702 DWORD len, cls_len;
704 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
705 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
706 info->ClassLength );
707 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
709 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
710 status = STATUS_BUFFER_OVERFLOW;
711 else
713 *name_len = len;
714 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
715 name[len] = 0;
716 if (class_len)
718 *class_len = cls_len;
719 if (class)
721 RtlUnicodeToMultiByteN( class, cls_len, NULL,
722 (WCHAR *)(buf_ptr + info->ClassOffset),
723 info->ClassLength );
724 class[cls_len] = 0;
730 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
731 return RtlNtStatusToDosError( status );
735 /******************************************************************************
736 * RegEnumKeyW [ADVAPI32.@]
738 * Enumerates subkeys of the specified open reg key.
740 * PARAMS
741 * hKey [I] Handle to an open key.
742 * dwIndex [I] Index of the subkey of hKey to retrieve.
743 * lpName [O] Name of the subkey.
744 * cchName [I] Size of lpName in TCHARS.
746 * RETURNS
747 * Success: ERROR_SUCCESS
748 * Failure: system error code. If there are no more subkeys available, the
749 * function returns ERROR_NO_MORE_ITEMS.
751 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
753 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
757 /******************************************************************************
758 * RegEnumKeyA [ADVAPI32.@]
760 * See RegEnumKeyW.
762 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
764 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
768 /******************************************************************************
769 * RegQueryInfoKeyW [ADVAPI32.@]
771 * Retrieves information about the specified registry key.
773 * PARAMS
774 * hkey [I] Handle to key to query
775 * class [O] Buffer for class string
776 * class_len [O] Size of class string buffer
777 * reserved [I] Reserved
778 * subkeys [O] Buffer for number of subkeys
779 * max_subkey [O] Buffer for longest subkey name length
780 * max_class [O] Buffer for longest class string length
781 * values [O] Buffer for number of value entries
782 * max_value [O] Buffer for longest value name length
783 * max_data [O] Buffer for longest value data length
784 * security [O] Buffer for security descriptor length
785 * modif [O] Modification time
787 * RETURNS
788 * Success: ERROR_SUCCESS
789 * Failure: system error code.
791 * NOTES
792 * - win95 allows class to be valid and class_len to be NULL
793 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
794 * - both allow class to be NULL and class_len to be NULL
795 * (it's hard to test validity, so test !NULL instead)
797 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
798 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
799 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
800 LPDWORD security, FILETIME *modif )
802 NTSTATUS status;
803 char buffer[256], *buf_ptr = buffer;
804 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
805 DWORD total_size;
807 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
808 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
810 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
811 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
813 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
814 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
816 if (class)
818 /* retry with a dynamically allocated buffer */
819 while (status == STATUS_BUFFER_OVERFLOW)
821 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
822 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
823 return ERROR_NOT_ENOUGH_MEMORY;
824 info = (KEY_FULL_INFORMATION *)buf_ptr;
825 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
828 if (status) goto done;
830 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
832 status = STATUS_BUFFER_OVERFLOW;
834 else
836 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
837 class[info->ClassLength/sizeof(WCHAR)] = 0;
840 else status = STATUS_SUCCESS;
842 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
843 if (subkeys) *subkeys = info->SubKeys;
844 if (max_subkey) *max_subkey = info->MaxNameLen;
845 if (max_class) *max_class = info->MaxClassLen;
846 if (values) *values = info->Values;
847 if (max_value) *max_value = info->MaxValueNameLen;
848 if (max_data) *max_data = info->MaxValueDataLen;
849 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
851 done:
852 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
853 return RtlNtStatusToDosError( status );
857 /******************************************************************************
858 * RegQueryMultipleValuesA [ADVAPI32.@]
860 * Retrieves the type and data for a list of value names associated with a key.
862 * PARAMS
863 * hKey [I] Handle to an open key.
864 * val_list [O] Array of VALENT structures that describes the entries.
865 * num_vals [I] Number of elements in val_list.
866 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
867 * ldwTotsize [I/O] Size of lpValueBuf.
869 * RETURNS
870 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
871 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
872 * bytes.
874 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
875 LPSTR lpValueBuf, LPDWORD ldwTotsize )
877 unsigned int i;
878 DWORD maxBytes = *ldwTotsize;
879 HRESULT status;
880 LPSTR bufptr = lpValueBuf;
881 *ldwTotsize = 0;
883 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
885 for(i=0; i < num_vals; ++i)
888 val_list[i].ve_valuelen=0;
889 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
890 if(status != ERROR_SUCCESS)
892 return status;
895 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
897 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
898 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
899 if(status != ERROR_SUCCESS)
901 return status;
904 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
906 bufptr += val_list[i].ve_valuelen;
909 *ldwTotsize += val_list[i].ve_valuelen;
911 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
915 /******************************************************************************
916 * RegQueryMultipleValuesW [ADVAPI32.@]
918 * See RegQueryMultipleValuesA.
920 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
921 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
923 unsigned int i;
924 DWORD maxBytes = *ldwTotsize;
925 HRESULT status;
926 LPSTR bufptr = (LPSTR)lpValueBuf;
927 *ldwTotsize = 0;
929 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
931 for(i=0; i < num_vals; ++i)
933 val_list[i].ve_valuelen=0;
934 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
935 if(status != ERROR_SUCCESS)
937 return status;
940 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
942 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
943 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
944 if(status != ERROR_SUCCESS)
946 return status;
949 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
951 bufptr += val_list[i].ve_valuelen;
954 *ldwTotsize += val_list[i].ve_valuelen;
956 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
959 /******************************************************************************
960 * RegQueryInfoKeyA [ADVAPI32.@]
962 * Retrieves information about a registry key.
964 * PARAMS
965 * hKey [I] Handle to an open key.
966 * lpClass [O] Class string of the key.
967 * lpcClass [I/O] size of lpClass.
968 * lpReserved [I] Reserved; must be NULL.
969 * lpcSubKeys [O] Number of subkeys contained by the key.
970 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
971 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
972 * class in TCHARS.
973 * lpcValues [O] Number of values associated with the key.
974 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
975 * lpcMaxValueLen [O] Longest data component among the key's values
976 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
977 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
979 * RETURNS
980 * Success: ERROR_SUCCESS
981 * Failure: nonzero error code from Winerror.h
983 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
984 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
985 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
986 LPDWORD security, FILETIME *modif )
988 NTSTATUS status;
989 char buffer[256], *buf_ptr = buffer;
990 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
991 DWORD total_size, len;
993 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
994 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
996 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
997 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
999 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
1000 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1002 if (class || class_len)
1004 /* retry with a dynamically allocated buffer */
1005 while (status == STATUS_BUFFER_OVERFLOW)
1007 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1008 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1009 return ERROR_NOT_ENOUGH_MEMORY;
1010 info = (KEY_FULL_INFORMATION *)buf_ptr;
1011 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
1014 if (status) goto done;
1016 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
1017 if (class_len)
1019 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
1020 *class_len = len;
1022 if (class && !status)
1024 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
1025 info->ClassLength );
1026 class[len] = 0;
1029 else status = STATUS_SUCCESS;
1031 if (subkeys) *subkeys = info->SubKeys;
1032 if (max_subkey) *max_subkey = info->MaxNameLen;
1033 if (max_class) *max_class = info->MaxClassLen;
1034 if (values) *values = info->Values;
1035 if (max_value) *max_value = info->MaxValueNameLen;
1036 if (max_data) *max_data = info->MaxValueDataLen;
1037 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
1039 done:
1040 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1041 return RtlNtStatusToDosError( status );
1045 /******************************************************************************
1046 * RegCloseKey [ADVAPI32.@]
1048 * Close an open registry key.
1050 * PARAMS
1051 * hkey [I] Handle of key to close
1053 * RETURNS
1054 * Success: ERROR_SUCCESS
1055 * Failure: Error code
1057 LSTATUS WINAPI RegCloseKey( HKEY hkey )
1059 if (!hkey) return ERROR_INVALID_HANDLE;
1060 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
1061 return RtlNtStatusToDosError( NtClose( hkey ) );
1065 /******************************************************************************
1066 * RegDeleteKeyExW [ADVAPI32.@]
1068 LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
1070 DWORD ret;
1071 HKEY tmp;
1073 if (!name) return ERROR_INVALID_PARAMETER;
1075 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1077 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1078 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
1080 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1081 RegCloseKey( tmp );
1083 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
1084 return ret;
1088 /******************************************************************************
1089 * RegDeleteKeyW [ADVAPI32.@]
1091 * See RegDeleteKeyA.
1093 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
1095 return RegDeleteKeyExW( hkey, name, 0, 0 );
1099 /******************************************************************************
1100 * RegDeleteKeyExA [ADVAPI32.@]
1102 LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
1104 DWORD ret;
1105 HKEY tmp;
1107 if (!name) return ERROR_INVALID_PARAMETER;
1109 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1111 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1112 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
1114 if (!is_version_nt()) /* win95 does recursive key deletes */
1116 CHAR sub[MAX_PATH];
1118 while(!RegEnumKeyA(tmp, 0, sub, sizeof(sub)))
1120 if(RegDeleteKeyExA(tmp, sub, access, reserved)) /* recurse */
1121 break;
1124 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1125 RegCloseKey( tmp );
1127 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
1128 return ret;
1132 /******************************************************************************
1133 * RegDeleteKeyA [ADVAPI32.@]
1135 * Delete a registry key.
1137 * PARAMS
1138 * hkey [I] Handle to parent key containing the key to delete
1139 * name [I] Name of the key user hkey to delete
1141 * NOTES
1143 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1144 * right. In reality, it opens a new handle with DELETE access.
1146 * RETURNS
1147 * Success: ERROR_SUCCESS
1148 * Failure: Error code
1150 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1152 return RegDeleteKeyExA( hkey, name, 0, 0 );
1157 /******************************************************************************
1158 * RegSetValueExW [ADVAPI32.@]
1160 * Set the data and contents of a registry value.
1162 * PARAMS
1163 * hkey [I] Handle of key to set value for
1164 * name [I] Name of value to set
1165 * reserved [I] Reserved, must be zero
1166 * type [I] Type of the value being set
1167 * data [I] The new contents of the value to set
1168 * count [I] Size of data
1170 * RETURNS
1171 * Success: ERROR_SUCCESS
1172 * Failure: Error code
1174 LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1175 DWORD type, CONST BYTE *data, DWORD count )
1177 UNICODE_STRING nameW;
1179 /* no need for version check, not implemented on win9x anyway */
1181 if (data && ((ULONG_PTR)data >> 16) == 0) return ERROR_NOACCESS;
1183 if (count && is_string(type))
1185 LPCWSTR str = (LPCWSTR)data;
1186 /* if user forgot to count terminating null, add it (yes NT does this) */
1187 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1188 count += sizeof(WCHAR);
1190 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1192 RtlInitUnicodeString( &nameW, name );
1193 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1197 /******************************************************************************
1198 * RegSetValueExA [ADVAPI32.@]
1200 * See RegSetValueExW.
1202 * NOTES
1203 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1204 * NT does definitely care (aj)
1206 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1207 CONST BYTE *data, DWORD count )
1209 ANSI_STRING nameA;
1210 UNICODE_STRING nameW;
1211 WCHAR *dataW = NULL;
1212 NTSTATUS status;
1214 if (!is_version_nt()) /* win95 */
1216 if (type == REG_SZ)
1218 if (!data) return ERROR_INVALID_PARAMETER;
1219 count = strlen((const char *)data) + 1;
1222 else if (count && is_string(type))
1224 /* if user forgot to count terminating null, add it (yes NT does this) */
1225 if (data[count-1] && !data[count]) count++;
1228 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1230 if (is_string( type )) /* need to convert to Unicode */
1232 DWORD lenW;
1233 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1234 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1235 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1236 count = lenW;
1237 data = (BYTE *)dataW;
1240 RtlInitAnsiString( &nameA, name );
1241 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1243 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1244 RtlFreeUnicodeString( &nameW );
1246 HeapFree( GetProcessHeap(), 0, dataW );
1247 return RtlNtStatusToDosError( status );
1251 /******************************************************************************
1252 * RegSetValueW [ADVAPI32.@]
1254 * Sets the data for the default or unnamed value of a reg key.
1256 * PARAMS
1257 * hKey [I] Handle to an open key.
1258 * lpSubKey [I] Name of a subkey of hKey.
1259 * dwType [I] Type of information to store.
1260 * lpData [I] String that contains the data to set for the default value.
1261 * cbData [I] Ignored.
1263 * RETURNS
1264 * Success: ERROR_SUCCESS
1265 * Failure: nonzero error code from Winerror.h
1267 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1269 HKEY subkey = hkey;
1270 DWORD ret;
1272 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1274 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1276 if (name && name[0]) /* need to create the subkey */
1278 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1281 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1282 (strlenW( data ) + 1) * sizeof(WCHAR) );
1283 if (subkey != hkey) RegCloseKey( subkey );
1284 return ret;
1288 /******************************************************************************
1289 * RegSetValueA [ADVAPI32.@]
1291 * See RegSetValueW.
1293 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1295 HKEY subkey = hkey;
1296 DWORD ret;
1298 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1300 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1302 if (name && name[0]) /* need to create the subkey */
1304 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1306 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1307 if (subkey != hkey) RegCloseKey( subkey );
1308 return ret;
1313 /******************************************************************************
1314 * RegQueryValueExW [ADVAPI32.@]
1316 * See RegQueryValueExA.
1318 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1319 LPBYTE data, LPDWORD count )
1321 NTSTATUS status;
1322 UNICODE_STRING name_str;
1323 DWORD total_size;
1324 char buffer[256], *buf_ptr = buffer;
1325 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1326 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1328 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1329 hkey, debugstr_w(name), reserved, type, data, count,
1330 (count && data) ? *count : 0 );
1332 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1333 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1335 RtlInitUnicodeString( &name_str, name );
1337 if (data) total_size = min( sizeof(buffer), *count + info_size );
1338 else
1340 total_size = info_size;
1341 if (count) *count = 0;
1344 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1345 buffer, total_size, &total_size );
1346 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1348 if (data)
1350 /* retry with a dynamically allocated buffer */
1351 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1353 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1354 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1355 return ERROR_NOT_ENOUGH_MEMORY;
1356 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1357 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1358 buf_ptr, total_size, &total_size );
1361 if (!status)
1363 memcpy( data, buf_ptr + info_size, total_size - info_size );
1364 /* if the type is REG_SZ and data is not 0-terminated
1365 * and there is enough space in the buffer NT appends a \0 */
1366 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1368 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1369 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1372 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1374 else status = STATUS_SUCCESS;
1376 if (type) *type = info->Type;
1377 if (count) *count = total_size - info_size;
1379 done:
1380 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1381 return RtlNtStatusToDosError(status);
1385 /******************************************************************************
1386 * RegQueryValueExA [ADVAPI32.@]
1388 * Get the type and contents of a specified value under with a key.
1390 * PARAMS
1391 * hkey [I] Handle of the key to query
1392 * name [I] Name of value under hkey to query
1393 * reserved [I] Reserved - must be NULL
1394 * type [O] Destination for the value type, or NULL if not required
1395 * data [O] Destination for the values contents, or NULL if not required
1396 * count [I/O] Size of data, updated with the number of bytes returned
1398 * RETURNS
1399 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1400 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1401 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1402 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1404 * NOTES
1405 * MSDN states that if data is too small it is partially filled. In reality
1406 * it remains untouched.
1408 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1409 LPBYTE data, LPDWORD count )
1411 NTSTATUS status;
1412 ANSI_STRING nameA;
1413 UNICODE_STRING nameW;
1414 DWORD total_size, datalen = 0;
1415 char buffer[256], *buf_ptr = buffer;
1416 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1417 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1419 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1420 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1422 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1423 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1425 if (count) datalen = *count;
1426 if (!data && count) *count = 0;
1428 /* this matches Win9x behaviour - NT sets *type to a random value */
1429 if (type) *type = REG_NONE;
1431 RtlInitAnsiString( &nameA, name );
1432 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1433 return RtlNtStatusToDosError(status);
1435 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1436 buffer, sizeof(buffer), &total_size );
1437 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1439 /* we need to fetch the contents for a string type even if not requested,
1440 * because we need to compute the length of the ASCII string. */
1441 if (data || is_string(info->Type))
1443 /* retry with a dynamically allocated buffer */
1444 while (status == STATUS_BUFFER_OVERFLOW)
1446 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1447 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1449 status = STATUS_NO_MEMORY;
1450 goto done;
1452 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1453 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1454 buf_ptr, total_size, &total_size );
1457 if (status) goto done;
1459 if (is_string(info->Type))
1461 DWORD len;
1463 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1464 total_size - info_size );
1465 if (data && len)
1467 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1468 else
1470 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1471 total_size - info_size );
1472 /* if the type is REG_SZ and data is not 0-terminated
1473 * and there is enough space in the buffer NT appends a \0 */
1474 if (len < datalen && data[len-1]) data[len] = 0;
1477 total_size = len + info_size;
1479 else if (data)
1481 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1482 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1485 else status = STATUS_SUCCESS;
1487 if (type) *type = info->Type;
1488 if (count) *count = total_size - info_size;
1490 done:
1491 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1492 RtlFreeUnicodeString( &nameW );
1493 return RtlNtStatusToDosError(status);
1497 /******************************************************************************
1498 * RegQueryValueW [ADVAPI32.@]
1500 * Retrieves the data associated with the default or unnamed value of a key.
1502 * PARAMS
1503 * hkey [I] Handle to an open key.
1504 * name [I] Name of the subkey of hKey.
1505 * data [O] Receives the string associated with the default value
1506 * of the key.
1507 * count [I/O] Size of lpValue in bytes.
1509 * RETURNS
1510 * Success: ERROR_SUCCESS
1511 * Failure: nonzero error code from Winerror.h
1513 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1515 DWORD ret;
1516 HKEY subkey = hkey;
1518 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1520 if (name && name[0])
1522 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1524 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1525 if (subkey != hkey) RegCloseKey( subkey );
1526 if (ret == ERROR_FILE_NOT_FOUND)
1528 /* return empty string if default value not found */
1529 if (data) *data = 0;
1530 if (count) *count = sizeof(WCHAR);
1531 ret = ERROR_SUCCESS;
1533 return ret;
1537 /******************************************************************************
1538 * RegQueryValueA [ADVAPI32.@]
1540 * See RegQueryValueW.
1542 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1544 DWORD ret;
1545 HKEY subkey = hkey;
1547 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1549 if (name && name[0])
1551 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1553 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1554 if (subkey != hkey) RegCloseKey( subkey );
1555 if (ret == ERROR_FILE_NOT_FOUND)
1557 /* return empty string if default value not found */
1558 if (data) *data = 0;
1559 if (count) *count = 1;
1560 ret = ERROR_SUCCESS;
1562 return ret;
1566 /******************************************************************************
1567 * ADVAPI_ApplyRestrictions [internal]
1569 * Helper function for RegGetValueA/W.
1571 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1572 DWORD cbData, PLONG ret )
1574 /* Check if the type is restricted by the passed flags */
1575 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1577 DWORD dwMask = 0;
1579 switch (dwType)
1581 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1582 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1583 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1584 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1585 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1586 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1587 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1590 if (dwFlags & dwMask)
1592 /* Type is not restricted, check for size mismatch */
1593 if (dwType == REG_BINARY)
1595 DWORD cbExpect = 0;
1597 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1598 cbExpect = 4;
1599 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1600 cbExpect = 8;
1602 if (cbExpect && cbData != cbExpect)
1603 *ret = ERROR_DATATYPE_MISMATCH;
1606 else *ret = ERROR_UNSUPPORTED_TYPE;
1611 /******************************************************************************
1612 * RegGetValueW [ADVAPI32.@]
1614 * Retrieves the type and data for a value name associated with a key,
1615 * optionally expanding its content and restricting its type.
1617 * PARAMS
1618 * hKey [I] Handle to an open key.
1619 * pszSubKey [I] Name of the subkey of hKey.
1620 * pszValue [I] Name of value under hKey/szSubKey to query.
1621 * dwFlags [I] Flags restricting the value type to retrieve.
1622 * pdwType [O] Destination for the values type, may be NULL.
1623 * pvData [O] Destination for the values content, may be NULL.
1624 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1625 * retrieve the whole content, including the trailing '\0'
1626 * for strings.
1628 * RETURNS
1629 * Success: ERROR_SUCCESS
1630 * Failure: nonzero error code from Winerror.h
1632 * NOTES
1633 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1634 * expanded and pdwType is set to REG_SZ instead.
1635 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1636 * without RRF_NOEXPAND is thus not allowed.
1637 * An exception is the case where RRF_RT_ANY is specified, because then
1638 * RRF_NOEXPAND is allowed.
1640 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1641 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1642 LPDWORD pcbData )
1644 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1645 PVOID pvBuf = NULL;
1646 LONG ret;
1648 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1649 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1650 pvData, pcbData, cbData);
1652 if (pvData && !pcbData)
1653 return ERROR_INVALID_PARAMETER;
1654 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1655 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1656 return ERROR_INVALID_PARAMETER;
1658 if (pszSubKey && pszSubKey[0])
1660 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1661 if (ret != ERROR_SUCCESS) return ret;
1664 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1666 /* If we are going to expand we need to read in the whole the value even
1667 * if the passed buffer was too small as the expanded string might be
1668 * smaller than the unexpanded one and could fit into cbData bytes. */
1669 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1670 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1672 do {
1673 HeapFree(GetProcessHeap(), 0, pvBuf);
1675 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1676 if (!pvBuf)
1678 ret = ERROR_NOT_ENOUGH_MEMORY;
1679 break;
1682 if (ret == ERROR_MORE_DATA || !pvData)
1683 ret = RegQueryValueExW(hKey, pszValue, NULL,
1684 &dwType, pvBuf, &cbData);
1685 else
1687 /* Even if cbData was large enough we have to copy the
1688 * string since ExpandEnvironmentStrings can't handle
1689 * overlapping buffers. */
1690 CopyMemory(pvBuf, pvData, cbData);
1693 /* Both the type or the value itself could have been modified in
1694 * between so we have to keep retrying until the buffer is large
1695 * enough or we no longer have to expand the value. */
1696 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1698 if (ret == ERROR_SUCCESS)
1700 /* Recheck dwType in case it changed since the first call */
1701 if (dwType == REG_EXPAND_SZ)
1703 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1704 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1705 dwType = REG_SZ;
1706 if(pvData && pcbData && cbData > *pcbData)
1707 ret = ERROR_MORE_DATA;
1709 else if (pvData)
1710 CopyMemory(pvData, pvBuf, *pcbData);
1713 HeapFree(GetProcessHeap(), 0, pvBuf);
1716 if (pszSubKey && pszSubKey[0])
1717 RegCloseKey(hKey);
1719 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1721 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1722 ZeroMemory(pvData, *pcbData);
1724 if (pdwType) *pdwType = dwType;
1725 if (pcbData) *pcbData = cbData;
1727 return ret;
1731 /******************************************************************************
1732 * RegGetValueA [ADVAPI32.@]
1734 * See RegGetValueW.
1736 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1737 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1738 LPDWORD pcbData )
1740 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1741 PVOID pvBuf = NULL;
1742 LONG ret;
1744 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1745 hKey, debugstr_a(pszSubKey), debugstr_a(pszValue), dwFlags,
1746 pdwType, pvData, pcbData, cbData);
1748 if (pvData && !pcbData)
1749 return ERROR_INVALID_PARAMETER;
1750 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1751 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1752 return ERROR_INVALID_PARAMETER;
1754 if (pszSubKey && pszSubKey[0])
1756 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1757 if (ret != ERROR_SUCCESS) return ret;
1760 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1762 /* If we are going to expand we need to read in the whole the value even
1763 * if the passed buffer was too small as the expanded string might be
1764 * smaller than the unexpanded one and could fit into cbData bytes. */
1765 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1766 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1768 do {
1769 HeapFree(GetProcessHeap(), 0, pvBuf);
1771 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1772 if (!pvBuf)
1774 ret = ERROR_NOT_ENOUGH_MEMORY;
1775 break;
1778 if (ret == ERROR_MORE_DATA || !pvData)
1779 ret = RegQueryValueExA(hKey, pszValue, NULL,
1780 &dwType, pvBuf, &cbData);
1781 else
1783 /* Even if cbData was large enough we have to copy the
1784 * string since ExpandEnvironmentStrings can't handle
1785 * overlapping buffers. */
1786 CopyMemory(pvBuf, pvData, cbData);
1789 /* Both the type or the value itself could have been modified in
1790 * between so we have to keep retrying until the buffer is large
1791 * enough or we no longer have to expand the value. */
1792 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1794 if (ret == ERROR_SUCCESS)
1796 /* Recheck dwType in case it changed since the first call */
1797 if (dwType == REG_EXPAND_SZ)
1799 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1800 pcbData ? *pcbData : 0);
1801 dwType = REG_SZ;
1802 if(pvData && pcbData && cbData > *pcbData)
1803 ret = ERROR_MORE_DATA;
1805 else if (pvData)
1806 CopyMemory(pvData, pvBuf, *pcbData);
1809 HeapFree(GetProcessHeap(), 0, pvBuf);
1812 if (pszSubKey && pszSubKey[0])
1813 RegCloseKey(hKey);
1815 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1817 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1818 ZeroMemory(pvData, *pcbData);
1820 if (pdwType) *pdwType = dwType;
1821 if (pcbData) *pcbData = cbData;
1823 return ret;
1827 /******************************************************************************
1828 * RegEnumValueW [ADVAPI32.@]
1830 * Enumerates the values for the specified open registry key.
1832 * PARAMS
1833 * hkey [I] Handle to key to query
1834 * index [I] Index of value to query
1835 * value [O] Value string
1836 * val_count [I/O] Size of value buffer (in wchars)
1837 * reserved [I] Reserved
1838 * type [O] Type code
1839 * data [O] Value data
1840 * count [I/O] Size of data buffer (in bytes)
1842 * RETURNS
1843 * Success: ERROR_SUCCESS
1844 * Failure: nonzero error code from Winerror.h
1847 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1848 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1850 NTSTATUS status;
1851 DWORD total_size;
1852 char buffer[256], *buf_ptr = buffer;
1853 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1854 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1856 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1857 hkey, index, value, val_count, reserved, type, data, count );
1859 /* NT only checks count, not val_count */
1860 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1861 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1863 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1864 if (data) total_size += *count;
1865 total_size = min( sizeof(buffer), total_size );
1867 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1868 buffer, total_size, &total_size );
1869 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1871 if (value || data)
1873 /* retry with a dynamically allocated buffer */
1874 while (status == STATUS_BUFFER_OVERFLOW)
1876 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1877 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1878 return ERROR_NOT_ENOUGH_MEMORY;
1879 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1880 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1881 buf_ptr, total_size, &total_size );
1884 if (status) goto done;
1886 if (value)
1888 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1890 status = STATUS_BUFFER_OVERFLOW;
1891 goto overflow;
1893 memcpy( value, info->Name, info->NameLength );
1894 *val_count = info->NameLength / sizeof(WCHAR);
1895 value[*val_count] = 0;
1898 if (data)
1900 if (total_size - info->DataOffset > *count)
1902 status = STATUS_BUFFER_OVERFLOW;
1903 goto overflow;
1905 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1906 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1908 /* if the type is REG_SZ and data is not 0-terminated
1909 * and there is enough space in the buffer NT appends a \0 */
1910 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1911 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1915 else status = STATUS_SUCCESS;
1917 overflow:
1918 if (type) *type = info->Type;
1919 if (count) *count = info->DataLength;
1921 done:
1922 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1923 return RtlNtStatusToDosError(status);
1927 /******************************************************************************
1928 * RegEnumValueA [ADVAPI32.@]
1930 * See RegEnumValueW.
1932 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1933 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1935 NTSTATUS status;
1936 DWORD total_size;
1937 char buffer[256], *buf_ptr = buffer;
1938 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1939 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1941 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1942 hkey, index, value, val_count, reserved, type, data, count );
1944 /* NT only checks count, not val_count */
1945 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1946 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1948 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1949 if (data) total_size += *count;
1950 total_size = min( sizeof(buffer), total_size );
1952 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1953 buffer, total_size, &total_size );
1954 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1956 /* we need to fetch the contents for a string type even if not requested,
1957 * because we need to compute the length of the ASCII string. */
1958 if (value || data || is_string(info->Type))
1960 /* retry with a dynamically allocated buffer */
1961 while (status == STATUS_BUFFER_OVERFLOW)
1963 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1964 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1965 return ERROR_NOT_ENOUGH_MEMORY;
1966 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1967 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1968 buf_ptr, total_size, &total_size );
1971 if (status) goto done;
1973 if (is_string(info->Type))
1975 DWORD len;
1976 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1977 total_size - info->DataOffset );
1978 if (data && len)
1980 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1981 else
1983 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1984 total_size - info->DataOffset );
1985 /* if the type is REG_SZ and data is not 0-terminated
1986 * and there is enough space in the buffer NT appends a \0 */
1987 if (len < *count && data[len-1]) data[len] = 0;
1990 info->DataLength = len;
1992 else if (data)
1994 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1995 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1998 if (value && !status)
2000 DWORD len;
2002 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2003 if (len >= *val_count)
2005 status = STATUS_BUFFER_OVERFLOW;
2006 if (*val_count)
2008 len = *val_count - 1;
2009 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2010 value[len] = 0;
2013 else
2015 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2016 value[len] = 0;
2017 *val_count = len;
2021 else status = STATUS_SUCCESS;
2023 if (type) *type = info->Type;
2024 if (count) *count = info->DataLength;
2026 done:
2027 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2028 return RtlNtStatusToDosError(status);
2033 /******************************************************************************
2034 * RegDeleteValueW [ADVAPI32.@]
2036 * See RegDeleteValueA.
2038 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2040 UNICODE_STRING nameW;
2042 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2044 RtlInitUnicodeString( &nameW, name );
2045 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2049 /******************************************************************************
2050 * RegDeleteValueA [ADVAPI32.@]
2052 * Delete a value from the registry.
2054 * PARAMS
2055 * hkey [I] Registry handle of the key holding the value
2056 * name [I] Name of the value under hkey to delete
2058 * RETURNS
2059 * Success: ERROR_SUCCESS
2060 * Failure: nonzero error code from Winerror.h
2062 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2064 ANSI_STRING nameA;
2065 UNICODE_STRING nameW;
2066 NTSTATUS status;
2068 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2070 RtlInitAnsiString( &nameA, name );
2071 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2073 status = NtDeleteValueKey( hkey, &nameW );
2074 RtlFreeUnicodeString( &nameW );
2076 return RtlNtStatusToDosError( status );
2080 /******************************************************************************
2081 * RegLoadKeyW [ADVAPI32.@]
2083 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2084 * registration information from a specified file into that subkey.
2086 * PARAMS
2087 * hkey [I] Handle of open key
2088 * subkey [I] Address of name of subkey
2089 * filename [I] Address of filename for registry information
2091 * RETURNS
2092 * Success: ERROR_SUCCESS
2093 * Failure: nonzero error code from Winerror.h
2095 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2097 OBJECT_ATTRIBUTES destkey, file;
2098 UNICODE_STRING subkeyW, filenameW;
2099 NTSTATUS status;
2101 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
2103 destkey.Length = sizeof(destkey);
2104 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2105 destkey.ObjectName = &subkeyW; /* name of the key */
2106 destkey.Attributes = 0;
2107 destkey.SecurityDescriptor = NULL;
2108 destkey.SecurityQualityOfService = NULL;
2109 RtlInitUnicodeString(&subkeyW, subkey);
2111 file.Length = sizeof(file);
2112 file.RootDirectory = NULL;
2113 file.ObjectName = &filenameW; /* file containing the hive */
2114 file.Attributes = OBJ_CASE_INSENSITIVE;
2115 file.SecurityDescriptor = NULL;
2116 file.SecurityQualityOfService = NULL;
2117 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2119 status = NtLoadKey(&destkey, &file);
2120 RtlFreeUnicodeString(&filenameW);
2121 return RtlNtStatusToDosError( status );
2125 /******************************************************************************
2126 * RegLoadKeyA [ADVAPI32.@]
2128 * See RegLoadKeyW.
2130 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2132 UNICODE_STRING subkeyW, filenameW;
2133 STRING subkeyA, filenameA;
2134 NTSTATUS status;
2135 LONG ret;
2137 RtlInitAnsiString(&subkeyA, subkey);
2138 RtlInitAnsiString(&filenameA, filename);
2140 RtlInitUnicodeString(&subkeyW, NULL);
2141 RtlInitUnicodeString(&filenameW, NULL);
2142 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2143 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2145 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2147 else ret = RtlNtStatusToDosError(status);
2148 RtlFreeUnicodeString(&subkeyW);
2149 RtlFreeUnicodeString(&filenameW);
2150 return ret;
2154 /******************************************************************************
2155 * RegSaveKeyW [ADVAPI32.@]
2157 * Save a key and all of its subkeys and values to a new file in the standard format.
2159 * PARAMS
2160 * hkey [I] Handle of key where save begins
2161 * lpFile [I] Address of filename to save to
2162 * sa [I] Address of security structure
2164 * RETURNS
2165 * Success: ERROR_SUCCESS
2166 * Failure: nonzero error code from Winerror.h
2168 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2170 static const WCHAR format[] =
2171 {'r','e','g','%','0','4','x','.','t','m','p',0};
2172 WCHAR buffer[MAX_PATH];
2173 int count = 0;
2174 LPWSTR nameW;
2175 DWORD ret, err;
2176 HANDLE handle;
2178 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2180 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2181 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2183 err = GetLastError();
2184 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2186 for (;;)
2188 snprintfW( nameW, 16, format, count++ );
2189 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2190 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2191 if (handle != INVALID_HANDLE_VALUE) break;
2192 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2194 /* Something gone haywire ? Please report if this happens abnormally */
2195 if (count >= 100)
2196 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);
2199 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2201 CloseHandle( handle );
2202 if (!ret)
2204 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2206 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2207 debugstr_w(file) );
2208 ret = GetLastError();
2211 if (ret) DeleteFileW( buffer );
2213 done:
2214 SetLastError( err ); /* restore last error code */
2215 return ret;
2219 /******************************************************************************
2220 * RegSaveKeyA [ADVAPI32.@]
2222 * See RegSaveKeyW.
2224 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2226 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2227 NTSTATUS status;
2228 STRING fileA;
2230 RtlInitAnsiString(&fileA, file);
2231 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2232 return RtlNtStatusToDosError( status );
2233 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2237 /******************************************************************************
2238 * RegRestoreKeyW [ADVAPI32.@]
2240 * Read the registry information from a file and copy it over a key.
2242 * PARAMS
2243 * hkey [I] Handle of key where restore begins
2244 * lpFile [I] Address of filename containing saved tree
2245 * dwFlags [I] Optional flags
2247 * RETURNS
2248 * Success: ERROR_SUCCESS
2249 * Failure: nonzero error code from Winerror.h
2251 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2253 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2255 /* It seems to do this check before the hkey check */
2256 if (!lpFile || !*lpFile)
2257 return ERROR_INVALID_PARAMETER;
2259 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2261 /* Check for file existence */
2263 return ERROR_SUCCESS;
2267 /******************************************************************************
2268 * RegRestoreKeyA [ADVAPI32.@]
2270 * See RegRestoreKeyW.
2272 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2274 UNICODE_STRING lpFileW;
2275 LONG ret;
2277 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2278 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2279 RtlFreeUnicodeString( &lpFileW );
2280 return ret;
2284 /******************************************************************************
2285 * RegUnLoadKeyW [ADVAPI32.@]
2287 * Unload a registry key and its subkeys from the registry.
2289 * PARAMS
2290 * hkey [I] Handle of open key
2291 * lpSubKey [I] Address of name of subkey to unload
2293 * RETURNS
2294 * Success: ERROR_SUCCESS
2295 * Failure: nonzero error code from Winerror.h
2297 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2299 DWORD ret;
2300 HKEY shkey;
2301 OBJECT_ATTRIBUTES attr;
2302 UNICODE_STRING subkey;
2304 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2306 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2307 if( ret )
2308 return ERROR_INVALID_PARAMETER;
2310 RtlInitUnicodeString(&subkey, lpSubKey);
2311 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2312 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2314 RegCloseKey(shkey);
2316 return ret;
2320 /******************************************************************************
2321 * RegUnLoadKeyA [ADVAPI32.@]
2323 * See RegUnLoadKeyW.
2325 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2327 UNICODE_STRING lpSubKeyW;
2328 LONG ret;
2330 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2331 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2332 RtlFreeUnicodeString( &lpSubKeyW );
2333 return ret;
2337 /******************************************************************************
2338 * RegReplaceKeyW [ADVAPI32.@]
2340 * Replace the file backing a registry key and all its subkeys with another file.
2342 * PARAMS
2343 * hkey [I] Handle of open key
2344 * lpSubKey [I] Address of name of subkey
2345 * lpNewFile [I] Address of filename for file with new data
2346 * lpOldFile [I] Address of filename for backup file
2348 * RETURNS
2349 * Success: ERROR_SUCCESS
2350 * Failure: nonzero error code from Winerror.h
2352 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2353 LPCWSTR lpOldFile )
2355 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2356 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2357 return ERROR_SUCCESS;
2361 /******************************************************************************
2362 * RegReplaceKeyA [ADVAPI32.@]
2364 * See RegReplaceKeyW.
2366 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2367 LPCSTR lpOldFile )
2369 UNICODE_STRING lpSubKeyW;
2370 UNICODE_STRING lpNewFileW;
2371 UNICODE_STRING lpOldFileW;
2372 LONG ret;
2374 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2375 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2376 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2377 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2378 RtlFreeUnicodeString( &lpOldFileW );
2379 RtlFreeUnicodeString( &lpNewFileW );
2380 RtlFreeUnicodeString( &lpSubKeyW );
2381 return ret;
2385 /******************************************************************************
2386 * RegSetKeySecurity [ADVAPI32.@]
2388 * Set the security of an open registry key.
2390 * PARAMS
2391 * hkey [I] Open handle of key to set
2392 * SecurityInfo [I] Descriptor contents
2393 * pSecurityDesc [I] Address of descriptor for key
2395 * RETURNS
2396 * Success: ERROR_SUCCESS
2397 * Failure: nonzero error code from Winerror.h
2399 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2400 PSECURITY_DESCRIPTOR pSecurityDesc )
2402 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2404 /* It seems to perform this check before the hkey check */
2405 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2406 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2407 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2408 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2409 /* Param OK */
2410 } else
2411 return ERROR_INVALID_PARAMETER;
2413 if (!pSecurityDesc)
2414 return ERROR_INVALID_PARAMETER;
2416 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2418 return ERROR_SUCCESS;
2422 /******************************************************************************
2423 * RegGetKeySecurity [ADVAPI32.@]
2425 * Get a copy of the security descriptor for a given registry key.
2427 * PARAMS
2428 * hkey [I] Open handle of key to set
2429 * SecurityInformation [I] Descriptor contents
2430 * pSecurityDescriptor [O] Address of descriptor for key
2431 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2433 * RETURNS
2434 * Success: ERROR_SUCCESS
2435 * Failure: Error code
2437 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2438 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2439 LPDWORD lpcbSecurityDescriptor )
2441 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2442 *lpcbSecurityDescriptor);
2444 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2446 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2447 SecurityInformation, pSecurityDescriptor,
2448 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2452 /******************************************************************************
2453 * RegFlushKey [ADVAPI32.@]
2455 * Immediately write a registry key to registry.
2457 * PARAMS
2458 * hkey [I] Handle of key to write
2460 * RETURNS
2461 * Success: ERROR_SUCCESS
2462 * Failure: Error code
2464 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2466 hkey = get_special_root_hkey( hkey );
2467 if (!hkey) return ERROR_INVALID_HANDLE;
2469 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2473 /******************************************************************************
2474 * RegConnectRegistryW [ADVAPI32.@]
2476 * Establish a connection to a predefined registry key on another computer.
2478 * PARAMS
2479 * lpMachineName [I] Address of name of remote computer
2480 * hHey [I] Predefined registry handle
2481 * phkResult [I] Address of buffer for remote registry handle
2483 * RETURNS
2484 * Success: ERROR_SUCCESS
2485 * Failure: nonzero error code from Winerror.h
2487 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2488 PHKEY phkResult )
2490 LONG ret;
2492 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName), hKey, phkResult);
2494 if (!lpMachineName || !*lpMachineName) {
2495 /* Use the local machine name */
2496 ret = RegOpenKeyW( hKey, NULL, phkResult );
2498 else {
2499 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2500 DWORD len = sizeof(compName) / sizeof(WCHAR);
2502 /* MSDN says lpMachineName must start with \\ : not so */
2503 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2504 lpMachineName += 2;
2505 if (GetComputerNameW(compName, &len))
2507 if (!strcmpiW(lpMachineName, compName))
2508 ret = RegOpenKeyW(hKey, NULL, phkResult);
2509 else
2511 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2512 ret = ERROR_BAD_NETPATH;
2515 else
2516 ret = GetLastError();
2518 return ret;
2522 /******************************************************************************
2523 * RegConnectRegistryA [ADVAPI32.@]
2525 * See RegConnectRegistryW.
2527 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2529 UNICODE_STRING machineW;
2530 LONG ret;
2532 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2533 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2534 RtlFreeUnicodeString( &machineW );
2535 return ret;
2539 /******************************************************************************
2540 * RegNotifyChangeKeyValue [ADVAPI32.@]
2542 * Notify the caller about changes to the attributes or contents of a registry key.
2544 * PARAMS
2545 * hkey [I] Handle of key to watch
2546 * fWatchSubTree [I] Flag for subkey notification
2547 * fdwNotifyFilter [I] Changes to be reported
2548 * hEvent [I] Handle of signaled event
2549 * fAsync [I] Flag for asynchronous reporting
2551 * RETURNS
2552 * Success: ERROR_SUCCESS
2553 * Failure: nonzero error code from Winerror.h
2555 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2556 DWORD fdwNotifyFilter, HANDLE hEvent,
2557 BOOL fAsync )
2559 NTSTATUS status;
2560 IO_STATUS_BLOCK iosb;
2562 hkey = get_special_root_hkey( hkey );
2563 if (!hkey) return ERROR_INVALID_HANDLE;
2565 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2566 hEvent, fAsync);
2568 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2569 fdwNotifyFilter, fAsync, NULL, 0,
2570 fWatchSubTree);
2572 if (status && status != STATUS_TIMEOUT)
2573 return RtlNtStatusToDosError( status );
2575 return ERROR_SUCCESS;
2578 /******************************************************************************
2579 * RegOpenUserClassesRoot [ADVAPI32.@]
2581 * Open the HKEY_CLASSES_ROOT key for a user.
2583 * PARAMS
2584 * hToken [I] Handle of token representing the user
2585 * dwOptions [I] Reserved, must be 0
2586 * samDesired [I] Desired access rights
2587 * phkResult [O] Destination for the resulting key handle
2589 * RETURNS
2590 * Success: ERROR_SUCCESS
2591 * Failure: nonzero error code from Winerror.h
2593 * NOTES
2594 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2595 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2596 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2598 LSTATUS WINAPI RegOpenUserClassesRoot(
2599 HANDLE hToken,
2600 DWORD dwOptions,
2601 REGSAM samDesired,
2602 PHKEY phkResult
2605 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2607 *phkResult = HKEY_CLASSES_ROOT;
2608 return ERROR_SUCCESS;
2611 /******************************************************************************
2612 * load_string [Internal]
2614 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2615 * avoid importing user32, which is higher level than advapi32. Helper for
2616 * RegLoadMUIString.
2618 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2620 HGLOBAL hMemory;
2621 HRSRC hResource;
2622 WCHAR *pString;
2623 int idxString;
2625 /* Negative values have to be inverted. */
2626 if (HIWORD(resId) == 0xffff)
2627 resId = (UINT)(-((INT)resId));
2629 /* Load the resource into memory and get a pointer to it. */
2630 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2631 if (!hResource) return 0;
2632 hMemory = LoadResource(hModule, hResource);
2633 if (!hMemory) return 0;
2634 pString = LockResource(hMemory);
2636 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2637 idxString = resId & 0xf;
2638 while (idxString--) pString += *pString + 1;
2640 /* If no buffer is given, return length of the string. */
2641 if (!pwszBuffer) return *pString;
2643 /* Else copy over the string, respecting the buffer size. */
2644 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2645 if (cMaxChars >= 0) {
2646 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2647 pwszBuffer[cMaxChars] = '\0';
2650 return cMaxChars;
2653 /******************************************************************************
2654 * RegLoadMUIStringW [ADVAPI32.@]
2656 * Load the localized version of a string resource from some PE, respective
2657 * id and path of which are given in the registry value in the format
2658 * @[path]\dllname,-resourceId
2660 * PARAMS
2661 * hKey [I] Key, of which to load the string value from.
2662 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2663 * pszBuffer [O] Buffer to store the localized string in.
2664 * cbBuffer [I] Size of the destination buffer in bytes.
2665 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2666 * dwFlags [I] None supported yet.
2667 * pszBaseDir [I] Not supported yet.
2669 * RETURNS
2670 * Success: ERROR_SUCCESS,
2671 * Failure: nonzero error code from winerror.h
2673 * NOTES
2674 * This is an API of Windows Vista, which wasn't available at the time this code
2675 * was written. We have to check for the correct behaviour once it's available.
2677 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2678 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2680 DWORD dwValueType, cbData;
2681 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2682 LONG result;
2684 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2685 "dwFlags = %d, pwszBaseDir = %s)\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2686 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2688 /* Parameter sanity checks. */
2689 if (!hKey || !pwszBuffer)
2690 return ERROR_INVALID_PARAMETER;
2692 if (pwszBaseDir && *pwszBaseDir) {
2693 FIXME("BaseDir parameter not yet supported!\n");
2694 return ERROR_INVALID_PARAMETER;
2697 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2698 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2699 if (result != ERROR_SUCCESS) goto cleanup;
2700 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2701 result = ERROR_FILE_NOT_FOUND;
2702 goto cleanup;
2704 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2705 if (!pwszTempBuffer) {
2706 result = ERROR_NOT_ENOUGH_MEMORY;
2707 goto cleanup;
2709 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2710 if (result != ERROR_SUCCESS) goto cleanup;
2712 /* Expand environment variables, if appropriate, or copy the original string over. */
2713 if (dwValueType == REG_EXPAND_SZ) {
2714 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2715 if (!cbData) goto cleanup;
2716 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2717 if (!pwszExpandedBuffer) {
2718 result = ERROR_NOT_ENOUGH_MEMORY;
2719 goto cleanup;
2721 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2722 } else {
2723 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2724 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2727 /* If the value references a resource based string, parse the value and load the string.
2728 * Else just copy over the original value. */
2729 result = ERROR_SUCCESS;
2730 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2731 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2732 } else {
2733 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2734 UINT uiStringId;
2735 HMODULE hModule;
2737 /* Format of the expanded value is 'path_to_dll,-resId' */
2738 if (!pComma || pComma[1] != '-') {
2739 result = ERROR_BADKEY;
2740 goto cleanup;
2743 uiStringId = atoiW(pComma+2);
2744 *pComma = '\0';
2746 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2747 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2748 result = ERROR_BADKEY;
2749 FreeLibrary(hModule);
2752 cleanup:
2753 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2754 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2755 return result;
2758 /******************************************************************************
2759 * RegLoadMUIStringA [ADVAPI32.@]
2761 * See RegLoadMUIStringW
2763 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2764 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2766 UNICODE_STRING valueW, baseDirW;
2767 WCHAR *pwszBuffer;
2768 DWORD cbData = cbBuffer * sizeof(WCHAR);
2769 LONG result;
2771 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2772 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2773 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2774 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2776 result = ERROR_NOT_ENOUGH_MEMORY;
2777 goto cleanup;
2780 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2781 baseDirW.Buffer);
2783 if (result == ERROR_SUCCESS) {
2784 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2785 if (pcbData)
2786 *pcbData = cbData;
2789 cleanup:
2790 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2791 RtlFreeUnicodeString(&baseDirW);
2792 RtlFreeUnicodeString(&valueW);
2794 return result;
2797 /******************************************************************************
2798 * RegDisablePredefinedCache [ADVAPI32.@]
2800 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2802 * PARAMS
2803 * None.
2805 * RETURNS
2806 * Success: ERROR_SUCCESS
2807 * Failure: nonzero error code from Winerror.h
2809 * NOTES
2810 * This is useful for services that use impersonation.
2812 LSTATUS WINAPI RegDisablePredefinedCache(void)
2814 HKEY hkey_current_user;
2815 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2817 /* prevent caching of future requests */
2818 hkcu_cache_disabled = TRUE;
2820 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2822 if (hkey_current_user)
2823 NtClose( hkey_current_user );
2825 return ERROR_SUCCESS;
2828 /******************************************************************************
2829 * RegDeleteTreeW [ADVAPI32.@]
2832 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2834 LONG ret;
2835 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2836 DWORD dwMaxLen, dwSize;
2837 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2838 HKEY hSubKey = hKey;
2840 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2842 if(lpszSubKey)
2844 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2845 if (ret) return ret;
2848 /* Get highest length for keys, values */
2849 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2850 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2851 if (ret) goto cleanup;
2853 dwMaxSubkeyLen++;
2854 dwMaxValueLen++;
2855 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2856 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2858 /* Name too big: alloc a buffer for it */
2859 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2861 ret = ERROR_NOT_ENOUGH_MEMORY;
2862 goto cleanup;
2867 /* Recursively delete all the subkeys */
2868 while (TRUE)
2870 dwSize = dwMaxLen;
2871 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2872 NULL, NULL, NULL)) break;
2874 ret = RegDeleteTreeW(hSubKey, lpszName);
2875 if (ret) goto cleanup;
2878 if (lpszSubKey)
2879 ret = RegDeleteKeyW(hKey, lpszSubKey);
2880 else
2881 while (TRUE)
2883 dwSize = dwMaxLen;
2884 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2885 NULL, NULL, NULL, NULL)) break;
2887 ret = RegDeleteValueW(hKey, lpszName);
2888 if (ret) goto cleanup;
2891 cleanup:
2892 /* Free buffer if allocated */
2893 if (lpszName != szNameBuf)
2894 HeapFree( GetProcessHeap(), 0, lpszName);
2895 if(lpszSubKey)
2896 RegCloseKey(hSubKey);
2897 return ret;
2900 /******************************************************************************
2901 * RegDeleteTreeA [ADVAPI32.@]
2904 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2906 LONG ret;
2907 UNICODE_STRING lpszSubKeyW;
2909 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2910 else lpszSubKeyW.Buffer = NULL;
2911 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2912 RtlFreeUnicodeString( &lpszSubKeyW );
2913 return ret;
2916 /******************************************************************************
2917 * RegDisableReflectionKey [ADVAPI32.@]
2920 LONG WINAPI RegDisableReflectionKey(HKEY base)
2922 FIXME("%p: stub\n", base);
2923 return ERROR_SUCCESS;