msi: Implement MSIMODIFY_MERGE function in TABLE_modify.
[wine.git] / dlls / advapi32 / registry.c
blobc4fef67ac54eecc88009e36c56bd6553a88bec25
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 name[MAX_PATH];
1118 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
1120 if(RegDeleteKeyExA(tmp, name, 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 */
1180 if (count && is_string(type))
1182 LPCWSTR str = (LPCWSTR)data;
1183 /* if user forgot to count terminating null, add it (yes NT does this) */
1184 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1185 count += sizeof(WCHAR);
1187 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1189 RtlInitUnicodeString( &nameW, name );
1190 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1194 /******************************************************************************
1195 * RegSetValueExA [ADVAPI32.@]
1197 * See RegSetValueExW.
1199 * NOTES
1200 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1201 * NT does definitely care (aj)
1203 LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1204 CONST BYTE *data, DWORD count )
1206 ANSI_STRING nameA;
1207 UNICODE_STRING nameW;
1208 WCHAR *dataW = NULL;
1209 NTSTATUS status;
1211 if (!is_version_nt()) /* win95 */
1213 if (type == REG_SZ)
1215 if (!data) return ERROR_INVALID_PARAMETER;
1216 count = strlen((const char *)data) + 1;
1219 else if (count && is_string(type))
1221 /* if user forgot to count terminating null, add it (yes NT does this) */
1222 if (data[count-1] && !data[count]) count++;
1225 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1227 if (is_string( type )) /* need to convert to Unicode */
1229 DWORD lenW;
1230 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1231 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1232 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1233 count = lenW;
1234 data = (BYTE *)dataW;
1237 RtlInitAnsiString( &nameA, name );
1238 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1240 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1241 RtlFreeUnicodeString( &nameW );
1243 HeapFree( GetProcessHeap(), 0, dataW );
1244 return RtlNtStatusToDosError( status );
1248 /******************************************************************************
1249 * RegSetValueW [ADVAPI32.@]
1251 * Sets the data for the default or unnamed value of a reg key.
1253 * PARAMS
1254 * hKey [I] Handle to an open key.
1255 * lpSubKey [I] Name of a subkey of hKey.
1256 * dwType [I] Type of information to store.
1257 * lpData [I] String that contains the data to set for the default value.
1258 * cbData [I] Ignored.
1260 * RETURNS
1261 * Success: ERROR_SUCCESS
1262 * Failure: nonzero error code from Winerror.h
1264 LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1266 HKEY subkey = hkey;
1267 DWORD ret;
1269 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1271 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1273 if (name && name[0]) /* need to create the subkey */
1275 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1278 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1279 (strlenW( data ) + 1) * sizeof(WCHAR) );
1280 if (subkey != hkey) RegCloseKey( subkey );
1281 return ret;
1285 /******************************************************************************
1286 * RegSetValueA [ADVAPI32.@]
1288 * See RegSetValueW.
1290 LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1292 HKEY subkey = hkey;
1293 DWORD ret;
1295 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1297 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1299 if (name && name[0]) /* need to create the subkey */
1301 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1303 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1304 if (subkey != hkey) RegCloseKey( subkey );
1305 return ret;
1310 /******************************************************************************
1311 * RegQueryValueExW [ADVAPI32.@]
1313 * See RegQueryValueExA.
1315 LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1316 LPBYTE data, LPDWORD count )
1318 NTSTATUS status;
1319 UNICODE_STRING name_str;
1320 DWORD total_size;
1321 char buffer[256], *buf_ptr = buffer;
1322 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1323 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1325 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1326 hkey, debugstr_w(name), reserved, type, data, count,
1327 (count && data) ? *count : 0 );
1329 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1330 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1332 RtlInitUnicodeString( &name_str, name );
1334 if (data) total_size = min( sizeof(buffer), *count + info_size );
1335 else
1337 total_size = info_size;
1338 if (count) *count = 0;
1341 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1342 buffer, total_size, &total_size );
1343 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1345 if (data)
1347 /* retry with a dynamically allocated buffer */
1348 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1350 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1351 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1352 return ERROR_NOT_ENOUGH_MEMORY;
1353 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1354 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1355 buf_ptr, total_size, &total_size );
1358 if (!status)
1360 memcpy( data, buf_ptr + info_size, total_size - info_size );
1361 /* if the type is REG_SZ and data is not 0-terminated
1362 * and there is enough space in the buffer NT appends a \0 */
1363 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1365 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1366 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1369 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1371 else status = STATUS_SUCCESS;
1373 if (type) *type = info->Type;
1374 if (count) *count = total_size - info_size;
1376 done:
1377 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1378 return RtlNtStatusToDosError(status);
1382 /******************************************************************************
1383 * RegQueryValueExA [ADVAPI32.@]
1385 * Get the type and contents of a specified value under with a key.
1387 * PARAMS
1388 * hkey [I] Handle of the key to query
1389 * name [I] Name of value under hkey to query
1390 * reserved [I] Reserved - must be NULL
1391 * type [O] Destination for the value type, or NULL if not required
1392 * data [O] Destination for the values contents, or NULL if not required
1393 * count [I/O] Size of data, updated with the number of bytes returned
1395 * RETURNS
1396 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1397 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1398 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1399 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1401 * NOTES
1402 * MSDN states that if data is too small it is partially filled. In reality
1403 * it remains untouched.
1405 LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1406 LPBYTE data, LPDWORD count )
1408 NTSTATUS status;
1409 ANSI_STRING nameA;
1410 UNICODE_STRING nameW;
1411 DWORD total_size, datalen = 0;
1412 char buffer[256], *buf_ptr = buffer;
1413 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1414 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1416 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1417 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1419 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1420 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1422 if (count) datalen = *count;
1423 if (!data && count) *count = 0;
1425 /* this matches Win9x behaviour - NT sets *type to a random value */
1426 if (type) *type = REG_NONE;
1428 RtlInitAnsiString( &nameA, name );
1429 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1430 return RtlNtStatusToDosError(status);
1432 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1433 buffer, sizeof(buffer), &total_size );
1434 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1436 /* we need to fetch the contents for a string type even if not requested,
1437 * because we need to compute the length of the ASCII string. */
1438 if (data || is_string(info->Type))
1440 /* retry with a dynamically allocated buffer */
1441 while (status == STATUS_BUFFER_OVERFLOW)
1443 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1444 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1446 status = STATUS_NO_MEMORY;
1447 goto done;
1449 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1450 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1451 buf_ptr, total_size, &total_size );
1454 if (status) goto done;
1456 if (is_string(info->Type))
1458 DWORD len;
1460 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1461 total_size - info_size );
1462 if (data && len)
1464 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1465 else
1467 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1468 total_size - info_size );
1469 /* if the type is REG_SZ and data is not 0-terminated
1470 * and there is enough space in the buffer NT appends a \0 */
1471 if (len < datalen && data[len-1]) data[len] = 0;
1474 total_size = len + info_size;
1476 else if (data)
1478 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1479 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1482 else status = STATUS_SUCCESS;
1484 if (type) *type = info->Type;
1485 if (count) *count = total_size - info_size;
1487 done:
1488 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1489 RtlFreeUnicodeString( &nameW );
1490 return RtlNtStatusToDosError(status);
1494 /******************************************************************************
1495 * RegQueryValueW [ADVAPI32.@]
1497 * Retrieves the data associated with the default or unnamed value of a key.
1499 * PARAMS
1500 * hkey [I] Handle to an open key.
1501 * name [I] Name of the subkey of hKey.
1502 * data [O] Receives the string associated with the default value
1503 * of the key.
1504 * count [I/O] Size of lpValue in bytes.
1506 * RETURNS
1507 * Success: ERROR_SUCCESS
1508 * Failure: nonzero error code from Winerror.h
1510 LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1512 DWORD ret;
1513 HKEY subkey = hkey;
1515 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1517 if (name && name[0])
1519 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1521 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1522 if (subkey != hkey) RegCloseKey( subkey );
1523 if (ret == ERROR_FILE_NOT_FOUND)
1525 /* return empty string if default value not found */
1526 if (data) *data = 0;
1527 if (count) *count = sizeof(WCHAR);
1528 ret = ERROR_SUCCESS;
1530 return ret;
1534 /******************************************************************************
1535 * RegQueryValueA [ADVAPI32.@]
1537 * See RegQueryValueW.
1539 LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1541 DWORD ret;
1542 HKEY subkey = hkey;
1544 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1546 if (name && name[0])
1548 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1550 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1551 if (subkey != hkey) RegCloseKey( subkey );
1552 if (ret == ERROR_FILE_NOT_FOUND)
1554 /* return empty string if default value not found */
1555 if (data) *data = 0;
1556 if (count) *count = 1;
1557 ret = ERROR_SUCCESS;
1559 return ret;
1563 /******************************************************************************
1564 * ADVAPI_ApplyRestrictions [internal]
1566 * Helper function for RegGetValueA/W.
1568 static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1569 DWORD cbData, PLONG ret )
1571 /* Check if the type is restricted by the passed flags */
1572 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1574 DWORD dwMask = 0;
1576 switch (dwType)
1578 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1579 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1580 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1581 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1582 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1583 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1584 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1587 if (dwFlags & dwMask)
1589 /* Type is not restricted, check for size mismatch */
1590 if (dwType == REG_BINARY)
1592 DWORD cbExpect = 0;
1594 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
1595 cbExpect = 4;
1596 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
1597 cbExpect = 8;
1599 if (cbExpect && cbData != cbExpect)
1600 *ret = ERROR_DATATYPE_MISMATCH;
1603 else *ret = ERROR_UNSUPPORTED_TYPE;
1608 /******************************************************************************
1609 * RegGetValueW [ADVAPI32.@]
1611 * Retrieves the type and data for a value name associated with a key,
1612 * optionally expanding its content and restricting its type.
1614 * PARAMS
1615 * hKey [I] Handle to an open key.
1616 * pszSubKey [I] Name of the subkey of hKey.
1617 * pszValue [I] Name of value under hKey/szSubKey to query.
1618 * dwFlags [I] Flags restricting the value type to retrieve.
1619 * pdwType [O] Destination for the values type, may be NULL.
1620 * pvData [O] Destination for the values content, may be NULL.
1621 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1622 * retrieve the whole content, including the trailing '\0'
1623 * for strings.
1625 * RETURNS
1626 * Success: ERROR_SUCCESS
1627 * Failure: nonzero error code from Winerror.h
1629 * NOTES
1630 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1631 * expanded and pdwType is set to REG_SZ instead.
1632 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1633 * without RRF_NOEXPAND is thus not allowed.
1634 * An exception is the case where RRF_RT_ANY is specified, because then
1635 * RRF_NOEXPAND is allowed.
1637 LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1638 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1639 LPDWORD pcbData )
1641 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1642 PVOID pvBuf = NULL;
1643 LONG ret;
1645 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1646 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1647 pvData, pcbData, cbData);
1649 if (pvData && !pcbData)
1650 return ERROR_INVALID_PARAMETER;
1651 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1652 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1653 return ERROR_INVALID_PARAMETER;
1655 if (pszSubKey && pszSubKey[0])
1657 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1658 if (ret != ERROR_SUCCESS) return ret;
1661 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1663 /* If we are going to expand we need to read in the whole the value even
1664 * if the passed buffer was too small as the expanded string might be
1665 * smaller than the unexpanded one and could fit into cbData bytes. */
1666 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1667 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1669 do {
1670 HeapFree(GetProcessHeap(), 0, pvBuf);
1672 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1673 if (!pvBuf)
1675 ret = ERROR_NOT_ENOUGH_MEMORY;
1676 break;
1679 if (ret == ERROR_MORE_DATA || !pvData)
1680 ret = RegQueryValueExW(hKey, pszValue, NULL,
1681 &dwType, pvBuf, &cbData);
1682 else
1684 /* Even if cbData was large enough we have to copy the
1685 * string since ExpandEnvironmentStrings can't handle
1686 * overlapping buffers. */
1687 CopyMemory(pvBuf, pvData, cbData);
1690 /* Both the type or the value itself could have been modified in
1691 * between so we have to keep retrying until the buffer is large
1692 * enough or we no longer have to expand the value. */
1693 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1695 if (ret == ERROR_SUCCESS)
1697 /* Recheck dwType in case it changed since the first call */
1698 if (dwType == REG_EXPAND_SZ)
1700 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1701 pcbData ? *pcbData : 0) * sizeof(WCHAR);
1702 dwType = REG_SZ;
1703 if(pvData && pcbData && cbData > *pcbData)
1704 ret = ERROR_MORE_DATA;
1706 else if (pvData)
1707 CopyMemory(pvData, pvBuf, *pcbData);
1710 HeapFree(GetProcessHeap(), 0, pvBuf);
1713 if (pszSubKey && pszSubKey[0])
1714 RegCloseKey(hKey);
1716 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1718 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1719 ZeroMemory(pvData, *pcbData);
1721 if (pdwType) *pdwType = dwType;
1722 if (pcbData) *pcbData = cbData;
1724 return ret;
1728 /******************************************************************************
1729 * RegGetValueA [ADVAPI32.@]
1731 * See RegGetValueW.
1733 LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1734 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1735 LPDWORD pcbData )
1737 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1738 PVOID pvBuf = NULL;
1739 LONG ret;
1741 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1742 hKey, debugstr_a(pszSubKey), debugstr_a(pszValue), dwFlags,
1743 pdwType, pvData, pcbData, cbData);
1745 if (pvData && !pcbData)
1746 return ERROR_INVALID_PARAMETER;
1747 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1748 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
1749 return ERROR_INVALID_PARAMETER;
1751 if (pszSubKey && pszSubKey[0])
1753 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1754 if (ret != ERROR_SUCCESS) return ret;
1757 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1759 /* If we are going to expand we need to read in the whole the value even
1760 * if the passed buffer was too small as the expanded string might be
1761 * smaller than the unexpanded one and could fit into cbData bytes. */
1762 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1763 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1765 do {
1766 HeapFree(GetProcessHeap(), 0, pvBuf);
1768 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1769 if (!pvBuf)
1771 ret = ERROR_NOT_ENOUGH_MEMORY;
1772 break;
1775 if (ret == ERROR_MORE_DATA || !pvData)
1776 ret = RegQueryValueExA(hKey, pszValue, NULL,
1777 &dwType, pvBuf, &cbData);
1778 else
1780 /* Even if cbData was large enough we have to copy the
1781 * string since ExpandEnvironmentStrings can't handle
1782 * overlapping buffers. */
1783 CopyMemory(pvBuf, pvData, cbData);
1786 /* Both the type or the value itself could have been modified in
1787 * between so we have to keep retrying until the buffer is large
1788 * enough or we no longer have to expand the value. */
1789 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1791 if (ret == ERROR_SUCCESS)
1793 /* Recheck dwType in case it changed since the first call */
1794 if (dwType == REG_EXPAND_SZ)
1796 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1797 pcbData ? *pcbData : 0);
1798 dwType = REG_SZ;
1799 if(pvData && pcbData && cbData > *pcbData)
1800 ret = ERROR_MORE_DATA;
1802 else if (pvData)
1803 CopyMemory(pvData, pvBuf, *pcbData);
1806 HeapFree(GetProcessHeap(), 0, pvBuf);
1809 if (pszSubKey && pszSubKey[0])
1810 RegCloseKey(hKey);
1812 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1814 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1815 ZeroMemory(pvData, *pcbData);
1817 if (pdwType) *pdwType = dwType;
1818 if (pcbData) *pcbData = cbData;
1820 return ret;
1824 /******************************************************************************
1825 * RegEnumValueW [ADVAPI32.@]
1827 * Enumerates the values for the specified open registry key.
1829 * PARAMS
1830 * hkey [I] Handle to key to query
1831 * index [I] Index of value to query
1832 * value [O] Value string
1833 * val_count [I/O] Size of value buffer (in wchars)
1834 * reserved [I] Reserved
1835 * type [O] Type code
1836 * data [O] Value data
1837 * count [I/O] Size of data buffer (in bytes)
1839 * RETURNS
1840 * Success: ERROR_SUCCESS
1841 * Failure: nonzero error code from Winerror.h
1844 LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1845 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1847 NTSTATUS status;
1848 DWORD total_size;
1849 char buffer[256], *buf_ptr = buffer;
1850 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1851 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1853 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1854 hkey, index, value, val_count, reserved, type, data, count );
1856 /* NT only checks count, not val_count */
1857 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1858 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1860 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1861 if (data) total_size += *count;
1862 total_size = min( sizeof(buffer), total_size );
1864 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1865 buffer, total_size, &total_size );
1866 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1868 if (value || data)
1870 /* retry with a dynamically allocated buffer */
1871 while (status == STATUS_BUFFER_OVERFLOW)
1873 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1874 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1875 return ERROR_NOT_ENOUGH_MEMORY;
1876 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1877 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1878 buf_ptr, total_size, &total_size );
1881 if (status) goto done;
1883 if (value)
1885 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1887 status = STATUS_BUFFER_OVERFLOW;
1888 goto overflow;
1890 memcpy( value, info->Name, info->NameLength );
1891 *val_count = info->NameLength / sizeof(WCHAR);
1892 value[*val_count] = 0;
1895 if (data)
1897 if (total_size - info->DataOffset > *count)
1899 status = STATUS_BUFFER_OVERFLOW;
1900 goto overflow;
1902 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1903 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1905 /* if the type is REG_SZ and data is not 0-terminated
1906 * and there is enough space in the buffer NT appends a \0 */
1907 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1908 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1912 else status = STATUS_SUCCESS;
1914 overflow:
1915 if (type) *type = info->Type;
1916 if (count) *count = info->DataLength;
1918 done:
1919 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1920 return RtlNtStatusToDosError(status);
1924 /******************************************************************************
1925 * RegEnumValueA [ADVAPI32.@]
1927 * See RegEnumValueW.
1929 LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1930 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1932 NTSTATUS status;
1933 DWORD total_size;
1934 char buffer[256], *buf_ptr = buffer;
1935 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1936 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1938 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1939 hkey, index, value, val_count, reserved, type, data, count );
1941 /* NT only checks count, not val_count */
1942 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1943 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1945 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1946 if (data) total_size += *count;
1947 total_size = min( sizeof(buffer), total_size );
1949 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1950 buffer, total_size, &total_size );
1951 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1953 /* we need to fetch the contents for a string type even if not requested,
1954 * because we need to compute the length of the ASCII string. */
1955 if (value || data || is_string(info->Type))
1957 /* retry with a dynamically allocated buffer */
1958 while (status == STATUS_BUFFER_OVERFLOW)
1960 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1961 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1962 return ERROR_NOT_ENOUGH_MEMORY;
1963 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1964 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1965 buf_ptr, total_size, &total_size );
1968 if (status) goto done;
1970 if (is_string(info->Type))
1972 DWORD len;
1973 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1974 total_size - info->DataOffset );
1975 if (data && len)
1977 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1978 else
1980 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1981 total_size - info->DataOffset );
1982 /* if the type is REG_SZ and data is not 0-terminated
1983 * and there is enough space in the buffer NT appends a \0 */
1984 if (len < *count && data[len-1]) data[len] = 0;
1987 info->DataLength = len;
1989 else if (data)
1991 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1992 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1995 if (value && !status)
1997 DWORD len;
1999 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
2000 if (len >= *val_count)
2002 status = STATUS_BUFFER_OVERFLOW;
2003 if (*val_count)
2005 len = *val_count - 1;
2006 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2007 value[len] = 0;
2010 else
2012 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2013 value[len] = 0;
2014 *val_count = len;
2018 else status = STATUS_SUCCESS;
2020 if (type) *type = info->Type;
2021 if (count) *count = info->DataLength;
2023 done:
2024 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2025 return RtlNtStatusToDosError(status);
2030 /******************************************************************************
2031 * RegDeleteValueW [ADVAPI32.@]
2033 * See RegDeleteValueA.
2035 LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2037 UNICODE_STRING nameW;
2039 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2041 RtlInitUnicodeString( &nameW, name );
2042 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2046 /******************************************************************************
2047 * RegDeleteValueA [ADVAPI32.@]
2049 * Delete a value from the registry.
2051 * PARAMS
2052 * hkey [I] Registry handle of the key holding the value
2053 * name [I] Name of the value under hkey to delete
2055 * RETURNS
2056 * Success: ERROR_SUCCESS
2057 * Failure: nonzero error code from Winerror.h
2059 LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2061 ANSI_STRING nameA;
2062 UNICODE_STRING nameW;
2063 NTSTATUS status;
2065 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2067 RtlInitAnsiString( &nameA, name );
2068 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2070 status = NtDeleteValueKey( hkey, &nameW );
2071 RtlFreeUnicodeString( &nameW );
2073 return RtlNtStatusToDosError( status );
2077 /******************************************************************************
2078 * RegLoadKeyW [ADVAPI32.@]
2080 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2081 * registration information from a specified file into that subkey.
2083 * PARAMS
2084 * hkey [I] Handle of open key
2085 * subkey [I] Address of name of subkey
2086 * filename [I] Address of filename for registry information
2088 * RETURNS
2089 * Success: ERROR_SUCCESS
2090 * Failure: nonzero error code from Winerror.h
2092 LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2094 OBJECT_ATTRIBUTES destkey, file;
2095 UNICODE_STRING subkeyW, filenameW;
2096 NTSTATUS status;
2098 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
2100 destkey.Length = sizeof(destkey);
2101 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2102 destkey.ObjectName = &subkeyW; /* name of the key */
2103 destkey.Attributes = 0;
2104 destkey.SecurityDescriptor = NULL;
2105 destkey.SecurityQualityOfService = NULL;
2106 RtlInitUnicodeString(&subkeyW, subkey);
2108 file.Length = sizeof(file);
2109 file.RootDirectory = NULL;
2110 file.ObjectName = &filenameW; /* file containing the hive */
2111 file.Attributes = OBJ_CASE_INSENSITIVE;
2112 file.SecurityDescriptor = NULL;
2113 file.SecurityQualityOfService = NULL;
2114 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2116 status = NtLoadKey(&destkey, &file);
2117 RtlFreeUnicodeString(&filenameW);
2118 return RtlNtStatusToDosError( status );
2122 /******************************************************************************
2123 * RegLoadKeyA [ADVAPI32.@]
2125 * See RegLoadKeyW.
2127 LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2129 UNICODE_STRING subkeyW, filenameW;
2130 STRING subkeyA, filenameA;
2131 NTSTATUS status;
2132 LONG ret;
2134 RtlInitAnsiString(&subkeyA, subkey);
2135 RtlInitAnsiString(&filenameA, filename);
2137 RtlInitUnicodeString(&subkeyW, NULL);
2138 RtlInitUnicodeString(&filenameW, NULL);
2139 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2140 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2142 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2144 else ret = RtlNtStatusToDosError(status);
2145 RtlFreeUnicodeString(&subkeyW);
2146 RtlFreeUnicodeString(&filenameW);
2147 return ret;
2151 /******************************************************************************
2152 * RegSaveKeyW [ADVAPI32.@]
2154 * Save a key and all of its subkeys and values to a new file in the standard format.
2156 * PARAMS
2157 * hkey [I] Handle of key where save begins
2158 * lpFile [I] Address of filename to save to
2159 * sa [I] Address of security structure
2161 * RETURNS
2162 * Success: ERROR_SUCCESS
2163 * Failure: nonzero error code from Winerror.h
2165 LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2167 static const WCHAR format[] =
2168 {'r','e','g','%','0','4','x','.','t','m','p',0};
2169 WCHAR buffer[MAX_PATH];
2170 int count = 0;
2171 LPWSTR nameW;
2172 DWORD ret, err;
2173 HANDLE handle;
2175 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2177 if (!file || !*file) return ERROR_INVALID_PARAMETER;
2178 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2180 err = GetLastError();
2181 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2183 for (;;)
2185 snprintfW( nameW, 16, format, count++ );
2186 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2187 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2188 if (handle != INVALID_HANDLE_VALUE) break;
2189 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2191 /* Something gone haywire ? Please report if this happens abnormally */
2192 if (count >= 100)
2193 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);
2196 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2198 CloseHandle( handle );
2199 if (!ret)
2201 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2203 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2204 debugstr_w(file) );
2205 ret = GetLastError();
2208 if (ret) DeleteFileW( buffer );
2210 done:
2211 SetLastError( err ); /* restore last error code */
2212 return ret;
2216 /******************************************************************************
2217 * RegSaveKeyA [ADVAPI32.@]
2219 * See RegSaveKeyW.
2221 LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2223 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2224 NTSTATUS status;
2225 STRING fileA;
2227 RtlInitAnsiString(&fileA, file);
2228 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2229 return RtlNtStatusToDosError( status );
2230 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2234 /******************************************************************************
2235 * RegRestoreKeyW [ADVAPI32.@]
2237 * Read the registry information from a file and copy it over a key.
2239 * PARAMS
2240 * hkey [I] Handle of key where restore begins
2241 * lpFile [I] Address of filename containing saved tree
2242 * dwFlags [I] Optional flags
2244 * RETURNS
2245 * Success: ERROR_SUCCESS
2246 * Failure: nonzero error code from Winerror.h
2248 LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2250 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2252 /* It seems to do this check before the hkey check */
2253 if (!lpFile || !*lpFile)
2254 return ERROR_INVALID_PARAMETER;
2256 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2258 /* Check for file existence */
2260 return ERROR_SUCCESS;
2264 /******************************************************************************
2265 * RegRestoreKeyA [ADVAPI32.@]
2267 * See RegRestoreKeyW.
2269 LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2271 UNICODE_STRING lpFileW;
2272 LONG ret;
2274 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2275 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2276 RtlFreeUnicodeString( &lpFileW );
2277 return ret;
2281 /******************************************************************************
2282 * RegUnLoadKeyW [ADVAPI32.@]
2284 * Unload a registry key and its subkeys from the registry.
2286 * PARAMS
2287 * hkey [I] Handle of open key
2288 * lpSubKey [I] Address of name of subkey to unload
2290 * RETURNS
2291 * Success: ERROR_SUCCESS
2292 * Failure: nonzero error code from Winerror.h
2294 LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2296 DWORD ret;
2297 HKEY shkey;
2298 OBJECT_ATTRIBUTES attr;
2299 UNICODE_STRING subkey;
2301 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2303 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2304 if( ret )
2305 return ERROR_INVALID_PARAMETER;
2307 RtlInitUnicodeString(&subkey, lpSubKey);
2308 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2309 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2311 RegCloseKey(shkey);
2313 return ret;
2317 /******************************************************************************
2318 * RegUnLoadKeyA [ADVAPI32.@]
2320 * See RegUnLoadKeyW.
2322 LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2324 UNICODE_STRING lpSubKeyW;
2325 LONG ret;
2327 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2328 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2329 RtlFreeUnicodeString( &lpSubKeyW );
2330 return ret;
2334 /******************************************************************************
2335 * RegReplaceKeyW [ADVAPI32.@]
2337 * Replace the file backing a registry key and all its subkeys with another file.
2339 * PARAMS
2340 * hkey [I] Handle of open key
2341 * lpSubKey [I] Address of name of subkey
2342 * lpNewFile [I] Address of filename for file with new data
2343 * lpOldFile [I] Address of filename for backup file
2345 * RETURNS
2346 * Success: ERROR_SUCCESS
2347 * Failure: nonzero error code from Winerror.h
2349 LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2350 LPCWSTR lpOldFile )
2352 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2353 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2354 return ERROR_SUCCESS;
2358 /******************************************************************************
2359 * RegReplaceKeyA [ADVAPI32.@]
2361 * See RegReplaceKeyW.
2363 LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2364 LPCSTR lpOldFile )
2366 UNICODE_STRING lpSubKeyW;
2367 UNICODE_STRING lpNewFileW;
2368 UNICODE_STRING lpOldFileW;
2369 LONG ret;
2371 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2372 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2373 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2374 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2375 RtlFreeUnicodeString( &lpOldFileW );
2376 RtlFreeUnicodeString( &lpNewFileW );
2377 RtlFreeUnicodeString( &lpSubKeyW );
2378 return ret;
2382 /******************************************************************************
2383 * RegSetKeySecurity [ADVAPI32.@]
2385 * Set the security of an open registry key.
2387 * PARAMS
2388 * hkey [I] Open handle of key to set
2389 * SecurityInfo [I] Descriptor contents
2390 * pSecurityDesc [I] Address of descriptor for key
2392 * RETURNS
2393 * Success: ERROR_SUCCESS
2394 * Failure: nonzero error code from Winerror.h
2396 LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2397 PSECURITY_DESCRIPTOR pSecurityDesc )
2399 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2401 /* It seems to perform this check before the hkey check */
2402 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2403 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2404 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2405 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2406 /* Param OK */
2407 } else
2408 return ERROR_INVALID_PARAMETER;
2410 if (!pSecurityDesc)
2411 return ERROR_INVALID_PARAMETER;
2413 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2415 return ERROR_SUCCESS;
2419 /******************************************************************************
2420 * RegGetKeySecurity [ADVAPI32.@]
2422 * Get a copy of the security descriptor for a given registry key.
2424 * PARAMS
2425 * hkey [I] Open handle of key to set
2426 * SecurityInformation [I] Descriptor contents
2427 * pSecurityDescriptor [O] Address of descriptor for key
2428 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2430 * RETURNS
2431 * Success: ERROR_SUCCESS
2432 * Failure: Error code
2434 LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2435 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2436 LPDWORD lpcbSecurityDescriptor )
2438 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2439 *lpcbSecurityDescriptor);
2441 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2443 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2444 SecurityInformation, pSecurityDescriptor,
2445 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2449 /******************************************************************************
2450 * RegFlushKey [ADVAPI32.@]
2452 * Immediately write a registry key to registry.
2454 * PARAMS
2455 * hkey [I] Handle of key to write
2457 * RETURNS
2458 * Success: ERROR_SUCCESS
2459 * Failure: Error code
2461 LSTATUS WINAPI RegFlushKey( HKEY hkey )
2463 hkey = get_special_root_hkey( hkey );
2464 if (!hkey) return ERROR_INVALID_HANDLE;
2466 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2470 /******************************************************************************
2471 * RegConnectRegistryW [ADVAPI32.@]
2473 * Establish a connection to a predefined registry key on another computer.
2475 * PARAMS
2476 * lpMachineName [I] Address of name of remote computer
2477 * hHey [I] Predefined registry handle
2478 * phkResult [I] Address of buffer for remote registry handle
2480 * RETURNS
2481 * Success: ERROR_SUCCESS
2482 * Failure: nonzero error code from Winerror.h
2484 LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2485 PHKEY phkResult )
2487 LONG ret;
2489 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2491 if (!lpMachineName || !*lpMachineName) {
2492 /* Use the local machine name */
2493 ret = RegOpenKeyW( hKey, NULL, phkResult );
2495 else {
2496 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2497 DWORD len = sizeof(compName) / sizeof(WCHAR);
2499 /* MSDN says lpMachineName must start with \\ : not so */
2500 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2501 lpMachineName += 2;
2502 if (GetComputerNameW(compName, &len))
2504 if (!strcmpiW(lpMachineName, compName))
2505 ret = RegOpenKeyW(hKey, NULL, phkResult);
2506 else
2508 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2509 ret = ERROR_BAD_NETPATH;
2512 else
2513 ret = GetLastError();
2515 return ret;
2519 /******************************************************************************
2520 * RegConnectRegistryA [ADVAPI32.@]
2522 * See RegConnectRegistryW.
2524 LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2526 UNICODE_STRING machineW;
2527 LONG ret;
2529 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2530 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2531 RtlFreeUnicodeString( &machineW );
2532 return ret;
2536 /******************************************************************************
2537 * RegNotifyChangeKeyValue [ADVAPI32.@]
2539 * Notify the caller about changes to the attributes or contents of a registry key.
2541 * PARAMS
2542 * hkey [I] Handle of key to watch
2543 * fWatchSubTree [I] Flag for subkey notification
2544 * fdwNotifyFilter [I] Changes to be reported
2545 * hEvent [I] Handle of signaled event
2546 * fAsync [I] Flag for asynchronous reporting
2548 * RETURNS
2549 * Success: ERROR_SUCCESS
2550 * Failure: nonzero error code from Winerror.h
2552 LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2553 DWORD fdwNotifyFilter, HANDLE hEvent,
2554 BOOL fAsync )
2556 NTSTATUS status;
2557 IO_STATUS_BLOCK iosb;
2559 hkey = get_special_root_hkey( hkey );
2560 if (!hkey) return ERROR_INVALID_HANDLE;
2562 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2563 hEvent, fAsync);
2565 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2566 fdwNotifyFilter, fAsync, NULL, 0,
2567 fWatchSubTree);
2569 if (status && status != STATUS_TIMEOUT)
2570 return RtlNtStatusToDosError( status );
2572 return ERROR_SUCCESS;
2575 /******************************************************************************
2576 * RegOpenUserClassesRoot [ADVAPI32.@]
2578 * Open the HKEY_CLASSES_ROOT key for a user.
2580 * PARAMS
2581 * hToken [I] Handle of token representing the user
2582 * dwOptions [I] Reserved, must be 0
2583 * samDesired [I] Desired access rights
2584 * phkResult [O] Destination for the resulting key handle
2586 * RETURNS
2587 * Success: ERROR_SUCCESS
2588 * Failure: nonzero error code from Winerror.h
2590 * NOTES
2591 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2592 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2593 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2595 LSTATUS WINAPI RegOpenUserClassesRoot(
2596 HANDLE hToken,
2597 DWORD dwOptions,
2598 REGSAM samDesired,
2599 PHKEY phkResult
2602 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2604 *phkResult = HKEY_CLASSES_ROOT;
2605 return ERROR_SUCCESS;
2608 /******************************************************************************
2609 * load_string [Internal]
2611 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2612 * avoid importing user32, which is higher level than advapi32. Helper for
2613 * RegLoadMUIString.
2615 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2617 HGLOBAL hMemory;
2618 HRSRC hResource;
2619 WCHAR *pString;
2620 int idxString;
2622 /* Negative values have to be inverted. */
2623 if (HIWORD(resId) == 0xffff)
2624 resId = (UINT)(-((INT)resId));
2626 /* Load the resource into memory and get a pointer to it. */
2627 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2628 if (!hResource) return 0;
2629 hMemory = LoadResource(hModule, hResource);
2630 if (!hMemory) return 0;
2631 pString = LockResource(hMemory);
2633 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2634 idxString = resId & 0xf;
2635 while (idxString--) pString += *pString + 1;
2637 /* If no buffer is given, return length of the string. */
2638 if (!pwszBuffer) return *pString;
2640 /* Else copy over the string, respecting the buffer size. */
2641 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2642 if (cMaxChars >= 0) {
2643 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2644 pwszBuffer[cMaxChars] = '\0';
2647 return cMaxChars;
2650 /******************************************************************************
2651 * RegLoadMUIStringW [ADVAPI32.@]
2653 * Load the localized version of a string resource from some PE, respective
2654 * id and path of which are given in the registry value in the format
2655 * @[path]\dllname,-resourceId
2657 * PARAMS
2658 * hKey [I] Key, of which to load the string value from.
2659 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2660 * pszBuffer [O] Buffer to store the localized string in.
2661 * cbBuffer [I] Size of the destination buffer in bytes.
2662 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2663 * dwFlags [I] None supported yet.
2664 * pszBaseDir [I] Not supported yet.
2666 * RETURNS
2667 * Success: ERROR_SUCCESS,
2668 * Failure: nonzero error code from winerror.h
2670 * NOTES
2671 * This is an API of Windows Vista, which wasn't available at the time this code
2672 * was written. We have to check for the correct behaviour once it's available.
2674 LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2675 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2677 DWORD dwValueType, cbData;
2678 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2679 LONG result;
2681 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2682 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2683 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2685 /* Parameter sanity checks. */
2686 if (!hKey || !pwszBuffer)
2687 return ERROR_INVALID_PARAMETER;
2689 if (pwszBaseDir && *pwszBaseDir) {
2690 FIXME("BaseDir parameter not yet supported!\n");
2691 return ERROR_INVALID_PARAMETER;
2694 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2695 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2696 if (result != ERROR_SUCCESS) goto cleanup;
2697 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2698 result = ERROR_FILE_NOT_FOUND;
2699 goto cleanup;
2701 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2702 if (!pwszTempBuffer) {
2703 result = ERROR_NOT_ENOUGH_MEMORY;
2704 goto cleanup;
2706 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2707 if (result != ERROR_SUCCESS) goto cleanup;
2709 /* Expand environment variables, if appropriate, or copy the original string over. */
2710 if (dwValueType == REG_EXPAND_SZ) {
2711 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2712 if (!cbData) goto cleanup;
2713 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2714 if (!pwszExpandedBuffer) {
2715 result = ERROR_NOT_ENOUGH_MEMORY;
2716 goto cleanup;
2718 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2719 } else {
2720 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2721 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2724 /* If the value references a resource based string, parse the value and load the string.
2725 * Else just copy over the original value. */
2726 result = ERROR_SUCCESS;
2727 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2728 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2729 } else {
2730 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2731 UINT uiStringId;
2732 HMODULE hModule;
2734 /* Format of the expanded value is 'path_to_dll,-resId' */
2735 if (!pComma || pComma[1] != '-') {
2736 result = ERROR_BADKEY;
2737 goto cleanup;
2740 uiStringId = atoiW(pComma+2);
2741 *pComma = '\0';
2743 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2744 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2745 result = ERROR_BADKEY;
2746 FreeLibrary(hModule);
2749 cleanup:
2750 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2751 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2752 return result;
2755 /******************************************************************************
2756 * RegLoadMUIStringA [ADVAPI32.@]
2758 * See RegLoadMUIStringW
2760 LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2761 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2763 UNICODE_STRING valueW, baseDirW;
2764 WCHAR *pwszBuffer;
2765 DWORD cbData = cbBuffer * sizeof(WCHAR);
2766 LONG result;
2768 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2769 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2770 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2771 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2773 result = ERROR_NOT_ENOUGH_MEMORY;
2774 goto cleanup;
2777 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2778 baseDirW.Buffer);
2780 if (result == ERROR_SUCCESS) {
2781 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2782 if (pcbData)
2783 *pcbData = cbData;
2786 cleanup:
2787 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2788 RtlFreeUnicodeString(&baseDirW);
2789 RtlFreeUnicodeString(&valueW);
2791 return result;
2794 /******************************************************************************
2795 * RegDisablePredefinedCache [ADVAPI32.@]
2797 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2799 * PARAMS
2800 * None.
2802 * RETURNS
2803 * Success: ERROR_SUCCESS
2804 * Failure: nonzero error code from Winerror.h
2806 * NOTES
2807 * This is useful for services that use impersonation.
2809 LSTATUS WINAPI RegDisablePredefinedCache(void)
2811 HKEY hkey_current_user;
2812 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2814 /* prevent caching of future requests */
2815 hkcu_cache_disabled = TRUE;
2817 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2819 if (hkey_current_user)
2820 NtClose( hkey_current_user );
2822 return ERROR_SUCCESS;
2825 /******************************************************************************
2826 * RegDeleteTreeW [ADVAPI32.@]
2829 LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2831 LONG ret;
2832 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2833 DWORD dwMaxLen, dwSize;
2834 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2835 HKEY hSubKey = hKey;
2837 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2839 if(lpszSubKey)
2841 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2842 if (ret) return ret;
2845 /* Get highest length for keys, values */
2846 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2847 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2848 if (ret) goto cleanup;
2850 dwMaxSubkeyLen++;
2851 dwMaxValueLen++;
2852 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2853 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2855 /* Name too big: alloc a buffer for it */
2856 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2858 ret = ERROR_NOT_ENOUGH_MEMORY;
2859 goto cleanup;
2864 /* Recursively delete all the subkeys */
2865 while (TRUE)
2867 dwSize = dwMaxLen;
2868 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2869 NULL, NULL, NULL)) break;
2871 ret = RegDeleteTreeW(hSubKey, lpszName);
2872 if (ret) goto cleanup;
2875 if (lpszSubKey)
2876 ret = RegDeleteKeyW(hKey, lpszSubKey);
2877 else
2878 while (TRUE)
2880 dwSize = dwMaxLen;
2881 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2882 NULL, NULL, NULL, NULL)) break;
2884 ret = RegDeleteValueW(hKey, lpszName);
2885 if (ret) goto cleanup;
2888 cleanup:
2889 /* Free buffer if allocated */
2890 if (lpszName != szNameBuf)
2891 HeapFree( GetProcessHeap(), 0, lpszName);
2892 if(lpszSubKey)
2893 RegCloseKey(hSubKey);
2894 return ret;
2897 /******************************************************************************
2898 * RegDeleteTreeA [ADVAPI32.@]
2901 LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2903 LONG ret;
2904 UNICODE_STRING lpszSubKeyW;
2906 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2907 else lpszSubKeyW.Buffer = NULL;
2908 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2909 RtlFreeUnicodeString( &lpszSubKeyW );
2910 return ret;
2913 /******************************************************************************
2914 * RegDisableReflectionKey [ADVAPI32.@]
2917 LONG WINAPI RegDisableReflectionKey(HKEY base)
2919 FIXME("%p: stub\n", base);
2920 return ERROR_SUCCESS;