wineconsole: Portability fixes in the curses mouse support.
[wine/testsucceed.git] / dlls / advapi32 / registry.c
blob7790862001af45e0894f8e184967e36bd2fa431f
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 file is concerned about handle management and interaction with the Wine server.
12 * Registry file I/O is in misc/registry.c.
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38 #include "winerror.h"
39 #include "winternl.h"
40 #include "winuser.h"
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(reg);
47 /* allowed bits for access mask */
48 #define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
50 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
51 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
52 #define NB_SPECIAL_ROOT_KEYS ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
54 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
56 static const WCHAR name_CLASSES_ROOT[] =
57 {'M','a','c','h','i','n','e','\\',
58 'S','o','f','t','w','a','r','e','\\',
59 'C','l','a','s','s','e','s',0};
60 static const WCHAR name_LOCAL_MACHINE[] =
61 {'M','a','c','h','i','n','e',0};
62 static const WCHAR name_USERS[] =
63 {'U','s','e','r',0};
64 static const WCHAR name_PERFORMANCE_DATA[] =
65 {'P','e','r','f','D','a','t','a',0};
66 static const WCHAR name_CURRENT_CONFIG[] =
67 {'M','a','c','h','i','n','e','\\',
68 'S','y','s','t','e','m','\\',
69 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
70 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
71 'C','u','r','r','e','n','t',0};
72 static const WCHAR name_DYN_DATA[] =
73 {'D','y','n','D','a','t','a',0};
75 #define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
76 static UNICODE_STRING root_key_names[NB_SPECIAL_ROOT_KEYS] =
78 DECL_STR(CLASSES_ROOT),
79 { 0, 0, NULL }, /* HKEY_CURRENT_USER is determined dynamically */
80 DECL_STR(LOCAL_MACHINE),
81 DECL_STR(USERS),
82 DECL_STR(PERFORMANCE_DATA),
83 DECL_STR(CURRENT_CONFIG),
84 DECL_STR(DYN_DATA)
86 #undef DECL_STR
89 /* check if value type needs string conversion (Ansi<->Unicode) */
90 inline static int is_string( DWORD type )
92 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
95 /* check if current version is NT or Win95 */
96 inline static int is_version_nt(void)
98 return !(GetVersion() & 0x80000000);
101 /* create one of the HKEY_* special root keys */
102 static HKEY create_special_root_hkey( HANDLE hkey, DWORD access )
104 HKEY ret = 0;
105 int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
107 if (hkey == HKEY_CURRENT_USER)
109 if (RtlOpenCurrentUser( access, &hkey )) return 0;
110 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
112 else
114 OBJECT_ATTRIBUTES attr;
116 attr.Length = sizeof(attr);
117 attr.RootDirectory = 0;
118 attr.ObjectName = &root_key_names[idx];
119 attr.Attributes = 0;
120 attr.SecurityDescriptor = NULL;
121 attr.SecurityQualityOfService = NULL;
122 if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
123 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
126 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
127 ret = hkey;
128 else
129 NtClose( hkey ); /* somebody beat us to it */
130 return ret;
133 /* map the hkey from special root to normal key if necessary */
134 inline static HKEY get_special_root_hkey( HKEY hkey )
136 HKEY ret = hkey;
138 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
140 if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
141 ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
143 return ret;
147 /******************************************************************************
148 * RegCreateKeyExW [ADVAPI32.@]
150 * See RegCreateKeyExA.
152 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
153 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
154 PHKEY retkey, LPDWORD dispos )
156 OBJECT_ATTRIBUTES attr;
157 UNICODE_STRING nameW, classW;
159 if (reserved) return ERROR_INVALID_PARAMETER;
160 if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
161 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
163 attr.Length = sizeof(attr);
164 attr.RootDirectory = hkey;
165 attr.ObjectName = &nameW;
166 attr.Attributes = 0;
167 attr.SecurityDescriptor = NULL;
168 attr.SecurityQualityOfService = NULL;
169 RtlInitUnicodeString( &nameW, name );
170 RtlInitUnicodeString( &classW, class );
172 return RtlNtStatusToDosError( NtCreateKey( (PHANDLE)retkey, access, &attr, 0,
173 &classW, options, dispos ) );
177 /******************************************************************************
178 * RegCreateKeyExA [ADVAPI32.@]
180 * Open a registry key, creating it if it doesn't exist.
182 * PARAMS
183 * hkey [I] Handle of the parent registry key
184 * name [I] Name of the new key to open or create
185 * reserved [I] Reserved, pass 0
186 * class [I] The object type of the new key
187 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
188 * access [I] Access level desired
189 * sa [I] Security attributes for the key
190 * retkey [O] Destination for the resulting handle
191 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
193 * RETURNS
194 * Success: ERROR_SUCCESS.
195 * Failure: A standard Win32 error code. retkey remains untouched.
197 * FIXME
198 * MAXIMUM_ALLOWED in access mask not supported by server
200 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
201 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
202 PHKEY retkey, LPDWORD dispos )
204 OBJECT_ATTRIBUTES attr;
205 UNICODE_STRING classW;
206 ANSI_STRING nameA, classA;
207 NTSTATUS status;
209 if (reserved) return ERROR_INVALID_PARAMETER;
210 if (!is_version_nt())
212 access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
213 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
215 else if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
216 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
218 attr.Length = sizeof(attr);
219 attr.RootDirectory = hkey;
220 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
221 attr.Attributes = 0;
222 attr.SecurityDescriptor = NULL;
223 attr.SecurityQualityOfService = NULL;
224 RtlInitAnsiString( &nameA, name );
225 RtlInitAnsiString( &classA, class );
227 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
228 &nameA, FALSE )))
230 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
232 status = NtCreateKey( (PHANDLE)retkey, access, &attr, 0, &classW, options, dispos );
233 RtlFreeUnicodeString( &classW );
236 return RtlNtStatusToDosError( status );
240 /******************************************************************************
241 * RegCreateKeyW [ADVAPI32.@]
243 * Creates the specified reg key.
245 * PARAMS
246 * hKey [I] Handle to an open key.
247 * lpSubKey [I] Name of a key that will be opened or created.
248 * phkResult [O] Receives a handle to the opened or created key.
250 * RETURNS
251 * Success: ERROR_SUCCESS
252 * Failure: nonzero error code defined in Winerror.h
254 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
256 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
257 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
258 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
259 KEY_ALL_ACCESS, NULL, phkResult, NULL );
263 /******************************************************************************
264 * RegCreateKeyA [ADVAPI32.@]
266 * See RegCreateKeyW.
268 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
270 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
271 KEY_ALL_ACCESS, NULL, phkResult, NULL );
276 /******************************************************************************
277 * RegOpenKeyExW [ADVAPI32.@]
279 * See RegOpenKeyExA.
281 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
283 OBJECT_ATTRIBUTES attr;
284 UNICODE_STRING nameW;
286 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
288 attr.Length = sizeof(attr);
289 attr.RootDirectory = hkey;
290 attr.ObjectName = &nameW;
291 attr.Attributes = 0;
292 attr.SecurityDescriptor = NULL;
293 attr.SecurityQualityOfService = NULL;
294 RtlInitUnicodeString( &nameW, name );
295 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE)retkey, access, &attr ) );
299 /******************************************************************************
300 * RegOpenKeyExA [ADVAPI32.@]
302 * Open a registry key.
304 * PARAMS
305 * hkey [I] Handle of open key
306 * name [I] Name of subkey to open
307 * reserved [I] Reserved - must be zero
308 * access [I] Security access mask
309 * retkey [O] Handle to open key
311 * RETURNS
312 * Success: ERROR_SUCCESS
313 * Failure: A standard Win32 error code. retkey is set to 0.
315 * NOTES
316 * Unlike RegCreateKeyExA(), this function will not create the key if it
317 * does not exist.
319 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
321 OBJECT_ATTRIBUTES attr;
322 STRING nameA;
323 NTSTATUS status;
325 if (!is_version_nt()) access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
327 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
329 attr.Length = sizeof(attr);
330 attr.RootDirectory = hkey;
331 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
332 attr.Attributes = 0;
333 attr.SecurityDescriptor = NULL;
334 attr.SecurityQualityOfService = NULL;
336 RtlInitAnsiString( &nameA, name );
337 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
338 &nameA, FALSE )))
340 status = NtOpenKey( (PHANDLE)retkey, access, &attr );
342 return RtlNtStatusToDosError( status );
346 /******************************************************************************
347 * RegOpenKeyW [ADVAPI32.@]
349 * See RegOpenKeyA.
351 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
353 if (!name || !*name)
355 *retkey = hkey;
356 return ERROR_SUCCESS;
358 return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
362 /******************************************************************************
363 * RegOpenKeyA [ADVAPI32.@]
365 * Open a registry key.
367 * PARAMS
368 * hkey [I] Handle of parent key to open the new key under
369 * name [I] Name of the key under hkey to open
370 * retkey [O] Destination for the resulting Handle
372 * RETURNS
373 * Success: ERROR_SUCCESS
374 * Failure: A standard Win32 error code. retkey is set to 0.
376 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
378 if (!name || !*name)
380 *retkey = hkey;
381 return ERROR_SUCCESS;
383 return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
387 /******************************************************************************
388 * RegOpenCurrentUser [ADVAPI32.@]
390 * Get a handle to the HKEY_CURRENT_USER key for the user
391 * the current thread is impersonating.
393 * PARAMS
394 * access [I] Desired access rights to the key
395 * retkey [O] Handle to the opened key
397 * RETURNS
398 * Success: ERROR_SUCCESS
399 * Failure: nonzero error code from Winerror.h
401 * FIXME
402 * This function is supposed to retrieve a handle to the
403 * HKEY_CURRENT_USER for the user the current thread is impersonating.
404 * Since Wine does not currently allow threads to impersonate other users,
405 * this stub should work fine.
407 DWORD WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
409 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
414 /******************************************************************************
415 * RegEnumKeyExW [ADVAPI32.@]
417 * Enumerate subkeys of the specified open registry key.
419 * PARAMS
420 * hkey [I] Handle to key to enumerate
421 * index [I] Index of subkey to enumerate
422 * name [O] Buffer for subkey name
423 * name_len [O] Size of subkey buffer
424 * reserved [I] Reserved
425 * class [O] Buffer for class string
426 * class_len [O] Size of class buffer
427 * ft [O] Time key last written to
429 * RETURNS
430 * Success: ERROR_SUCCESS
431 * Failure: System error code. If there are no more subkeys available, the
432 * function returns ERROR_NO_MORE_ITEMS.
434 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
435 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
437 NTSTATUS status;
438 char buffer[256], *buf_ptr = buffer;
439 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
440 DWORD total_size;
442 TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
443 name_len ? *name_len : -1, reserved, class, class_len, ft );
445 if (reserved) return ERROR_INVALID_PARAMETER;
446 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
448 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
449 buffer, sizeof(buffer), &total_size );
451 while (status == STATUS_BUFFER_OVERFLOW)
453 /* retry with a dynamically allocated buffer */
454 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
455 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
456 return ERROR_NOT_ENOUGH_MEMORY;
457 info = (KEY_NODE_INFORMATION *)buf_ptr;
458 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
459 buf_ptr, total_size, &total_size );
462 if (!status)
464 DWORD len = info->NameLength / sizeof(WCHAR);
465 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
467 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
469 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
470 status = STATUS_BUFFER_OVERFLOW;
471 else
473 *name_len = len;
474 memcpy( name, info->Name, info->NameLength );
475 name[len] = 0;
476 if (class_len)
478 *class_len = cls_len;
479 if (class)
481 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
482 class[cls_len] = 0;
488 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
489 return RtlNtStatusToDosError( status );
493 /******************************************************************************
494 * RegEnumKeyExA [ADVAPI32.@]
496 * See RegEnumKeyExW.
498 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
499 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
501 NTSTATUS status;
502 char buffer[256], *buf_ptr = buffer;
503 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
504 DWORD total_size;
506 TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
507 name_len ? *name_len : -1, reserved, class, class_len, ft );
509 if (reserved) return ERROR_INVALID_PARAMETER;
510 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
512 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
513 buffer, sizeof(buffer), &total_size );
515 while (status == STATUS_BUFFER_OVERFLOW)
517 /* retry with a dynamically allocated buffer */
518 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
519 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
520 return ERROR_NOT_ENOUGH_MEMORY;
521 info = (KEY_NODE_INFORMATION *)buf_ptr;
522 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
523 buf_ptr, total_size, &total_size );
526 if (!status)
528 DWORD len, cls_len;
530 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
531 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
532 info->ClassLength );
533 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
535 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
536 status = STATUS_BUFFER_OVERFLOW;
537 else
539 *name_len = len;
540 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
541 name[len] = 0;
542 if (class_len)
544 *class_len = cls_len;
545 if (class)
547 RtlUnicodeToMultiByteN( class, cls_len, NULL,
548 (WCHAR *)(buf_ptr + info->ClassOffset),
549 info->ClassLength );
550 class[cls_len] = 0;
556 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
557 return RtlNtStatusToDosError( status );
561 /******************************************************************************
562 * RegEnumKeyW [ADVAPI32.@]
564 * Enumerates subkyes of the specified open reg key.
566 * PARAMS
567 * hKey [I] Handle to an open key.
568 * dwIndex [I] Index of the subkey of hKey to retrieve.
569 * lpName [O] Name of the subkey.
570 * cchName [I] Size of lpName in TCHARS.
572 * RETURNS
573 * Success: ERROR_SUCCESS
574 * Failure: system error code. If there are no more subkeys available, the
575 * function returns ERROR_NO_MORE_ITEMS.
577 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
579 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
583 /******************************************************************************
584 * RegEnumKeyA [ADVAPI32.@]
586 * See RegEnumKeyW.
588 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
590 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
594 /******************************************************************************
595 * RegQueryInfoKeyW [ADVAPI32.@]
597 * Retrieves information about the specified registry key.
599 * PARAMS
600 * hkey [I] Handle to key to query
601 * class [O] Buffer for class string
602 * class_len [O] Size of class string buffer
603 * reserved [I] Reserved
604 * subkeys [O] Buffer for number of subkeys
605 * max_subkey [O] Buffer for longest subkey name length
606 * max_class [O] Buffer for longest class string length
607 * values [O] Buffer for number of value entries
608 * max_value [O] Buffer for longest value name length
609 * max_data [O] Buffer for longest value data length
610 * security [O] Buffer for security descriptor length
611 * modif [O] Modification time
613 * RETURNS
614 * Success: ERROR_SUCCESS
615 * Failure: system error code.
617 * NOTES
618 * - win95 allows class to be valid and class_len to be NULL
619 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
620 * - both allow class to be NULL and class_len to be NULL
621 * (it's hard to test validity, so test !NULL instead)
623 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
624 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
625 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
626 LPDWORD security, FILETIME *modif )
628 NTSTATUS status;
629 char buffer[256], *buf_ptr = buffer;
630 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
631 DWORD total_size;
633 TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
634 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
636 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
637 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
639 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
640 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
642 if (class)
644 /* retry with a dynamically allocated buffer */
645 while (status == STATUS_BUFFER_OVERFLOW)
647 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
648 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
649 return ERROR_NOT_ENOUGH_MEMORY;
650 info = (KEY_FULL_INFORMATION *)buf_ptr;
651 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
654 if (status) goto done;
656 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
658 status = STATUS_BUFFER_OVERFLOW;
660 else
662 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
663 class[info->ClassLength/sizeof(WCHAR)] = 0;
666 else status = STATUS_SUCCESS;
668 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
669 if (subkeys) *subkeys = info->SubKeys;
670 if (max_subkey) *max_subkey = info->MaxNameLen;
671 if (max_class) *max_class = info->MaxClassLen;
672 if (values) *values = info->Values;
673 if (max_value) *max_value = info->MaxValueNameLen;
674 if (max_data) *max_data = info->MaxValueDataLen;
675 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
677 done:
678 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
679 return RtlNtStatusToDosError( status );
683 /******************************************************************************
684 * RegQueryMultipleValuesA [ADVAPI32.@]
686 * Retrieves the type and data for a list of value names associated with a key.
688 * PARAMS
689 * hKey [I] Handle to an open key.
690 * val_list [O] Array of VALENT structures that describes the entries.
691 * num_vals [I] Number of elements in val_list.
692 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
693 * ldwTotsize [I/O] Size of lpValueBuf.
695 * RETURNS
696 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
697 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
698 * bytes.
700 DWORD WINAPI RegQueryMultipleValuesA(HKEY hkey, PVALENTA val_list, DWORD num_vals,
701 LPSTR lpValueBuf, LPDWORD ldwTotsize)
703 unsigned int i;
704 DWORD maxBytes = *ldwTotsize;
705 HRESULT status;
706 LPSTR bufptr = lpValueBuf;
707 *ldwTotsize = 0;
709 TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
711 for(i=0; i < num_vals; ++i)
714 val_list[i].ve_valuelen=0;
715 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
716 if(status != ERROR_SUCCESS)
718 return status;
721 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
723 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
724 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
725 if(status != ERROR_SUCCESS)
727 return status;
730 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
732 bufptr += val_list[i].ve_valuelen;
735 *ldwTotsize += val_list[i].ve_valuelen;
737 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
741 /******************************************************************************
742 * RegQueryMultipleValuesW [ADVAPI32.@]
744 * See RegQueryMultipleValuesA.
746 DWORD WINAPI RegQueryMultipleValuesW(HKEY hkey, PVALENTW val_list, DWORD num_vals,
747 LPWSTR lpValueBuf, LPDWORD ldwTotsize)
749 unsigned int i;
750 DWORD maxBytes = *ldwTotsize;
751 HRESULT status;
752 LPSTR bufptr = (LPSTR)lpValueBuf;
753 *ldwTotsize = 0;
755 TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
757 for(i=0; i < num_vals; ++i)
759 val_list[i].ve_valuelen=0;
760 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
761 if(status != ERROR_SUCCESS)
763 return status;
766 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
768 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
769 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
770 if(status != ERROR_SUCCESS)
772 return status;
775 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
777 bufptr += val_list[i].ve_valuelen;
780 *ldwTotsize += val_list[i].ve_valuelen;
782 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
785 /******************************************************************************
786 * RegQueryInfoKeyA [ADVAPI32.@]
788 * Retrieves information about a registry key.
790 * PARAMS
791 * hKey [I] Handle to an open key.
792 * lpClass [O] Class string of the key.
793 * lpcClass [I/O] size of lpClass.
794 * lpReserved [I] Reserved; must be NULL.
795 * lpcSubKeys [O] Number of subkeys contained by the key.
796 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
797 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
798 * class in TCHARS.
799 * lpcValues [O] Number of values associated with the key.
800 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
801 * lpcMaxValueLen [O] Longest data component among the key's values
802 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
803 * lpftLastWriteTime [O] FILETIME strucutre that is the last write time.
805 * RETURNS
806 * Success: ERROR_SUCCESS
807 * Failure: nonzero error code from Winerror.h
809 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
810 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
811 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
812 LPDWORD security, FILETIME *modif )
814 NTSTATUS status;
815 char buffer[256], *buf_ptr = buffer;
816 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
817 DWORD total_size, len;
819 TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
820 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
822 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
823 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
825 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
826 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
828 if (class || class_len)
830 /* retry with a dynamically allocated buffer */
831 while (status == STATUS_BUFFER_OVERFLOW)
833 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
834 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
835 return ERROR_NOT_ENOUGH_MEMORY;
836 info = (KEY_FULL_INFORMATION *)buf_ptr;
837 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
840 if (status) goto done;
842 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
843 if (class_len)
845 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
846 *class_len = len;
848 if (class && !status)
850 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
851 info->ClassLength );
852 class[len] = 0;
855 else status = STATUS_SUCCESS;
857 if (subkeys) *subkeys = info->SubKeys;
858 if (max_subkey) *max_subkey = info->MaxNameLen;
859 if (max_class) *max_class = info->MaxClassLen;
860 if (values) *values = info->Values;
861 if (max_value) *max_value = info->MaxValueNameLen;
862 if (max_data) *max_data = info->MaxValueDataLen;
863 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
865 done:
866 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
867 return RtlNtStatusToDosError( status );
871 /******************************************************************************
872 * RegCloseKey [ADVAPI32.@]
874 * Close an open registry key.
876 * PARAMS
877 * hkey [I] Handle of key to close
879 * RETURNS
880 * Success: ERROR_SUCCESS
881 * Failure: Error code
883 DWORD WINAPI RegCloseKey( HKEY hkey )
885 if (!hkey) return ERROR_INVALID_HANDLE;
886 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
887 return RtlNtStatusToDosError( NtClose( hkey ) );
891 /******************************************************************************
892 * RegDeleteKeyW [ADVAPI32.@]
894 * See RegDeleteKeyA.
896 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
898 DWORD ret;
899 HKEY tmp;
901 if (!name) return ERROR_INVALID_PARAMETER;
903 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
905 if (!(ret = RegOpenKeyExW( hkey, name, 0, DELETE, &tmp )))
907 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
908 RegCloseKey( tmp );
910 TRACE("%s ret=%08lx\n", debugstr_w(name), ret);
911 return ret;
915 /******************************************************************************
916 * RegDeleteKeyA [ADVAPI32.@]
918 * Delete a registry key.
920 * PARAMS
921 * hkey [I] Handle to parent key containing the key to delete
922 * name [I] Name of the key user hkey to delete
924 * NOTES
926 * MSDN is wrong when it says that hkey must be opened with the DELETE access
927 * right. In reality, it opens a new handle with DELETE access.
929 * RETURNS
930 * Success: ERROR_SUCCESS
931 * Failure: Error code
933 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
935 DWORD ret;
936 HKEY tmp;
938 if (!name) return ERROR_INVALID_PARAMETER;
940 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
942 if (!(ret = RegOpenKeyExA( hkey, name, 0, DELETE, &tmp )))
944 if (!is_version_nt()) /* win95 does recursive key deletes */
946 CHAR name[MAX_PATH];
948 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
950 if(RegDeleteKeyA(tmp, name)) /* recurse */
951 break;
954 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
955 RegCloseKey( tmp );
957 TRACE("%s ret=%08lx\n", debugstr_a(name), ret);
958 return ret;
963 /******************************************************************************
964 * RegSetValueExW [ADVAPI32.@]
966 * Set the data and contents of a registry value.
968 * PARAMS
969 * hkey [I] Handle of key to set value for
970 * name [I] Name of value to set
971 * reserved [I] Reserved, must be zero
972 * type [I] Type of the value being set
973 * data [I] The new contents of the value to set
974 * count [I] Size of data
976 * RETURNS
977 * Success: ERROR_SUCCESS
978 * Failure: Error code
980 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
981 DWORD type, CONST BYTE *data, DWORD count )
983 UNICODE_STRING nameW;
985 /* no need for version check, not implemented on win9x anyway */
986 if (count && is_string(type))
988 LPCWSTR str = (LPCWSTR)data;
989 /* if user forgot to count terminating null, add it (yes NT does this) */
990 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
991 count += sizeof(WCHAR);
993 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
995 RtlInitUnicodeString( &nameW, name );
996 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1000 /******************************************************************************
1001 * RegSetValueExA [ADVAPI32.@]
1003 * See RegSetValueExW.
1005 * NOTES
1006 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1007 * NT does definitely care (aj)
1009 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1010 CONST BYTE *data, DWORD count )
1012 ANSI_STRING nameA;
1013 WCHAR *dataW = NULL;
1014 NTSTATUS status;
1016 if (!is_version_nt()) /* win95 */
1018 if (type == REG_SZ)
1020 if (!data) return ERROR_INVALID_PARAMETER;
1021 count = strlen((const char *)data) + 1;
1024 else if (count && is_string(type))
1026 /* if user forgot to count terminating null, add it (yes NT does this) */
1027 if (data[count-1] && !data[count]) count++;
1030 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1032 if (is_string( type )) /* need to convert to Unicode */
1034 DWORD lenW;
1035 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1036 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1037 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1038 count = lenW;
1039 data = (BYTE *)dataW;
1042 RtlInitAnsiString( &nameA, name );
1043 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1044 &nameA, FALSE )))
1046 status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
1048 HeapFree( GetProcessHeap(), 0, dataW );
1049 return RtlNtStatusToDosError( status );
1053 /******************************************************************************
1054 * RegSetValueW [ADVAPI32.@]
1056 * Sets the data for the default or unnamed value of a reg key.
1058 * PARAMS
1059 * hKey [I] Handle to an open key.
1060 * lpSubKey [I] Name of a subkey of hKey.
1061 * dwType [I] Type of information to store.
1062 * lpData [I] String that contains the data to set for the default value.
1063 * cbData [I] Size of lpData.
1065 * RETURNS
1066 * Success: ERROR_SUCCESS
1067 * Failure: nonzero error code from Winerror.h
1069 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1071 HKEY subkey = hkey;
1072 DWORD ret;
1074 TRACE("(%p,%s,%ld,%s,%ld)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1076 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
1078 if (name && name[0]) /* need to create the subkey */
1080 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1083 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1084 (strlenW( data ) + 1) * sizeof(WCHAR) );
1085 if (subkey != hkey) RegCloseKey( subkey );
1086 return ret;
1090 /******************************************************************************
1091 * RegSetValueA [ADVAPI32.@]
1093 * See RegSetValueW.
1095 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1097 HKEY subkey = hkey;
1098 DWORD ret;
1100 TRACE("(%p,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1102 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
1104 if (name && name[0]) /* need to create the subkey */
1106 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1108 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1109 if (subkey != hkey) RegCloseKey( subkey );
1110 return ret;
1115 /******************************************************************************
1116 * RegQueryValueExW [ADVAPI32.@]
1118 * See RegQueryValueExA.
1120 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1121 LPBYTE data, LPDWORD count )
1123 NTSTATUS status;
1124 UNICODE_STRING name_str;
1125 DWORD total_size;
1126 char buffer[256], *buf_ptr = buffer;
1127 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1128 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1130 TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1131 hkey, debugstr_w(name), reserved, type, data, count,
1132 (count && data) ? *count : 0 );
1134 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1135 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1137 RtlInitUnicodeString( &name_str, name );
1139 if (data) total_size = min( sizeof(buffer), *count + info_size );
1140 else total_size = info_size;
1142 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1143 buffer, total_size, &total_size );
1144 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1146 if (data)
1148 /* retry with a dynamically allocated buffer */
1149 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1151 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1152 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1153 return ERROR_NOT_ENOUGH_MEMORY;
1154 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1155 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1156 buf_ptr, total_size, &total_size );
1159 if (!status)
1161 memcpy( data, buf_ptr + info_size, total_size - info_size );
1162 /* if the type is REG_SZ and data is not 0-terminated
1163 * and there is enough space in the buffer NT appends a \0 */
1164 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1166 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1167 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1170 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1172 else status = STATUS_SUCCESS;
1174 if (type) *type = info->Type;
1175 if (count) *count = total_size - info_size;
1177 done:
1178 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1179 return RtlNtStatusToDosError(status);
1183 /******************************************************************************
1184 * RegQueryValueExA [ADVAPI32.@]
1186 * Get the type and contents of a specified value under with a key.
1188 * PARAMS
1189 * hkey [I] Handle of the key to query
1190 * name [I] Name of value under hkey to query
1191 * reserved [I] Reserved - must be NULL
1192 * type [O] Destination for the value type, or NULL if not required
1193 * data [O] Destination for the values contents, or NULL if not required
1194 * count [I/O] Size of data, updated with the number of bytes returned
1196 * RETURNS
1197 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1198 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1199 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1200 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1202 * NOTES
1203 * MSDN states that if data is too small it is partially filled. In reality
1204 * it remains untouched.
1206 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1207 LPBYTE data, LPDWORD count )
1209 NTSTATUS status;
1210 ANSI_STRING nameA;
1211 DWORD total_size;
1212 char buffer[256], *buf_ptr = buffer;
1213 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1214 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1216 TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1217 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1219 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1220 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1222 RtlInitAnsiString( &nameA, name );
1223 if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1224 &nameA, FALSE )))
1225 return RtlNtStatusToDosError(status);
1227 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1228 KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
1229 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1231 /* we need to fetch the contents for a string type even if not requested,
1232 * because we need to compute the length of the ASCII string. */
1233 if (data || is_string(info->Type))
1235 /* retry with a dynamically allocated buffer */
1236 while (status == STATUS_BUFFER_OVERFLOW)
1238 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1239 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1241 status = STATUS_NO_MEMORY;
1242 goto done;
1244 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1245 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1246 KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1249 if (status) goto done;
1251 if (is_string(info->Type))
1253 DWORD len;
1255 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1256 total_size - info_size );
1257 if (data && len)
1259 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1260 else
1262 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1263 total_size - info_size );
1264 /* if the type is REG_SZ and data is not 0-terminated
1265 * and there is enough space in the buffer NT appends a \0 */
1266 if (len < *count && data[len-1]) data[len] = 0;
1269 total_size = len + info_size;
1271 else if (data)
1273 if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
1274 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1277 else status = STATUS_SUCCESS;
1279 if (type) *type = info->Type;
1280 if (count) *count = total_size - info_size;
1282 done:
1283 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1284 return RtlNtStatusToDosError(status);
1288 /******************************************************************************
1289 * RegQueryValueW [ADVAPI32.@]
1291 * Retrieves the data associated with the default or unnamed value of a key.
1293 * PARAMS
1294 * hkey [I] Handle to an open key.
1295 * name [I] Name of the subkey of hKey.
1296 * data [O] Receives the string associated with the default value
1297 * of the key.
1298 * count [I/O] Size of lpValue in bytes.
1300 * RETURNS
1301 * Success: ERROR_SUCCESS
1302 * Failure: nonzero error code from Winerror.h
1304 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1306 DWORD ret;
1307 HKEY subkey = hkey;
1309 TRACE("(%p,%s,%p,%ld)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1311 if (name && name[0])
1313 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1315 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1316 if (subkey != hkey) RegCloseKey( subkey );
1317 if (ret == ERROR_FILE_NOT_FOUND)
1319 /* return empty string if default value not found */
1320 if (data) *data = 0;
1321 if (count) *count = sizeof(WCHAR);
1322 ret = ERROR_SUCCESS;
1324 return ret;
1328 /******************************************************************************
1329 * RegQueryValueA [ADVAPI32.@]
1331 * See RegQueryValueW.
1333 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1335 DWORD ret;
1336 HKEY subkey = hkey;
1338 TRACE("(%p,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1340 if (name && name[0])
1342 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1344 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1345 if (subkey != hkey) RegCloseKey( subkey );
1346 if (ret == ERROR_FILE_NOT_FOUND)
1348 /* return empty string if default value not found */
1349 if (data) *data = 0;
1350 if (count) *count = 1;
1351 ret = ERROR_SUCCESS;
1353 return ret;
1357 /******************************************************************************
1358 * ADVAPI_ApplyRestrictions [internal]
1360 * Helper function for RegGetValueA/W.
1362 VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType, DWORD cbData,
1363 PLONG ret )
1365 /* Check if the type is restricted by the passed flags */
1366 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1368 DWORD dwMask = 0;
1370 switch (dwType)
1372 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1373 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1374 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1375 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1376 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1377 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1378 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1381 if (dwFlags & dwMask)
1383 /* Type is not restricted, check for size mismatch */
1384 if (dwType == REG_BINARY)
1386 DWORD cbExpect = 0;
1388 if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD)
1389 cbExpect = 4;
1390 else if ((dwFlags & RRF_RT_DWORD) == RRF_RT_QWORD)
1391 cbExpect = 8;
1393 if (cbExpect && cbData != cbExpect)
1394 *ret = ERROR_DATATYPE_MISMATCH;
1397 else *ret = ERROR_UNSUPPORTED_TYPE;
1402 /******************************************************************************
1403 * RegGetValueW [ADVAPI32.@]
1405 * Retrieves the type and data for a value name associated with a key
1406 * optionally expanding it's content and restricting it's type.
1408 * PARAMS
1409 * hKey [I] Handle to an open key.
1410 * pszSubKey [I] Name of the subkey of hKey.
1411 * pszValue [I] Name of value under hKey/szSubKey to query.
1412 * dwFlags [I] Flags restricting the value type to retrieve.
1413 * pdwType [O] Destination for the values type, may be NULL.
1414 * pvData [O] Destination for the values content, may be NULL.
1415 * pcbData [I/O] Size of pvData, updated with the size required to
1416 * retrieve the whole content.
1418 * RETURNS
1419 * Success: ERROR_SUCCESS
1420 * Failure: nonzero error code from Winerror.h
1422 * NOTES
1423 * - Unless RRF_NOEXPAND is specified REG_EXPAND_SZ is automatically expanded
1424 * and REG_SZ is retrieved instead.
1425 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1426 * without RRF_NOEXPAND is thus not allowed.
1428 LONG WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1429 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1430 LPDWORD pcbData )
1432 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1433 PVOID pvBuf = NULL;
1434 LONG ret;
1436 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1437 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1438 pvData, pcbData, cbData);
1440 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
1441 return ERROR_INVALID_PARAMETER;
1443 if (pszSubKey && pszSubKey[0])
1445 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1446 if (ret != ERROR_SUCCESS) return ret;
1449 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1451 /* If we are going to expand we need to read in the whole the value even
1452 * if the passed buffer was too small as the expanded string might be
1453 * smaller than the unexpanded one and could fit into cbData bytes. */
1454 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1455 (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
1457 do {
1458 HeapFree(GetProcessHeap(), 0, pvBuf);
1460 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1461 if (!pvBuf)
1463 ret = ERROR_NOT_ENOUGH_MEMORY;
1464 break;
1467 if (ret == ERROR_MORE_DATA)
1468 ret = RegQueryValueExW(hKey, pszValue, NULL,
1469 &dwType, pvBuf, &cbData);
1470 else
1472 /* Even if cbData was large enough we have to copy the
1473 * string since ExpandEnvironmentStrings can't handle
1474 * overlapping buffers. */
1475 CopyMemory(pvBuf, pvData, cbData);
1478 /* Both the type or the value itself could have been modified in
1479 * between so we have to keep retrying until the buffer is large
1480 * enough or we no longer have to expand the value. */
1481 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1483 if (ret == ERROR_SUCCESS)
1485 if (dwType == REG_EXPAND_SZ)
1487 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1488 pcbData ? *pcbData : 0);
1489 dwType = REG_SZ;
1490 if(pcbData && cbData > *pcbData)
1491 ret = ERROR_MORE_DATA;
1493 else if (pcbData)
1494 CopyMemory(pvData, pvBuf, *pcbData);
1497 HeapFree(GetProcessHeap(), 0, pvBuf);
1500 if (pszSubKey && pszSubKey[0])
1501 RegCloseKey(hKey);
1503 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1505 if (pcbData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1506 ZeroMemory(pvData, *pcbData);
1508 if (pdwType) *pdwType = dwType;
1509 if (pcbData) *pcbData = cbData;
1511 return ret;
1515 /******************************************************************************
1516 * RegGetValueA [ADVAPI32.@]
1518 * See RegGetValueW.
1520 LONG WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1521 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1522 LPDWORD pcbData )
1524 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1525 PVOID pvBuf = NULL;
1526 LONG ret;
1528 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1529 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1530 cbData);
1532 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
1533 return ERROR_INVALID_PARAMETER;
1535 if (pszSubKey && pszSubKey[0])
1537 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1538 if (ret != ERROR_SUCCESS) return ret;
1541 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1543 /* If we are going to expand we need to read in the whole the value even
1544 * if the passed buffer was too small as the expanded string might be
1545 * smaller than the unexpanded one and could fit into cbData bytes. */
1546 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1547 (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
1549 do {
1550 HeapFree(GetProcessHeap(), 0, pvBuf);
1552 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1553 if (!pvBuf)
1555 ret = ERROR_NOT_ENOUGH_MEMORY;
1556 break;
1559 if (ret == ERROR_MORE_DATA)
1560 ret = RegQueryValueExA(hKey, pszValue, NULL,
1561 &dwType, pvBuf, &cbData);
1562 else
1564 /* Even if cbData was large enough we have to copy the
1565 * string since ExpandEnvironmentStrings can't handle
1566 * overlapping buffers. */
1567 CopyMemory(pvBuf, pvData, cbData);
1570 /* Both the type or the value itself could have been modified in
1571 * between so we have to keep retrying until the buffer is large
1572 * enough or we no longer have to expand the value. */
1573 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1575 if (ret == ERROR_SUCCESS)
1577 if (dwType == REG_EXPAND_SZ)
1579 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1580 pcbData ? *pcbData : 0);
1581 dwType = REG_SZ;
1582 if(pcbData && cbData > *pcbData)
1583 ret = ERROR_MORE_DATA;
1585 else if (pcbData)
1586 CopyMemory(pvData, pvBuf, *pcbData);
1589 HeapFree(GetProcessHeap(), 0, pvBuf);
1592 if (pszSubKey && pszSubKey[0])
1593 RegCloseKey(hKey);
1595 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1597 if (pcbData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1598 ZeroMemory(pvData, *pcbData);
1600 if (pdwType) *pdwType = dwType;
1601 if (pcbData) *pcbData = cbData;
1603 return ret;
1607 /******************************************************************************
1608 * RegEnumValueW [ADVAPI32.@]
1610 * Enumerates the values for the specified open registry key.
1612 * PARAMS
1613 * hkey [I] Handle to key to query
1614 * index [I] Index of value to query
1615 * value [O] Value string
1616 * val_count [I/O] Size of value buffer (in wchars)
1617 * reserved [I] Reserved
1618 * type [O] Type code
1619 * data [O] Value data
1620 * count [I/O] Size of data buffer (in bytes)
1622 * RETURNS
1623 * Success: ERROR_SUCCESS
1624 * Failure: nonzero error code from Winerror.h
1627 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1628 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1630 NTSTATUS status;
1631 DWORD total_size;
1632 char buffer[256], *buf_ptr = buffer;
1633 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1634 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1636 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1637 hkey, index, value, val_count, reserved, type, data, count );
1639 /* NT only checks count, not val_count */
1640 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1641 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1643 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1644 if (data) total_size += *count;
1645 total_size = min( sizeof(buffer), total_size );
1647 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1648 buffer, total_size, &total_size );
1649 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1651 if (value || data)
1653 /* retry with a dynamically allocated buffer */
1654 while (status == STATUS_BUFFER_OVERFLOW)
1656 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1657 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1658 return ERROR_NOT_ENOUGH_MEMORY;
1659 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1660 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1661 buf_ptr, total_size, &total_size );
1664 if (status) goto done;
1666 if (value)
1668 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1670 status = STATUS_BUFFER_OVERFLOW;
1671 goto overflow;
1673 memcpy( value, info->Name, info->NameLength );
1674 *val_count = info->NameLength / sizeof(WCHAR);
1675 value[*val_count] = 0;
1678 if (data)
1680 if (total_size - info->DataOffset > *count)
1682 status = STATUS_BUFFER_OVERFLOW;
1683 goto overflow;
1685 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1686 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1688 /* if the type is REG_SZ and data is not 0-terminated
1689 * and there is enough space in the buffer NT appends a \0 */
1690 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1691 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1695 else status = STATUS_SUCCESS;
1697 overflow:
1698 if (type) *type = info->Type;
1699 if (count) *count = info->DataLength;
1701 done:
1702 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1703 return RtlNtStatusToDosError(status);
1707 /******************************************************************************
1708 * RegEnumValueA [ADVAPI32.@]
1710 * See RegEnumValueW.
1712 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1713 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1715 NTSTATUS status;
1716 DWORD total_size;
1717 char buffer[256], *buf_ptr = buffer;
1718 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1719 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1721 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1722 hkey, index, value, val_count, reserved, type, data, count );
1724 /* NT only checks count, not val_count */
1725 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1726 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1728 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1729 if (data) total_size += *count;
1730 total_size = min( sizeof(buffer), total_size );
1732 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1733 buffer, total_size, &total_size );
1734 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1736 /* we need to fetch the contents for a string type even if not requested,
1737 * because we need to compute the length of the ASCII string. */
1738 if (value || data || is_string(info->Type))
1740 /* retry with a dynamically allocated buffer */
1741 while (status == STATUS_BUFFER_OVERFLOW)
1743 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1744 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1745 return ERROR_NOT_ENOUGH_MEMORY;
1746 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1747 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1748 buf_ptr, total_size, &total_size );
1751 if (status) goto done;
1753 if (is_string(info->Type))
1755 DWORD len;
1756 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1757 total_size - info->DataOffset );
1758 if (data && len)
1760 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1761 else
1763 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1764 total_size - info->DataOffset );
1765 /* if the type is REG_SZ and data is not 0-terminated
1766 * and there is enough space in the buffer NT appends a \0 */
1767 if (len < *count && data[len-1]) data[len] = 0;
1770 info->DataLength = len;
1772 else if (data)
1774 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1775 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1778 if (value && !status)
1780 DWORD len;
1782 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1783 if (len >= *val_count)
1785 status = STATUS_BUFFER_OVERFLOW;
1786 if (*val_count)
1788 len = *val_count - 1;
1789 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1790 value[len] = 0;
1793 else
1795 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1796 value[len] = 0;
1797 *val_count = len;
1801 else status = STATUS_SUCCESS;
1803 if (type) *type = info->Type;
1804 if (count) *count = info->DataLength;
1806 done:
1807 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1808 return RtlNtStatusToDosError(status);
1813 /******************************************************************************
1814 * RegDeleteValueW [ADVAPI32.@]
1816 * See RegDeleteValueA.
1818 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1820 UNICODE_STRING nameW;
1822 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1824 RtlInitUnicodeString( &nameW, name );
1825 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1829 /******************************************************************************
1830 * RegDeleteValueA [ADVAPI32.@]
1832 * Delete a value from the registry.
1834 * PARAMS
1835 * hkey [I] Registry handle of the key holding the value
1836 * name [I] Name of the value under hkey to delete
1838 * RETURNS
1839 * Success: ERROR_SUCCESS
1840 * Failure: nonzero error code from Winerror.h
1842 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1844 STRING nameA;
1845 NTSTATUS status;
1847 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1849 RtlInitAnsiString( &nameA, name );
1850 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1851 &nameA, FALSE )))
1852 status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1853 return RtlNtStatusToDosError( status );
1857 /******************************************************************************
1858 * RegLoadKeyW [ADVAPI32.@]
1860 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1861 * registration information from a specified file into that subkey.
1863 * PARAMS
1864 * hkey [I] Handle of open key
1865 * subkey [I] Address of name of subkey
1866 * filename [I] Address of filename for registry information
1868 * RETURNS
1869 * Success: ERROR_SUCCES
1870 * Failure: nonzero error code from Winerror.h
1872 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1874 OBJECT_ATTRIBUTES destkey, file;
1875 UNICODE_STRING subkeyW, filenameW;
1877 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
1879 destkey.Length = sizeof(destkey);
1880 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
1881 destkey.ObjectName = &subkeyW; /* name of the key */
1882 destkey.Attributes = 0;
1883 destkey.SecurityDescriptor = NULL;
1884 destkey.SecurityQualityOfService = NULL;
1885 RtlInitUnicodeString(&subkeyW, subkey);
1887 file.Length = sizeof(file);
1888 file.RootDirectory = NULL;
1889 file.ObjectName = &filenameW; /* file containing the hive */
1890 file.Attributes = OBJ_CASE_INSENSITIVE;
1891 file.SecurityDescriptor = NULL;
1892 file.SecurityQualityOfService = NULL;
1893 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
1895 return RtlNtStatusToDosError( NtLoadKey(&destkey, &file) );
1899 /******************************************************************************
1900 * RegLoadKeyA [ADVAPI32.@]
1902 * See RegLoadKeyW.
1904 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1906 UNICODE_STRING subkeyW, filenameW;
1907 STRING subkeyA, filenameA;
1908 NTSTATUS status;
1910 RtlInitAnsiString(&subkeyA, subkey);
1911 RtlInitAnsiString(&filenameA, filename);
1913 if ((status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)))
1914 return RtlNtStatusToDosError(status);
1916 if ((status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
1917 return RtlNtStatusToDosError(status);
1919 return RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
1923 /******************************************************************************
1924 * RegSaveKeyW [ADVAPI32.@]
1926 * Save a key and all of its subkeys and values to a new file in the standard format.
1928 * PARAMS
1929 * hkey [I] Handle of key where save begins
1930 * lpFile [I] Address of filename to save to
1931 * sa [I] Address of security structure
1933 * RETURNS
1934 * Success: ERROR_SUCCESS
1935 * Failure: nonzero error code from Winerror.h
1937 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1939 static const WCHAR format[] =
1940 {'r','e','g','%','0','4','x','.','t','m','p',0};
1941 WCHAR buffer[MAX_PATH];
1942 int count = 0;
1943 LPWSTR nameW;
1944 DWORD ret, err;
1945 HANDLE handle;
1947 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
1949 if (!file || !*file) return ERROR_INVALID_PARAMETER;
1950 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1952 err = GetLastError();
1953 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
1955 for (;;)
1957 snprintfW( nameW, 16, format, count++ );
1958 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1959 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1960 if (handle != INVALID_HANDLE_VALUE) break;
1961 if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
1963 /* Something gone haywire ? Please report if this happens abnormally */
1964 if (count >= 100)
1965 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);
1968 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
1970 CloseHandle( handle );
1971 if (!ret)
1973 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
1975 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
1976 debugstr_w(file) );
1977 ret = GetLastError();
1980 if (ret) DeleteFileW( buffer );
1982 done:
1983 SetLastError( err ); /* restore last error code */
1984 return ret;
1988 /******************************************************************************
1989 * RegSaveKeyA [ADVAPI32.@]
1991 * See RegSaveKeyW.
1993 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
1995 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
1996 NTSTATUS status;
1997 STRING fileA;
1999 RtlInitAnsiString(&fileA, file);
2000 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2001 return RtlNtStatusToDosError( status );
2002 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2006 /******************************************************************************
2007 * RegRestoreKeyW [ADVAPI32.@]
2009 * Read the registry information from a file and copy it over a key.
2011 * PARAMS
2012 * hkey [I] Handle of key where restore begins
2013 * lpFile [I] Address of filename containing saved tree
2014 * dwFlags [I] Optional flags
2016 * RETURNS
2017 * Success: ERROR_SUCCESS
2018 * Failure: nonzero error code from Winerror.h
2020 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2022 TRACE("(%p,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
2024 /* It seems to do this check before the hkey check */
2025 if (!lpFile || !*lpFile)
2026 return ERROR_INVALID_PARAMETER;
2028 FIXME("(%p,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2030 /* Check for file existence */
2032 return ERROR_SUCCESS;
2036 /******************************************************************************
2037 * RegRestoreKeyA [ADVAPI32.@]
2039 * See RegRestoreKeyW.
2041 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2043 UNICODE_STRING lpFileW;
2044 LONG ret;
2046 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2047 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2048 RtlFreeUnicodeString( &lpFileW );
2049 return ret;
2053 /******************************************************************************
2054 * RegUnLoadKeyW [ADVAPI32.@]
2056 * Unload a registry key and its subkeys from the registry.
2058 * PARAMS
2059 * hkey [I] Handle of open key
2060 * lpSubKey [I] Address of name of subkey to unload
2062 * RETURNS
2063 * Success: ERROR_SUCCESS
2064 * Failure: nonzero error code from Winerror.h
2066 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2068 DWORD ret;
2069 HKEY shkey;
2071 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2073 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2074 if( ret )
2075 return ERROR_INVALID_PARAMETER;
2077 ret = RtlNtStatusToDosError(NtUnloadKey(shkey));
2079 RegCloseKey(shkey);
2081 return ret;
2085 /******************************************************************************
2086 * RegUnLoadKeyA [ADVAPI32.@]
2088 * See RegUnLoadKeyW.
2090 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2092 UNICODE_STRING lpSubKeyW;
2093 LONG ret;
2095 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2096 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2097 RtlFreeUnicodeString( &lpSubKeyW );
2098 return ret;
2102 /******************************************************************************
2103 * RegReplaceKeyW [ADVAPI32.@]
2105 * Replace the file backing a registry key and all its subkeys with another file.
2107 * PARAMS
2108 * hkey [I] Handle of open key
2109 * lpSubKey [I] Address of name of subkey
2110 * lpNewFile [I] Address of filename for file with new data
2111 * lpOldFile [I] Address of filename for backup file
2113 * RETURNS
2114 * Success: ERROR_SUCCESS
2115 * Failure: nonzero error code from Winerror.h
2117 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2118 LPCWSTR lpOldFile )
2120 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2121 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2122 return ERROR_SUCCESS;
2126 /******************************************************************************
2127 * RegReplaceKeyA [ADVAPI32.@]
2129 * See RegReplaceKeyW.
2131 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2132 LPCSTR lpOldFile )
2134 UNICODE_STRING lpSubKeyW;
2135 UNICODE_STRING lpNewFileW;
2136 UNICODE_STRING lpOldFileW;
2137 LONG ret;
2139 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2140 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2141 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2142 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2143 RtlFreeUnicodeString( &lpOldFileW );
2144 RtlFreeUnicodeString( &lpNewFileW );
2145 RtlFreeUnicodeString( &lpSubKeyW );
2146 return ret;
2150 /******************************************************************************
2151 * RegSetKeySecurity [ADVAPI32.@]
2153 * Set the security of an open registry key.
2155 * PARAMS
2156 * hkey [I] Open handle of key to set
2157 * SecurityInfo [I] Descriptor contents
2158 * pSecurityDesc [I] Address of descriptor for key
2160 * RETURNS
2161 * Success: ERROR_SUCCESS
2162 * Failure: nonzero error code from Winerror.h
2164 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2165 PSECURITY_DESCRIPTOR pSecurityDesc )
2167 TRACE("(%p,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2169 /* It seems to perform this check before the hkey check */
2170 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2171 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2172 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2173 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2174 /* Param OK */
2175 } else
2176 return ERROR_INVALID_PARAMETER;
2178 if (!pSecurityDesc)
2179 return ERROR_INVALID_PARAMETER;
2181 FIXME(":(%p,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2183 return ERROR_SUCCESS;
2187 /******************************************************************************
2188 * RegGetKeySecurity [ADVAPI32.@]
2190 * Get a copy of the security descriptor for a given registry key.
2192 * PARAMS
2193 * hkey [I] Open handle of key to set
2194 * SecurityInformation [I] Descriptor contents
2195 * pSecurityDescriptor [O] Address of descriptor for key
2196 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2198 * RETURNS
2199 * Success: ERROR_SUCCESS
2200 * Failure: Error code
2202 LONG WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2203 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2204 LPDWORD lpcbSecurityDescriptor )
2206 TRACE("(%p,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
2207 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
2209 /* FIXME: Check for valid SecurityInformation values */
2211 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
2212 return ERROR_INSUFFICIENT_BUFFER;
2214 FIXME("(%p,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
2215 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
2217 /* Do not leave security descriptor filled with garbage */
2218 RtlCreateSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2220 return ERROR_SUCCESS;
2224 /******************************************************************************
2225 * RegFlushKey [ADVAPI32.@]
2227 * Immediately write a registry key to registry.
2229 * PARAMS
2230 * hkey [I] Handle of key to write
2232 * RETURNS
2233 * Success: ERROR_SUCCESS
2234 * Failure: Error code
2236 DWORD WINAPI RegFlushKey( HKEY hkey )
2238 hkey = get_special_root_hkey( hkey );
2239 if (!hkey) return ERROR_INVALID_HANDLE;
2241 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2245 /******************************************************************************
2246 * RegConnectRegistryW [ADVAPI32.@]
2248 * Establishe a connection to a predefined registry key on another computer.
2250 * PARAMS
2251 * lpMachineName [I] Address of name of remote computer
2252 * hHey [I] Predefined registry handle
2253 * phkResult [I] Address of buffer for remote registry handle
2255 * RETURNS
2256 * Success: ERROR_SUCCESS
2257 * Failure: nonzero error code from Winerror.h
2259 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2260 PHKEY phkResult )
2262 LONG ret;
2264 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2266 if (!lpMachineName || !*lpMachineName) {
2267 /* Use the local machine name */
2268 ret = RegOpenKeyW( hKey, NULL, phkResult );
2270 else {
2271 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2272 DWORD len = sizeof(compName) / sizeof(WCHAR);
2274 /* MSDN says lpMachineName must start with \\ : not so */
2275 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2276 lpMachineName += 2;
2277 if (GetComputerNameW(compName, &len))
2279 if (!strcmpiW(lpMachineName, compName))
2280 ret = RegOpenKeyW(hKey, NULL, phkResult);
2281 else
2283 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2284 ret = ERROR_BAD_NETPATH;
2287 else
2288 ret = GetLastError();
2290 return ret;
2294 /******************************************************************************
2295 * RegConnectRegistryA [ADVAPI32.@]
2297 * See RegConnectRegistryW.
2299 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2301 UNICODE_STRING machineW;
2302 LONG ret;
2304 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2305 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2306 RtlFreeUnicodeString( &machineW );
2307 return ret;
2311 /******************************************************************************
2312 * RegNotifyChangeKeyValue [ADVAPI32.@]
2314 * Notify the caller about changes to the attributes or contents of a registry key.
2316 * PARAMS
2317 * hkey [I] Handle of key to watch
2318 * fWatchSubTree [I] Flag for subkey notification
2319 * fdwNotifyFilter [I] Changes to be reported
2320 * hEvent [I] Handle of signaled event
2321 * fAsync [I] Flag for asynchronous reporting
2323 * RETURNS
2324 * Success: ERROR_SUCCESS
2325 * Failure: nonzero error code from Winerror.h
2327 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2328 DWORD fdwNotifyFilter, HANDLE hEvent,
2329 BOOL fAsync )
2331 NTSTATUS status;
2332 IO_STATUS_BLOCK iosb;
2334 hkey = get_special_root_hkey( hkey );
2335 if (!hkey) return ERROR_INVALID_HANDLE;
2337 TRACE("(%p,%i,%ld,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2338 hEvent, fAsync);
2340 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2341 fdwNotifyFilter, fAsync, NULL, 0,
2342 fWatchSubTree);
2344 if (status && status != STATUS_TIMEOUT)
2345 return RtlNtStatusToDosError( status );
2347 return ERROR_SUCCESS;
2350 /******************************************************************************
2351 * RegOpenUserClassesRoot [ADVAPI32.@]
2353 * Open the HKEY_CLASSES_ROOT key for a user.
2355 * PARAMS
2356 * hToken [I] Handle of token representing the user
2357 * dwOptions [I] Reserved, nust be 0
2358 * samDesired [I] Desired access rights
2359 * phkResult [O] Destination for the resulting key handle
2361 * RETURNS
2362 * Success: ERROR_SUCCESS
2363 * Failure: nonzero error code from Winerror.h
2365 * NOTES
2366 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2367 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2368 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2370 LONG WINAPI RegOpenUserClassesRoot(
2371 HANDLE hToken,
2372 DWORD dwOptions,
2373 REGSAM samDesired,
2374 PHKEY phkResult
2377 FIXME("(%p, 0x%lx, 0x%lx, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2379 *phkResult = HKEY_CLASSES_ROOT;
2380 return ERROR_SUCCESS;
2383 /******************************************************************************
2384 * load_string [Internal]
2386 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2387 * avoid importing user32, which is higher level than advapi32. Helper for
2388 * RegLoadMUIString.
2390 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2392 HGLOBAL hMemory;
2393 HRSRC hResource;
2394 WCHAR *pString;
2395 int idxString;
2397 /* Negative values have to be inverted. */
2398 if (HIWORD(resId) == 0xffff)
2399 resId = (UINT)(-((INT)resId));
2401 /* Load the resource into memory and get a pointer to it. */
2402 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2403 if (!hResource) return 0;
2404 hMemory = LoadResource(hModule, hResource);
2405 if (!hMemory) return 0;
2406 pString = LockResource(hMemory);
2408 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2409 idxString = resId & 0xf;
2410 while (idxString--) pString += *pString + 1;
2412 /* If no buffer is given, return length of the string. */
2413 if (!pwszBuffer) return *pString;
2415 /* Else copy over the string, respecting the buffer size. */
2416 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2417 if (cMaxChars >= 0) {
2418 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2419 pwszBuffer[cMaxChars] = '\0';
2422 return cMaxChars;
2425 /******************************************************************************
2426 * RegLoadMUIStringW [ADVAPI32.@]
2428 * Load the localized version of a string resource from some PE, respective
2429 * id and path of which are given in the registry value in the format
2430 * @[path]\dllname,-resourceId
2432 * PARAMS
2433 * hKey [I] Key, of which to load the string value from.
2434 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2435 * pszBuffer [O] Buffer to store the localized string in.
2436 * cbBuffer [I] Size of the destination buffer in bytes.
2437 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2438 * dwFlags [I] None supported yet.
2439 * pszBaseDir [I] Not supported yet.
2441 * RETURNS
2442 * Success: ERROR_SUCCESS,
2443 * Failure: nonzero error code from winerror.h
2445 * NOTES
2446 * This is an API of Windows Vista, which wasn't available at the time this code
2447 * was written. We have to check for the correct behaviour once it's available.
2449 LONG WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2450 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2452 DWORD dwValueType, cbData;
2453 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2454 LONG result;
2456 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %ld, pcbData = %p, "
2457 "dwFlags = %ld, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
2458 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2460 /* Parameter sanity checks. */
2461 if (!hKey || !pwszBuffer)
2462 return ERROR_INVALID_PARAMETER;
2464 if (pwszBaseDir && *pwszBaseDir) {
2465 FIXME("BaseDir parameter not yet supported!\n");
2466 return ERROR_INVALID_PARAMETER;
2469 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2470 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2471 if (result != ERROR_SUCCESS) goto cleanup;
2472 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2473 result = ERROR_FILE_NOT_FOUND;
2474 goto cleanup;
2476 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2477 if (!pwszTempBuffer) {
2478 result = ERROR_NOT_ENOUGH_MEMORY;
2479 goto cleanup;
2481 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2482 if (result != ERROR_SUCCESS) goto cleanup;
2484 /* Expand environment variables, if appropriate, or copy the original string over. */
2485 if (dwValueType == REG_EXPAND_SZ) {
2486 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2487 if (!cbData) goto cleanup;
2488 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2489 if (!pwszExpandedBuffer) {
2490 result = ERROR_NOT_ENOUGH_MEMORY;
2491 goto cleanup;
2493 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2494 } else {
2495 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2496 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2499 /* If the value references a resource based string, parse the value and load the string.
2500 * Else just copy over the original value. */
2501 result = ERROR_SUCCESS;
2502 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2503 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2504 } else {
2505 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2506 UINT uiStringId;
2507 HMODULE hModule;
2509 /* Format of the expanded value is 'path_to_dll,-resId' */
2510 if (!pComma || pComma[1] != '-') {
2511 result = ERROR_BADKEY;
2512 goto cleanup;
2515 uiStringId = atoiW(pComma+2);
2516 *pComma = '\0';
2518 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2519 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2520 result = ERROR_BADKEY;
2521 FreeLibrary(hModule);
2524 cleanup:
2525 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2526 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2527 return result;
2530 /******************************************************************************
2531 * RegLoadMUIStringA [ADVAPI32.@]
2533 * See RegLoadMUIStringW
2535 LONG WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2536 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2538 UNICODE_STRING valueW, baseDirW;
2539 WCHAR *pwszBuffer;
2540 DWORD cbData = cbBuffer * sizeof(WCHAR);
2541 LONG result;
2543 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2544 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2545 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2546 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2548 result = ERROR_NOT_ENOUGH_MEMORY;
2549 goto cleanup;
2552 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2553 baseDirW.Buffer);
2555 if (result == ERROR_SUCCESS) {
2556 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2557 if (pcbData)
2558 *pcbData = cbData;
2561 cleanup:
2562 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2563 RtlFreeUnicodeString(&baseDirW);
2564 RtlFreeUnicodeString(&valueW);
2566 return result;