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 /* copy a key name into the request buffer */
47 static inline DWORD
copy_nameW( LPWSTR dest
, LPCWSTR name
)
51 if (strlenW(name
) > MAX_PATH
) return ERROR_MORE_DATA
;
52 strcpyW( dest
, name
);
58 /* copy a key name into the request buffer */
59 static inline DWORD
copy_nameAtoW( LPWSTR dest
, LPCSTR name
)
63 if (strlen(name
) > MAX_PATH
) return ERROR_MORE_DATA
;
64 lstrcpyAtoW( dest
, name
);
70 /* do a server call without setting the last error code */
71 static inline int reg_server_call( enum request req
)
73 unsigned int res
= server_call_noerr( req
);
74 if (res
) res
= RtlNtStatusToDosError(res
);
78 /******************************************************************************
79 * RegCreateKeyExW [ADVAPI32.131]
82 * hkey [I] Handle of an open key
83 * name [I] Address of subkey name
84 * reserved [I] Reserved - must be 0
85 * class [I] Address of class string
86 * options [I] Special options flag
87 * access [I] Desired security access
88 * sa [I] Address of key security structure
89 * retkey [O] Address of buffer for opened handle
90 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
93 * in case of failing retkey remains untouched
95 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
96 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
97 LPHKEY retkey
, LPDWORD dispos
)
99 OBJECT_ATTRIBUTES attr
;
100 UNICODE_STRING nameW
, classW
;
102 if (reserved
) return ERROR_INVALID_PARAMETER
;
103 if (!(access
& KEY_ALL_ACCESS
) || (access
& ~KEY_ALL_ACCESS
)) return ERROR_ACCESS_DENIED
;
105 attr
.Length
= sizeof(attr
);
106 attr
.RootDirectory
= hkey
;
107 attr
.ObjectName
= &nameW
;
109 attr
.SecurityDescriptor
= NULL
;
110 attr
.SecurityQualityOfService
= NULL
;
111 RtlInitUnicodeString( &nameW
, name
);
112 RtlInitUnicodeString( &classW
, class );
114 return RtlNtStatusToDosError( NtCreateKey( retkey
, access
, &attr
, 0,
115 &classW
, options
, dispos
) );
119 /******************************************************************************
120 * RegCreateKeyExA [ADVAPI32.130]
122 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
123 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
124 LPHKEY retkey
, LPDWORD dispos
)
126 OBJECT_ATTRIBUTES attr
;
127 UNICODE_STRING nameW
, classW
;
128 ANSI_STRING nameA
, classA
;
131 if (reserved
) return ERROR_INVALID_PARAMETER
;
132 if (!(access
& KEY_ALL_ACCESS
) || (access
& ~KEY_ALL_ACCESS
)) return ERROR_ACCESS_DENIED
;
134 attr
.Length
= sizeof(attr
);
135 attr
.RootDirectory
= hkey
;
136 attr
.ObjectName
= &nameW
;
138 attr
.SecurityDescriptor
= NULL
;
139 attr
.SecurityQualityOfService
= NULL
;
140 RtlInitAnsiString( &nameA
, name
);
141 RtlInitAnsiString( &classA
, class );
143 /* FIXME: should use Unicode buffer in TEB */
144 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
146 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
148 status
= NtCreateKey( retkey
, access
, &attr
, 0, &classW
, options
, dispos
);
149 RtlFreeUnicodeString( &classW
);
151 RtlFreeUnicodeString( &nameW
);
153 return RtlNtStatusToDosError( status
);
157 /******************************************************************************
158 * RegCreateKeyW [ADVAPI32.132]
160 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR name
, LPHKEY retkey
)
162 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
163 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
164 return RegCreateKeyExW( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
165 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
169 /******************************************************************************
170 * RegCreateKeyA [ADVAPI32.129]
172 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
174 return RegCreateKeyExA( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
175 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
180 /******************************************************************************
181 * RegOpenKeyExW [ADVAPI32.150]
183 * Opens the specified key
185 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
188 * hkey [I] Handle of open key
189 * name [I] Name of subkey to open
190 * reserved [I] Reserved - must be zero
191 * access [I] Security access mask
192 * retkey [O] Handle to open key
195 * Success: ERROR_SUCCESS
196 * Failure: Error code
199 * in case of failing is retkey = 0
201 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, REGSAM access
, LPHKEY retkey
)
203 OBJECT_ATTRIBUTES attr
;
204 UNICODE_STRING nameW
;
206 attr
.Length
= sizeof(attr
);
207 attr
.RootDirectory
= hkey
;
208 attr
.ObjectName
= &nameW
;
210 attr
.SecurityDescriptor
= NULL
;
211 attr
.SecurityQualityOfService
= NULL
;
212 RtlInitUnicodeString( &nameW
, name
);
213 return RtlNtStatusToDosError( NtOpenKey( retkey
, access
, &attr
) );
217 /******************************************************************************
218 * RegOpenKeyExA [ADVAPI32.149]
220 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, REGSAM access
, LPHKEY retkey
)
222 OBJECT_ATTRIBUTES attr
;
223 UNICODE_STRING nameW
;
227 attr
.Length
= sizeof(attr
);
228 attr
.RootDirectory
= hkey
;
229 attr
.ObjectName
= &nameW
;
231 attr
.SecurityDescriptor
= NULL
;
232 attr
.SecurityQualityOfService
= NULL
;
234 RtlInitAnsiString( &nameA
, name
);
235 /* FIXME: should use Unicode buffer in TEB */
236 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
238 status
= NtOpenKey( retkey
, access
, &attr
);
239 RtlFreeUnicodeString( &nameW
);
241 return RtlNtStatusToDosError( status
);
245 /******************************************************************************
246 * RegOpenKeyW [ADVAPI32.151]
249 * hkey [I] Handle of open key
250 * name [I] Address of name of subkey to open
251 * retkey [O] Handle to open key
254 * Success: ERROR_SUCCESS
255 * Failure: Error code
258 * in case of failing is retkey = 0
260 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, LPHKEY retkey
)
262 return RegOpenKeyExW( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
266 /******************************************************************************
267 * RegOpenKeyA [ADVAPI32.148]
269 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
271 return RegOpenKeyExA( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
276 /******************************************************************************
277 * RegEnumKeyExW [ADVAPI32.139]
280 * hkey [I] Handle to key to enumerate
281 * index [I] Index of subkey to enumerate
282 * name [O] Buffer for subkey name
283 * name_len [O] Size of subkey buffer
284 * reserved [I] Reserved
285 * class [O] Buffer for class string
286 * class_len [O] Size of class buffer
287 * ft [O] Time key last written to
289 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
290 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
293 char buffer
[256], *buf_ptr
= buffer
;
294 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
297 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
298 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
300 if (reserved
) return ERROR_INVALID_PARAMETER
;
302 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
303 buffer
, sizeof(buffer
), &total_size
);
305 while (status
== STATUS_BUFFER_OVERFLOW
)
307 /* retry with a dynamically allocated buffer */
308 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
309 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
310 return ERROR_NOT_ENOUGH_MEMORY
;
311 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
312 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
313 buf_ptr
, total_size
, &total_size
);
318 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
319 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
321 if (ft
) *ft
= info
->LastWriteTime
;
323 if (len
>= *name_len
|| (class_len
&& (cls_len
>= *class_len
)))
324 status
= STATUS_BUFFER_OVERFLOW
;
328 memcpy( name
, info
->Name
, info
->NameLength
);
332 *class_len
= cls_len
;
335 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
342 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
343 return RtlNtStatusToDosError( status
);
347 /******************************************************************************
348 * RegEnumKeyExA [ADVAPI32.138]
350 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
351 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
354 char buffer
[256], *buf_ptr
= buffer
;
355 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
358 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
359 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
361 if (reserved
) return ERROR_INVALID_PARAMETER
;
363 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
364 buffer
, sizeof(buffer
), &total_size
);
366 while (status
== STATUS_BUFFER_OVERFLOW
)
368 /* retry with a dynamically allocated buffer */
369 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
370 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
371 return ERROR_NOT_ENOUGH_MEMORY
;
372 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
373 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
374 buf_ptr
, total_size
, &total_size
);
379 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, info
->Name
, info
->NameLength
/sizeof(WCHAR
),
380 NULL
, 0, NULL
, NULL
);
381 DWORD cls_len
= WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
382 info
->ClassLength
/ sizeof(WCHAR
),
383 NULL
, 0, NULL
, NULL
);
385 if (ft
) *ft
= info
->LastWriteTime
;
387 if (len
>= *name_len
|| (class_len
&& (cls_len
>= *class_len
)))
388 status
= STATUS_BUFFER_OVERFLOW
;
392 WideCharToMultiByte( CP_ACP
, 0, info
->Name
, info
->NameLength
/sizeof(WCHAR
),
393 name
, len
, NULL
, NULL
);
397 *class_len
= cls_len
;
400 WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
401 info
->ClassLength
/ sizeof(WCHAR
),
402 class, cls_len
, NULL
, NULL
);
409 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
410 return RtlNtStatusToDosError( status
);
414 /******************************************************************************
415 * RegEnumKeyW [ADVAPI32.140]
417 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
419 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
423 /******************************************************************************
424 * RegEnumKeyA [ADVAPI32.137]
426 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
428 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
432 /******************************************************************************
433 * RegQueryInfoKeyW [ADVAPI32.153]
436 * hkey [I] Handle to key to query
437 * class [O] Buffer for class string
438 * class_len [O] Size of class string buffer
439 * reserved [I] Reserved
440 * subkeys [O] Buffer for number of subkeys
441 * max_subkey [O] Buffer for longest subkey name length
442 * max_class [O] Buffer for longest class string length
443 * values [O] Buffer for number of value entries
444 * max_value [O] Buffer for longest value name length
445 * max_data [O] Buffer for longest value data length
446 * security [O] Buffer for security descriptor length
447 * modif [O] Modification time
449 * - win95 allows class to be valid and class_len to be NULL
450 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
451 * - both allow class to be NULL and class_len to be NULL
452 * (it's hard to test validity, so test !NULL instead)
454 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
455 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
456 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
457 LPDWORD security
, FILETIME
*modif
)
460 char buffer
[256], *buf_ptr
= buffer
;
461 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
464 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
465 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
467 if (class && !class_len
&& !(GetVersion() & 0x80000000 /*NT*/))
468 return ERROR_INVALID_PARAMETER
;
470 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
474 /* retry with a dynamically allocated buffer */
475 while (status
== STATUS_BUFFER_OVERFLOW
)
477 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
478 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
479 return ERROR_NOT_ENOUGH_MEMORY
;
480 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
481 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
486 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
488 status
= STATUS_BUFFER_OVERFLOW
;
492 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
493 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
498 if (!status
|| status
== STATUS_BUFFER_OVERFLOW
)
500 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
501 if (subkeys
) *subkeys
= info
->SubKeys
;
502 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
503 if (max_class
) *max_class
= info
->MaxClassLen
;
504 if (values
) *values
= info
->Values
;
505 if (max_value
) *max_value
= info
->MaxValueNameLen
;
506 if (max_data
) *max_data
= info
->MaxValueDataLen
;
507 if (modif
) *modif
= info
->LastWriteTime
;
510 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
511 return RtlNtStatusToDosError( status
);
515 /******************************************************************************
516 * RegQueryInfoKeyA [ADVAPI32.152]
518 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
519 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
520 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
521 LPDWORD security
, FILETIME
*modif
)
524 char buffer
[256], *buf_ptr
= buffer
;
525 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
528 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
529 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
531 if (class && !class_len
&& !(GetVersion() & 0x80000000 /*NT*/))
532 return ERROR_INVALID_PARAMETER
;
534 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
536 if (class || class_len
)
538 /* retry with a dynamically allocated buffer */
539 while (status
== STATUS_BUFFER_OVERFLOW
)
541 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
542 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
543 return ERROR_NOT_ENOUGH_MEMORY
;
544 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
545 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
550 DWORD len
= WideCharToMultiByte( CP_ACP
, 0,
551 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
552 info
->ClassLength
/sizeof(WCHAR
),
553 NULL
, 0, NULL
, NULL
);
556 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
559 if (class && !status
)
561 WideCharToMultiByte( CP_ACP
, 0,
562 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
563 info
->ClassLength
/sizeof(WCHAR
),
564 class, len
, NULL
, NULL
);
570 if (!status
|| status
== STATUS_BUFFER_OVERFLOW
)
572 if (subkeys
) *subkeys
= info
->SubKeys
;
573 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
574 if (max_class
) *max_class
= info
->MaxClassLen
;
575 if (values
) *values
= info
->Values
;
576 if (max_value
) *max_value
= info
->MaxValueNameLen
;
577 if (max_data
) *max_data
= info
->MaxValueDataLen
;
578 if (modif
) *modif
= info
->LastWriteTime
;
581 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
582 return RtlNtStatusToDosError( status
);
586 /******************************************************************************
587 * RegCloseKey [ADVAPI32.126]
589 * Releases the handle of the specified key
592 * hkey [I] Handle of key to close
595 * Success: ERROR_SUCCESS
596 * Failure: Error code
598 DWORD WINAPI
RegCloseKey( HKEY hkey
)
600 if (!hkey
|| hkey
>= 0x80000000) return ERROR_SUCCESS
;
601 return RtlNtStatusToDosError( NtClose( hkey
) );
605 /******************************************************************************
606 * RegDeleteKeyW [ADVAPI32.134]
609 * hkey [I] Handle to open key
610 * name [I] Name of subkey to delete
613 * Success: ERROR_SUCCESS
614 * Failure: Error code
616 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
621 if (!name
|| !*name
) return NtDeleteKey( hkey
);
622 if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, 0, &tmp
)))
624 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
631 /******************************************************************************
632 * RegDeleteKeyA [ADVAPI32.133]
634 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
639 if (!name
|| !*name
) return NtDeleteKey( hkey
);
640 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, 0, &tmp
)))
642 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
650 /******************************************************************************
651 * RegSetValueExW [ADVAPI32.170]
653 * Sets the data and type of a value under a register key
656 * hkey [I] Handle of key to set value for
657 * name [I] Name of value to set
658 * reserved [I] Reserved - must be zero
659 * type [I] Flag for value type
660 * data [I] Address of value data
661 * count [I] Size of value data
664 * Success: ERROR_SUCCESS
665 * Failure: Error code
668 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
669 * NT does definitely care (aj)
671 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
672 DWORD type
, CONST BYTE
*data
, DWORD count
)
674 UNICODE_STRING nameW
;
676 if (count
&& is_string(type
))
678 LPCWSTR str
= (LPCWSTR
)data
;
679 /* if user forgot to count terminating null, add it (yes NT does this) */
680 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
681 count
+= sizeof(WCHAR
);
684 RtlInitUnicodeString( &nameW
, name
);
685 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
689 /******************************************************************************
690 * RegSetValueExA [ADVAPI32.169]
692 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
693 CONST BYTE
*data
, DWORD count
)
695 UNICODE_STRING nameW
;
700 if (count
&& is_string(type
))
702 /* if user forgot to count terminating null, add it (yes NT does this) */
703 if (data
[count
-1] && !data
[count
]) count
++;
706 if (is_string( type
)) /* need to convert to Unicode */
708 DWORD lenW
= MultiByteToWideChar( CP_ACP
, 0, data
, count
, NULL
, 0 );
709 if (!(dataW
= HeapAlloc( GetProcessHeap(), 0, lenW
*sizeof(WCHAR
) )))
710 return ERROR_OUTOFMEMORY
;
711 MultiByteToWideChar( CP_ACP
, 0, data
, count
, dataW
, lenW
);
712 count
= lenW
* sizeof(WCHAR
);
713 data
= (BYTE
*)dataW
;
716 RtlInitAnsiString( &nameA
, name
);
717 /* FIXME: should use Unicode buffer in TEB */
718 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
720 status
= NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
);
721 RtlFreeUnicodeString( &nameW
);
723 if (dataW
) HeapFree( GetProcessHeap(), 0, dataW
);
724 return RtlNtStatusToDosError( status
);
728 /******************************************************************************
729 * RegSetValueW [ADVAPI32.171]
731 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR name
, DWORD type
, LPCWSTR data
, DWORD count
)
736 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey
, debugstr_w(name
), type
, debugstr_w(data
), count
);
738 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
740 if (name
&& name
[0]) /* need to create the subkey */
742 if ((ret
= RegCreateKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
745 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
,
746 (strlenW( data
) + 1) * sizeof(WCHAR
) );
747 if (subkey
!= hkey
) RegCloseKey( subkey
);
752 /******************************************************************************
753 * RegSetValueA [ADVAPI32.168]
755 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
760 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey
, debugstr_a(name
), type
, debugstr_a(data
), count
);
762 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
764 if (name
&& name
[0]) /* need to create the subkey */
766 if ((ret
= RegCreateKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
768 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
, strlen(data
)+1 );
769 if (subkey
!= hkey
) RegCloseKey( subkey
);
775 /******************************************************************************
776 * RegQueryValueExW [ADVAPI32.158]
778 * Retrieves type and data for a specified name associated with an open key
781 * hkey [I] Handle of key to query
782 * name [I] Name of value to query
783 * reserved [I] Reserved - must be NULL
784 * type [O] Address of buffer for value type. If NULL, the type
786 * data [O] Address of data buffer. If NULL, the actual data is
788 * count [I/O] Address of data buffer size
791 * ERROR_SUCCESS: Success
792 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
793 * buffer is left untouched. The MS-documentation is wrong (js) !!!
795 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
796 LPBYTE data
, LPDWORD count
)
799 UNICODE_STRING name_str
;
801 char buffer
[256], *buf_ptr
= buffer
;
802 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
803 static const int info_size
= sizeof(*info
) - sizeof(info
->Data
);
805 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
806 hkey
, debugstr_w(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
808 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
810 RtlInitUnicodeString( &name_str
, name
);
812 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
813 else total_size
= info_size
;
815 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
816 buffer
, total_size
, &total_size
);
817 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
821 /* retry with a dynamically allocated buffer */
822 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
824 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
825 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
826 return ERROR_NOT_ENOUGH_MEMORY
;
827 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
828 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
829 buf_ptr
, total_size
, &total_size
);
834 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
835 /* if the type is REG_SZ and data is not 0-terminated
836 * and there is enough space in the buffer NT appends a \0 */
837 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
839 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
840 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
843 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
846 if (type
) *type
= info
->Type
;
847 if (count
) *count
= total_size
- info_size
;
850 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
851 return RtlNtStatusToDosError(status
);
855 /******************************************************************************
856 * RegQueryValueExA [ADVAPI32.157]
859 * the documentation is wrong: if the buffer is to small it remains untouched
861 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
862 LPBYTE data
, LPDWORD count
)
866 UNICODE_STRING nameW
;
868 char buffer
[256], *buf_ptr
= buffer
;
869 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
870 static const int info_size
= sizeof(*info
) - sizeof(info
->Data
);
872 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
873 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
875 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
877 RtlInitAnsiString( &nameA
, name
);
878 /* FIXME: should use Unicode buffer in TEB */
879 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
880 return RtlNtStatusToDosError(status
);
882 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
883 buffer
, sizeof(buffer
), &total_size
);
884 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
886 /* we need to fetch the contents for a string type even if not requested,
887 * because we need to compute the length of the ASCII string. */
888 if (data
|| is_string(info
->Type
))
890 /* retry with a dynamically allocated buffer */
891 while (status
== STATUS_BUFFER_OVERFLOW
)
893 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
894 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
896 status
= STATUS_NO_MEMORY
;
899 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
900 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
901 buf_ptr
, total_size
, &total_size
);
906 if (is_string(info
->Type
))
908 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info_size
),
909 (total_size
- info_size
) /sizeof(WCHAR
),
910 NULL
, 0, NULL
, NULL
);
913 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
916 WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info_size
),
917 (total_size
- info_size
) /sizeof(WCHAR
),
918 data
, len
, NULL
, NULL
);
919 /* if the type is REG_SZ and data is not 0-terminated
920 * and there is enough space in the buffer NT appends a \0 */
921 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
924 total_size
= len
+ info_size
;
928 if (total_size
- info_size
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
929 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
932 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
935 if (type
) *type
= info
->Type
;
936 if (count
) *count
= total_size
- info_size
;
939 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
940 RtlFreeUnicodeString( &nameW
);
941 return RtlNtStatusToDosError(status
);
945 /******************************************************************************
946 * RegQueryValueW [ADVAPI32.159]
948 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
953 TRACE("(%x,%s,%p,%ld)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
957 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
959 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
960 if (subkey
!= hkey
) RegCloseKey( subkey
);
961 if (ret
== ERROR_FILE_NOT_FOUND
)
963 /* return empty string if default value not found */
965 if (count
) *count
= 1;
972 /******************************************************************************
973 * RegQueryValueA [ADVAPI32.156]
975 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
980 TRACE("(%x,%s,%p,%ld)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
984 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
986 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
987 if (subkey
!= hkey
) RegCloseKey( subkey
);
988 if (ret
== ERROR_FILE_NOT_FOUND
)
990 /* return empty string if default value not found */
992 if (count
) *count
= 1;
999 /******************************************************************************
1000 * RegEnumValueW [ADVAPI32.142]
1003 * hkey [I] Handle to key to query
1004 * index [I] Index of value to query
1005 * value [O] Value string
1006 * val_count [I/O] Size of value buffer (in wchars)
1007 * reserved [I] Reserved
1008 * type [O] Type code
1009 * data [O] Value data
1010 * count [I/O] Size of data buffer (in bytes)
1013 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
1014 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1017 struct enum_key_value_request
*req
= get_req_buffer();
1019 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1020 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1022 /* NT only checks count, not val_count */
1023 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1028 if ((ret
= reg_server_call( REQ_ENUM_KEY_VALUE
)) != ERROR_SUCCESS
) return ret
;
1030 len
= strlenW( req
->name
) + 1;
1031 if (len
> *val_count
) return ERROR_MORE_DATA
;
1032 memcpy( value
, req
->name
, len
* sizeof(WCHAR
) );
1033 *val_count
= len
- 1;
1037 if (*count
< req
->len
) ret
= ERROR_MORE_DATA
;
1041 unsigned int max
= server_remaining( req
->data
);
1042 unsigned int pos
= 0;
1043 while (pos
< req
->len
)
1045 unsigned int len
= min( req
->len
- pos
, max
);
1046 memcpy( data
+ pos
, req
->data
, len
);
1047 if ((pos
+= len
) >= req
->len
) break;
1049 if ((ret
= reg_server_call( REQ_ENUM_KEY_VALUE
)) != ERROR_SUCCESS
) return ret
;
1052 /* if the type is REG_SZ and data is not 0-terminated
1053 * and there is enough space in the buffer NT appends a \0 */
1054 if (req
->len
&& is_string(req
->type
) &&
1055 (req
->len
< *count
) && ((WCHAR
*)data
)[req
->len
-1]) ((WCHAR
*)data
)[req
->len
] = 0;
1057 if (type
) *type
= req
->type
;
1058 if (count
) *count
= req
->len
;
1063 /******************************************************************************
1064 * RegEnumValueA [ADVAPI32.141]
1066 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1067 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1069 DWORD ret
, len
, total_len
;
1070 struct enum_key_value_request
*req
= get_req_buffer();
1072 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1073 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1075 /* NT only checks count, not val_count */
1076 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1081 if ((ret
= reg_server_call( REQ_ENUM_KEY_VALUE
)) != ERROR_SUCCESS
) return ret
;
1083 len
= strlenW( req
->name
) + 1;
1084 if (len
> *val_count
) return ERROR_MORE_DATA
;
1085 memcpyWtoA( value
, req
->name
, len
);
1086 *val_count
= len
- 1;
1088 total_len
= is_string( req
->type
) ? req
->len
/sizeof(WCHAR
) : req
->len
;
1092 if (*count
< total_len
) ret
= ERROR_MORE_DATA
;
1096 unsigned int max
= server_remaining( req
->data
);
1097 unsigned int pos
= 0;
1098 while (pos
< req
->len
)
1100 unsigned int len
= min( req
->len
- pos
, max
);
1101 if (is_string( req
->type
))
1102 memcpyWtoA( data
+ pos
/sizeof(WCHAR
), (WCHAR
*)req
->data
, len
/sizeof(WCHAR
) );
1104 memcpy( data
+ pos
, req
->data
, len
);
1105 if ((pos
+= len
) >= req
->len
) break;
1107 if ((ret
= reg_server_call( REQ_ENUM_KEY_VALUE
)) != ERROR_SUCCESS
) return ret
;
1110 /* if the type is REG_SZ and data is not 0-terminated
1111 * and there is enough space in the buffer NT appends a \0 */
1112 if (total_len
&& is_string(req
->type
) && (total_len
< *count
) && data
[total_len
-1])
1113 data
[total_len
] = 0;
1116 if (count
) *count
= total_len
;
1117 if (type
) *type
= req
->type
;
1123 /******************************************************************************
1124 * RegDeleteValueW [ADVAPI32.136]
1127 * hkey [I] handle to key
1128 * name [I] name of value to delete
1133 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
1135 UNICODE_STRING nameW
;
1136 RtlInitUnicodeString( &nameW
, name
);
1137 return RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
1141 /******************************************************************************
1142 * RegDeleteValueA [ADVAPI32.135]
1144 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
1146 UNICODE_STRING nameW
;
1150 RtlInitAnsiString( &nameA
, name
);
1151 /* FIXME: should use Unicode buffer in TEB */
1152 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1154 status
= NtDeleteValueKey( hkey
, &nameW
);
1155 RtlFreeUnicodeString( &nameW
);
1157 return RtlNtStatusToDosError( status
);
1161 /******************************************************************************
1162 * RegLoadKeyW [ADVAPI32.185]
1165 * hkey [I] Handle of open key
1166 * subkey [I] Address of name of subkey
1167 * filename [I] Address of filename for registry information
1169 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
1171 struct load_registry_request
*req
= get_req_buffer();
1173 DWORD ret
, err
= GetLastError();
1175 TRACE( "(%x,%s,%s)\n", hkey
, debugstr_w(subkey
), debugstr_w(filename
) );
1177 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1178 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1180 if ((file
= CreateFileW( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1181 FILE_ATTRIBUTE_NORMAL
, -1 )) == INVALID_HANDLE_VALUE
)
1183 ret
= GetLastError();
1188 if ((ret
= copy_nameW( req
->name
, subkey
)) != ERROR_SUCCESS
) goto done
;
1189 ret
= reg_server_call( REQ_LOAD_REGISTRY
);
1190 CloseHandle( file
);
1193 SetLastError( err
); /* restore the last error code */
1198 /******************************************************************************
1199 * RegLoadKeyA [ADVAPI32.184]
1201 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
1203 struct load_registry_request
*req
= get_req_buffer();
1205 DWORD ret
, err
= GetLastError();
1207 TRACE( "(%x,%s,%s)\n", hkey
, debugstr_a(subkey
), debugstr_a(filename
) );
1209 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1210 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1212 if ((file
= CreateFileA( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1213 FILE_ATTRIBUTE_NORMAL
, -1 )) == INVALID_HANDLE_VALUE
)
1215 ret
= GetLastError();
1220 if ((ret
= copy_nameAtoW( req
->name
, subkey
)) != ERROR_SUCCESS
) goto done
;
1221 ret
= reg_server_call( REQ_LOAD_REGISTRY
);
1222 CloseHandle( file
);
1225 SetLastError( err
); /* restore the last error code */
1230 /******************************************************************************
1231 * RegSaveKeyA [ADVAPI32.165]
1234 * hkey [I] Handle of key where save begins
1235 * lpFile [I] Address of filename to save to
1236 * sa [I] Address of security structure
1238 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
1240 struct save_registry_request
*req
= get_req_buffer();
1247 TRACE( "(%x,%s,%p)\n", hkey
, debugstr_a(file
), sa
);
1249 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
1251 err
= GetLastError();
1252 GetFullPathNameA( file
, sizeof(buffer
), buffer
, &name
);
1255 sprintf( name
, "reg%04x.tmp", count
++ );
1256 handle
= CreateFileA( buffer
, GENERIC_WRITE
, 0, NULL
,
1257 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, -1 );
1258 if (handle
!= INVALID_HANDLE_VALUE
) break;
1259 if ((ret
= GetLastError()) != ERROR_ALREADY_EXISTS
) goto done
;
1261 /* Something gone haywire ? Please report if this happens abnormally */
1263 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
);
1268 ret
= reg_server_call( REQ_SAVE_REGISTRY
);
1269 CloseHandle( handle
);
1272 if (!MoveFileExA( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
1274 ERR( "Failed to move %s to %s\n", buffer
, file
);
1275 ret
= GetLastError();
1278 if (ret
) DeleteFileA( buffer
);
1281 SetLastError( err
); /* restore last error code */
1286 /******************************************************************************
1287 * RegSaveKeyW [ADVAPI32.166]
1289 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
1291 LPSTR fileA
= HEAP_strdupWtoA( GetProcessHeap(), 0, file
);
1292 DWORD ret
= RegSaveKeyA( hkey
, fileA
, sa
);
1293 if (fileA
) HeapFree( GetProcessHeap(), 0, fileA
);