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.
22 #include "wine/winbase16.h"
23 #include "wine/unicode.h"
24 #include "wine/winestring.h"
27 #include "debugtools.h"
29 DEFAULT_DEBUG_CHANNEL(reg);
32 /* Unicode->Ansi conversion without string delimiters */
33 static LPSTR memcpyWtoA( LPSTR dst, LPCWSTR src, INT n )
36 while (n-- > 0) *p++ = (CHAR)*src++;
40 /* check if value type needs string conversion (Ansi<->Unicode) */
41 static inline int is_string( DWORD type )
43 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
46 /* do a server call without setting the last error code */
47 static inline int reg_server_call( enum request req )
49 unsigned int res = server_call_noerr( req );
50 if (res) res = RtlNtStatusToDosError(res);
54 /******************************************************************************
55 * RegCreateKeyExW [ADVAPI32.131]
58 * hkey [I] Handle of an open key
59 * name [I] Address of subkey name
60 * reserved [I] Reserved - must be 0
61 * class [I] Address of class string
62 * options [I] Special options flag
63 * access [I] Desired security access
64 * sa [I] Address of key security structure
65 * retkey [O] Address of buffer for opened handle
66 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
69 * in case of failing retkey remains untouched
71 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
72 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
73 LPHKEY retkey, LPDWORD dispos )
75 OBJECT_ATTRIBUTES attr;
76 UNICODE_STRING nameW, classW;
78 if (reserved) return ERROR_INVALID_PARAMETER;
79 if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
81 attr.Length = sizeof(attr);
82 attr.RootDirectory = hkey;
83 attr.ObjectName = &nameW;
85 attr.SecurityDescriptor = NULL;
86 attr.SecurityQualityOfService = NULL;
87 RtlInitUnicodeString( &nameW, name );
88 RtlInitUnicodeString( &classW, class );
90 return RtlNtStatusToDosError( NtCreateKey( retkey, access, &attr, 0,
91 &classW, options, dispos ) );
95 /******************************************************************************
96 * RegCreateKeyExA [ADVAPI32.130]
98 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
99 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
100 LPHKEY retkey, LPDWORD dispos )
102 OBJECT_ATTRIBUTES attr;
103 UNICODE_STRING nameW, classW;
104 ANSI_STRING nameA, classA;
107 if (reserved) return ERROR_INVALID_PARAMETER;
108 if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
110 attr.Length = sizeof(attr);
111 attr.RootDirectory = hkey;
112 attr.ObjectName = &nameW;
114 attr.SecurityDescriptor = NULL;
115 attr.SecurityQualityOfService = NULL;
116 RtlInitAnsiString( &nameA, name );
117 RtlInitAnsiString( &classA, class );
119 /* FIXME: should use Unicode buffer in TEB */
120 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
122 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
124 status = NtCreateKey( retkey, access, &attr, 0, &classW, options, dispos );
125 RtlFreeUnicodeString( &classW );
127 RtlFreeUnicodeString( &nameW );
129 return RtlNtStatusToDosError( status );
133 /******************************************************************************
134 * RegCreateKeyW [ADVAPI32.132]
136 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
138 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
139 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
140 return RegCreateKeyExW( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
141 KEY_ALL_ACCESS, NULL, retkey, NULL );
145 /******************************************************************************
146 * RegCreateKeyA [ADVAPI32.129]
148 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
150 return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
151 KEY_ALL_ACCESS, NULL, retkey, NULL );
156 /******************************************************************************
157 * RegOpenKeyExW [ADVAPI32.150]
159 * Opens the specified key
161 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
164 * hkey [I] Handle of open key
165 * name [I] Name of subkey to open
166 * reserved [I] Reserved - must be zero
167 * access [I] Security access mask
168 * retkey [O] Handle to open key
171 * Success: ERROR_SUCCESS
172 * Failure: Error code
175 * in case of failing is retkey = 0
177 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
179 OBJECT_ATTRIBUTES attr;
180 UNICODE_STRING nameW;
182 attr.Length = sizeof(attr);
183 attr.RootDirectory = hkey;
184 attr.ObjectName = &nameW;
186 attr.SecurityDescriptor = NULL;
187 attr.SecurityQualityOfService = NULL;
188 RtlInitUnicodeString( &nameW, name );
189 return RtlNtStatusToDosError( NtOpenKey( retkey, access, &attr ) );
193 /******************************************************************************
194 * RegOpenKeyExA [ADVAPI32.149]
196 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
198 OBJECT_ATTRIBUTES attr;
199 UNICODE_STRING nameW;
203 attr.Length = sizeof(attr);
204 attr.RootDirectory = hkey;
205 attr.ObjectName = &nameW;
207 attr.SecurityDescriptor = NULL;
208 attr.SecurityQualityOfService = NULL;
210 RtlInitAnsiString( &nameA, name );
211 /* FIXME: should use Unicode buffer in TEB */
212 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
214 status = NtOpenKey( retkey, access, &attr );
215 RtlFreeUnicodeString( &nameW );
217 return RtlNtStatusToDosError( status );
221 /******************************************************************************
222 * RegOpenKeyW [ADVAPI32.151]
225 * hkey [I] Handle of open key
226 * name [I] Address of name of subkey to open
227 * retkey [O] Handle to open key
230 * Success: ERROR_SUCCESS
231 * Failure: Error code
234 * in case of failing is retkey = 0
236 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
238 return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
242 /******************************************************************************
243 * RegOpenKeyA [ADVAPI32.148]
245 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
247 return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
251 /******************************************************************************
252 * RegOpenCurrentUser [ADVAPI32]
253 * FIXME: This function is supposed to retrieve a handle to the
254 * HKEY_CURRENT_USER for the user the current thread is impersonating.
255 * Since Wine does not currently allow threads to impersonate other users,
256 * this stub should work fine.
258 DWORD WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
260 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
265 /******************************************************************************
266 * RegEnumKeyExW [ADVAPI32.139]
269 * hkey [I] Handle to key to enumerate
270 * index [I] Index of subkey to enumerate
271 * name [O] Buffer for subkey name
272 * name_len [O] Size of subkey buffer
273 * reserved [I] Reserved
274 * class [O] Buffer for class string
275 * class_len [O] Size of class buffer
276 * ft [O] Time key last written to
278 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
279 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
282 char buffer[256], *buf_ptr = buffer;
283 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
286 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
287 name_len ? *name_len : -1, reserved, class, class_len, ft );
289 if (reserved) return ERROR_INVALID_PARAMETER;
291 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
292 buffer, sizeof(buffer), &total_size );
294 while (status == STATUS_BUFFER_OVERFLOW)
296 /* retry with a dynamically allocated buffer */
297 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
298 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
299 return ERROR_NOT_ENOUGH_MEMORY;
300 info = (KEY_NODE_INFORMATION *)buf_ptr;
301 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
302 buf_ptr, total_size, &total_size );
307 DWORD len = info->NameLength / sizeof(WCHAR);
308 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
310 if (ft) *ft = info->LastWriteTime;
312 if (len >= *name_len || (class_len && (cls_len >= *class_len)))
313 status = STATUS_BUFFER_OVERFLOW;
317 memcpy( name, info->Name, info->NameLength );
321 *class_len = cls_len;
324 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
331 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
332 return RtlNtStatusToDosError( status );
336 /******************************************************************************
337 * RegEnumKeyExA [ADVAPI32.138]
339 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
340 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
343 char buffer[256], *buf_ptr = buffer;
344 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
347 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
348 name_len ? *name_len : -1, reserved, class, class_len, ft );
350 if (reserved) return ERROR_INVALID_PARAMETER;
352 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
353 buffer, sizeof(buffer), &total_size );
355 while (status == STATUS_BUFFER_OVERFLOW)
357 /* retry with a dynamically allocated buffer */
358 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
359 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
360 return ERROR_NOT_ENOUGH_MEMORY;
361 info = (KEY_NODE_INFORMATION *)buf_ptr;
362 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
363 buf_ptr, total_size, &total_size );
368 DWORD len = WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
369 NULL, 0, NULL, NULL );
370 DWORD cls_len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset),
371 info->ClassLength / sizeof(WCHAR),
372 NULL, 0, NULL, NULL );
374 if (ft) *ft = info->LastWriteTime;
376 if (len >= *name_len || (class_len && (cls_len >= *class_len)))
377 status = STATUS_BUFFER_OVERFLOW;
381 WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
382 name, len, NULL, NULL );
386 *class_len = cls_len;
389 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset),
390 info->ClassLength / sizeof(WCHAR),
391 class, cls_len, NULL, NULL );
398 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
399 return RtlNtStatusToDosError( status );
403 /******************************************************************************
404 * RegEnumKeyW [ADVAPI32.140]
406 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
408 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
412 /******************************************************************************
413 * RegEnumKeyA [ADVAPI32.137]
415 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
417 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
421 /******************************************************************************
422 * RegQueryInfoKeyW [ADVAPI32.153]
425 * hkey [I] Handle to key to query
426 * class [O] Buffer for class string
427 * class_len [O] Size of class string buffer
428 * reserved [I] Reserved
429 * subkeys [O] Buffer for number of subkeys
430 * max_subkey [O] Buffer for longest subkey name length
431 * max_class [O] Buffer for longest class string length
432 * values [O] Buffer for number of value entries
433 * max_value [O] Buffer for longest value name length
434 * max_data [O] Buffer for longest value data length
435 * security [O] Buffer for security descriptor length
436 * modif [O] Modification time
438 * - win95 allows class to be valid and class_len to be NULL
439 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
440 * - both allow class to be NULL and class_len to be NULL
441 * (it's hard to test validity, so test !NULL instead)
443 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
444 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
445 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
446 LPDWORD security, FILETIME *modif )
449 char buffer[256], *buf_ptr = buffer;
450 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
453 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
454 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
456 if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
457 return ERROR_INVALID_PARAMETER;
459 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
463 /* retry with a dynamically allocated buffer */
464 while (status == STATUS_BUFFER_OVERFLOW)
466 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
467 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
468 return ERROR_NOT_ENOUGH_MEMORY;
469 info = (KEY_FULL_INFORMATION *)buf_ptr;
470 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
475 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
477 status = STATUS_BUFFER_OVERFLOW;
481 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
482 class[info->ClassLength/sizeof(WCHAR)] = 0;
487 if (!status || status == STATUS_BUFFER_OVERFLOW)
489 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
490 if (subkeys) *subkeys = info->SubKeys;
491 if (max_subkey) *max_subkey = info->MaxNameLen;
492 if (max_class) *max_class = info->MaxClassLen;
493 if (values) *values = info->Values;
494 if (max_value) *max_value = info->MaxValueNameLen;
495 if (max_data) *max_data = info->MaxValueDataLen;
496 if (modif) *modif = info->LastWriteTime;
499 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
500 return RtlNtStatusToDosError( status );
504 /******************************************************************************
505 * RegQueryInfoKeyA [ADVAPI32.152]
507 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
508 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
509 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
510 LPDWORD security, FILETIME *modif )
513 char buffer[256], *buf_ptr = buffer;
514 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
517 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
518 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
520 if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
521 return ERROR_INVALID_PARAMETER;
523 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
525 if (class || class_len)
527 /* retry with a dynamically allocated buffer */
528 while (status == STATUS_BUFFER_OVERFLOW)
530 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
531 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
532 return ERROR_NOT_ENOUGH_MEMORY;
533 info = (KEY_FULL_INFORMATION *)buf_ptr;
534 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
539 DWORD len = WideCharToMultiByte( CP_ACP, 0,
540 (WCHAR *)(buf_ptr + info->ClassOffset),
541 info->ClassLength/sizeof(WCHAR),
542 NULL, 0, NULL, NULL );
545 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
548 if (class && !status)
550 WideCharToMultiByte( CP_ACP, 0,
551 (WCHAR *)(buf_ptr + info->ClassOffset),
552 info->ClassLength/sizeof(WCHAR),
553 class, len, NULL, NULL );
559 if (!status || status == STATUS_BUFFER_OVERFLOW)
561 if (subkeys) *subkeys = info->SubKeys;
562 if (max_subkey) *max_subkey = info->MaxNameLen;
563 if (max_class) *max_class = info->MaxClassLen;
564 if (values) *values = info->Values;
565 if (max_value) *max_value = info->MaxValueNameLen;
566 if (max_data) *max_data = info->MaxValueDataLen;
567 if (modif) *modif = info->LastWriteTime;
570 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
571 return RtlNtStatusToDosError( status );
575 /******************************************************************************
576 * RegCloseKey [ADVAPI32.126]
578 * Releases the handle of the specified key
581 * hkey [I] Handle of key to close
584 * Success: ERROR_SUCCESS
585 * Failure: Error code
587 DWORD WINAPI RegCloseKey( HKEY hkey )
589 if (!hkey || hkey >= 0x80000000) return ERROR_SUCCESS;
590 return RtlNtStatusToDosError( NtClose( hkey ) );
594 /******************************************************************************
595 * RegDeleteKeyW [ADVAPI32.134]
598 * hkey [I] Handle to open key
599 * name [I] Name of subkey to delete
602 * Success: ERROR_SUCCESS
603 * Failure: Error code
605 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
610 if (!name || !*name) return NtDeleteKey( hkey );
611 if (!(ret = RegOpenKeyExW( hkey, name, 0, 0, &tmp )))
613 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
620 /******************************************************************************
621 * RegDeleteKeyA [ADVAPI32.133]
623 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
628 if (!name || !*name) return NtDeleteKey( hkey );
629 if (!(ret = RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
631 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
639 /******************************************************************************
640 * RegSetValueExW [ADVAPI32.170]
642 * Sets the data and type of a value under a register key
645 * hkey [I] Handle of key to set value for
646 * name [I] Name of value to set
647 * reserved [I] Reserved - must be zero
648 * type [I] Flag for value type
649 * data [I] Address of value data
650 * count [I] Size of value data
653 * Success: ERROR_SUCCESS
654 * Failure: Error code
657 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
658 * NT does definitely care (aj)
660 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
661 DWORD type, CONST BYTE *data, DWORD count )
663 UNICODE_STRING nameW;
665 if (count && is_string(type))
667 LPCWSTR str = (LPCWSTR)data;
668 /* if user forgot to count terminating null, add it (yes NT does this) */
669 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
670 count += sizeof(WCHAR);
673 RtlInitUnicodeString( &nameW, name );
674 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
678 /******************************************************************************
679 * RegSetValueExA [ADVAPI32.169]
681 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
682 CONST BYTE *data, DWORD count )
684 UNICODE_STRING nameW;
689 if (count && is_string(type))
691 /* if user forgot to count terminating null, add it (yes NT does this) */
692 if (data[count-1] && !data[count]) count++;
695 if (is_string( type )) /* need to convert to Unicode */
697 DWORD lenW = MultiByteToWideChar( CP_ACP, 0, data, count, NULL, 0 );
698 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW*sizeof(WCHAR) )))
699 return ERROR_OUTOFMEMORY;
700 MultiByteToWideChar( CP_ACP, 0, data, count, dataW, lenW );
701 count = lenW * sizeof(WCHAR);
702 data = (BYTE *)dataW;
705 RtlInitAnsiString( &nameA, name );
706 /* FIXME: should use Unicode buffer in TEB */
707 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
709 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
710 RtlFreeUnicodeString( &nameW );
712 if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
713 return RtlNtStatusToDosError( status );
717 /******************************************************************************
718 * RegSetValueW [ADVAPI32.171]
720 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
725 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
727 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
729 if (name && name[0]) /* need to create the subkey */
731 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
734 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (LPBYTE)data,
735 (strlenW( data ) + 1) * sizeof(WCHAR) );
736 if (subkey != hkey) RegCloseKey( subkey );
741 /******************************************************************************
742 * RegSetValueA [ADVAPI32.168]
744 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
749 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
751 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
753 if (name && name[0]) /* need to create the subkey */
755 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
757 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
758 if (subkey != hkey) RegCloseKey( subkey );
764 /******************************************************************************
765 * RegQueryValueExW [ADVAPI32.158]
767 * Retrieves type and data for a specified name associated with an open key
770 * hkey [I] Handle of key to query
771 * name [I] Name of value to query
772 * reserved [I] Reserved - must be NULL
773 * type [O] Address of buffer for value type. If NULL, the type
775 * data [O] Address of data buffer. If NULL, the actual data is
777 * count [I/O] Address of data buffer size
780 * ERROR_SUCCESS: Success
781 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
782 * buffer is left untouched. The MS-documentation is wrong (js) !!!
784 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
785 LPBYTE data, LPDWORD count )
788 UNICODE_STRING name_str;
790 char buffer[256], *buf_ptr = buffer;
791 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
792 static const int info_size = sizeof(*info) - sizeof(info->Data);
794 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
795 hkey, debugstr_w(name), reserved, type, data, count, count ? *count : 0 );
797 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
799 RtlInitUnicodeString( &name_str, name );
801 if (data) total_size = min( sizeof(buffer), *count + info_size );
802 else total_size = info_size;
804 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
805 buffer, total_size, &total_size );
806 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
810 /* retry with a dynamically allocated buffer */
811 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
813 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
814 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
815 return ERROR_NOT_ENOUGH_MEMORY;
816 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
817 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
818 buf_ptr, total_size, &total_size );
823 memcpy( data, buf_ptr + info_size, total_size - info_size );
824 /* if the type is REG_SZ and data is not 0-terminated
825 * and there is enough space in the buffer NT appends a \0 */
826 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
828 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
829 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
832 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
835 if (type) *type = info->Type;
836 if (count) *count = total_size - info_size;
839 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
840 return RtlNtStatusToDosError(status);
844 /******************************************************************************
845 * RegQueryValueExA [ADVAPI32.157]
848 * the documentation is wrong: if the buffer is too small it remains untouched
850 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
851 LPBYTE data, LPDWORD count )
855 UNICODE_STRING nameW;
857 char buffer[256], *buf_ptr = buffer;
858 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
859 static const int info_size = sizeof(*info) - sizeof(info->Data);
861 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
862 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
864 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
866 RtlInitAnsiString( &nameA, name );
867 /* FIXME: should use Unicode buffer in TEB */
868 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
869 return RtlNtStatusToDosError(status);
871 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
872 buffer, sizeof(buffer), &total_size );
873 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
875 /* we need to fetch the contents for a string type even if not requested,
876 * because we need to compute the length of the ASCII string. */
877 if (data || is_string(info->Type))
879 /* retry with a dynamically allocated buffer */
880 while (status == STATUS_BUFFER_OVERFLOW)
882 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
883 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
885 status = STATUS_NO_MEMORY;
888 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
889 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
890 buf_ptr, total_size, &total_size );
895 if (is_string(info->Type))
897 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
898 (total_size - info_size) /sizeof(WCHAR),
899 NULL, 0, NULL, NULL );
902 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
905 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
906 (total_size - info_size) /sizeof(WCHAR),
907 data, len, NULL, NULL );
908 /* if the type is REG_SZ and data is not 0-terminated
909 * and there is enough space in the buffer NT appends a \0 */
910 if (len < *count && data[len-1]) data[len] = 0;
913 total_size = len + info_size;
917 if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
918 else memcpy( data, buf_ptr + info_size, total_size - info_size );
921 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
924 if (type) *type = info->Type;
925 if (count) *count = total_size - info_size;
928 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
929 RtlFreeUnicodeString( &nameW );
930 return RtlNtStatusToDosError(status);
934 /******************************************************************************
935 * RegQueryValueW [ADVAPI32.159]
937 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
942 TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
946 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
948 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
949 if (subkey != hkey) RegCloseKey( subkey );
950 if (ret == ERROR_FILE_NOT_FOUND)
952 /* return empty string if default value not found */
954 if (count) *count = 1;
961 /******************************************************************************
962 * RegQueryValueA [ADVAPI32.156]
964 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
969 TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
973 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
975 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
976 if (subkey != hkey) RegCloseKey( subkey );
977 if (ret == ERROR_FILE_NOT_FOUND)
979 /* return empty string if default value not found */
981 if (count) *count = 1;
988 /******************************************************************************
989 * RegEnumValueW [ADVAPI32.142]
992 * hkey [I] Handle to key to query
993 * index [I] Index of value to query
994 * value [O] Value string
995 * val_count [I/O] Size of value buffer (in wchars)
996 * reserved [I] Reserved
998 * data [O] Value data
999 * count [I/O] Size of data buffer (in bytes)
1002 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1003 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1006 struct enum_key_value_request *req = get_req_buffer();
1008 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1009 hkey, index, value, val_count, reserved, type, data, count );
1011 /* NT only checks count, not val_count */
1012 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1017 if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
1019 len = strlenW( req->name ) + 1;
1020 if (len > *val_count) return ERROR_MORE_DATA;
1021 memcpy( value, req->name, len * sizeof(WCHAR) );
1022 *val_count = len - 1;
1026 if (*count < req->len) ret = ERROR_MORE_DATA;
1030 unsigned int max = server_remaining( req->data );
1031 unsigned int pos = 0;
1032 while (pos < req->len)
1034 unsigned int len = min( req->len - pos, max );
1035 memcpy( data + pos, req->data, len );
1036 if ((pos += len) >= req->len) break;
1038 if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
1041 /* if the type is REG_SZ and data is not 0-terminated
1042 * and there is enough space in the buffer NT appends a \0 */
1043 if (req->len && is_string(req->type) &&
1044 (req->len < *count) && ((WCHAR *)data)[req->len-1]) ((WCHAR *)data)[req->len] = 0;
1046 if (type) *type = req->type;
1047 if (count) *count = req->len;
1052 /******************************************************************************
1053 * RegEnumValueA [ADVAPI32.141]
1055 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1056 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1058 DWORD ret, len, total_len;
1059 struct enum_key_value_request *req = get_req_buffer();
1061 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1062 hkey, index, value, val_count, reserved, type, data, count );
1064 /* NT only checks count, not val_count */
1065 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1070 if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
1072 len = strlenW( req->name ) + 1;
1073 if (len > *val_count) return ERROR_MORE_DATA;
1074 memcpyWtoA( value, req->name, len );
1075 *val_count = len - 1;
1077 total_len = is_string( req->type ) ? req->len/sizeof(WCHAR) : req->len;
1081 if (*count < total_len) ret = ERROR_MORE_DATA;
1085 unsigned int max = server_remaining( req->data );
1086 unsigned int pos = 0;
1087 while (pos < req->len)
1089 unsigned int len = min( req->len - pos, max );
1090 if (is_string( req->type ))
1091 memcpyWtoA( data + pos/sizeof(WCHAR), (WCHAR *)req->data, len/sizeof(WCHAR) );
1093 memcpy( data + pos, req->data, len );
1094 if ((pos += len) >= req->len) break;
1096 if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
1099 /* if the type is REG_SZ and data is not 0-terminated
1100 * and there is enough space in the buffer NT appends a \0 */
1101 if (total_len && is_string(req->type) && (total_len < *count) && data[total_len-1])
1102 data[total_len] = 0;
1105 if (count) *count = total_len;
1106 if (type) *type = req->type;
1112 /******************************************************************************
1113 * RegDeleteValueW [ADVAPI32.136]
1116 * hkey [I] handle to key
1117 * name [I] name of value to delete
1122 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1124 UNICODE_STRING nameW;
1125 RtlInitUnicodeString( &nameW, name );
1126 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1130 /******************************************************************************
1131 * RegDeleteValueA [ADVAPI32.135]
1133 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1135 UNICODE_STRING nameW;
1139 RtlInitAnsiString( &nameA, name );
1140 /* FIXME: should use Unicode buffer in TEB */
1141 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1143 status = NtDeleteValueKey( hkey, &nameW );
1144 RtlFreeUnicodeString( &nameW );
1146 return RtlNtStatusToDosError( status );
1150 /******************************************************************************
1151 * RegLoadKeyW [ADVAPI32.185]
1154 * hkey [I] Handle of open key
1155 * subkey [I] Address of name of subkey
1156 * filename [I] Address of filename for registry information
1158 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1161 DWORD ret, len, err = GetLastError();
1163 TRACE( "(%x,%s,%s)\n", hkey, debugstr_w(subkey), debugstr_w(filename) );
1165 if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1166 if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1168 len = strlenW( subkey ) * sizeof(WCHAR);
1169 if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
1171 if ((file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1172 FILE_ATTRIBUTE_NORMAL, -1 )) == INVALID_HANDLE_VALUE)
1174 ret = GetLastError();
1180 struct load_registry_request *req = server_alloc_req( sizeof(*req), len );
1183 memcpy( server_data_ptr(req), subkey, len );
1184 ret = reg_server_call( REQ_LOAD_REGISTRY );
1187 CloseHandle( file );
1190 SetLastError( err ); /* restore the last error code */
1195 /******************************************************************************
1196 * RegLoadKeyA [ADVAPI32.184]
1198 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1201 DWORD ret, len, err = GetLastError();
1203 TRACE( "(%x,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
1205 if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1206 if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1208 len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), NULL, 0 ) * sizeof(WCHAR);
1209 if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
1211 if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1212 FILE_ATTRIBUTE_NORMAL, -1 )) == INVALID_HANDLE_VALUE)
1214 ret = GetLastError();
1220 struct load_registry_request *req = server_alloc_req( sizeof(*req), len );
1223 MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey),
1224 server_data_ptr(req), len/sizeof(WCHAR) );
1225 ret = reg_server_call( REQ_LOAD_REGISTRY );
1228 CloseHandle( file );
1231 SetLastError( err ); /* restore the last error code */
1236 /******************************************************************************
1237 * RegSaveKeyA [ADVAPI32.165]
1240 * hkey [I] Handle of key where save begins
1241 * lpFile [I] Address of filename to save to
1242 * sa [I] Address of security structure
1244 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
1252 TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa );
1254 if (!file || !*file) return ERROR_INVALID_PARAMETER;
1256 err = GetLastError();
1257 GetFullPathNameA( file, sizeof(buffer), buffer, &name );
1260 sprintf( name, "reg%04x.tmp", count++ );
1261 handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
1262 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1 );
1263 if (handle != INVALID_HANDLE_VALUE) break;
1264 if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
1266 /* Something gone haywire ? Please report if this happens abnormally */
1268 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", buffer, count);
1273 struct save_registry_request *req = server_alloc_req( sizeof(*req), 0 );
1276 ret = reg_server_call( REQ_SAVE_REGISTRY );
1280 CloseHandle( handle );
1283 if (!MoveFileExA( buffer, file, MOVEFILE_REPLACE_EXISTING ))
1285 ERR( "Failed to move %s to %s\n", buffer, file );
1286 ret = GetLastError();
1289 if (ret) DeleteFileA( buffer );
1292 SetLastError( err ); /* restore last error code */
1297 /******************************************************************************
1298 * RegSaveKeyW [ADVAPI32.166]
1300 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1302 LPSTR fileA = HEAP_strdupWtoA( GetProcessHeap(), 0, file );
1303 DWORD ret = RegSaveKeyA( hkey, fileA, sa );
1304 if (fileA) HeapFree( GetProcessHeap(), 0, fileA );