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
);
252 /******************************************************************************
253 * RegEnumKeyExW [ADVAPI32.139]
256 * hkey [I] Handle to key to enumerate
257 * index [I] Index of subkey to enumerate
258 * name [O] Buffer for subkey name
259 * name_len [O] Size of subkey buffer
260 * reserved [I] Reserved
261 * class [O] Buffer for class string
262 * class_len [O] Size of class buffer
263 * ft [O] Time key last written to
265 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
266 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
269 char buffer
[256], *buf_ptr
= buffer
;
270 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
273 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
274 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
276 if (reserved
) return ERROR_INVALID_PARAMETER
;
278 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
279 buffer
, sizeof(buffer
), &total_size
);
281 while (status
== STATUS_BUFFER_OVERFLOW
)
283 /* retry with a dynamically allocated buffer */
284 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
285 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
286 return ERROR_NOT_ENOUGH_MEMORY
;
287 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
288 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
289 buf_ptr
, total_size
, &total_size
);
294 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
295 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
297 if (ft
) *ft
= info
->LastWriteTime
;
299 if (len
>= *name_len
|| (class_len
&& (cls_len
>= *class_len
)))
300 status
= STATUS_BUFFER_OVERFLOW
;
304 memcpy( name
, info
->Name
, info
->NameLength
);
308 *class_len
= cls_len
;
311 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
318 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
319 return RtlNtStatusToDosError( status
);
323 /******************************************************************************
324 * RegEnumKeyExA [ADVAPI32.138]
326 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
327 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
330 char buffer
[256], *buf_ptr
= buffer
;
331 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
334 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
335 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
337 if (reserved
) return ERROR_INVALID_PARAMETER
;
339 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
340 buffer
, sizeof(buffer
), &total_size
);
342 while (status
== STATUS_BUFFER_OVERFLOW
)
344 /* retry with a dynamically allocated buffer */
345 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
346 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
347 return ERROR_NOT_ENOUGH_MEMORY
;
348 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
349 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
350 buf_ptr
, total_size
, &total_size
);
355 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, info
->Name
, info
->NameLength
/sizeof(WCHAR
),
356 NULL
, 0, NULL
, NULL
);
357 DWORD cls_len
= WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
358 info
->ClassLength
/ sizeof(WCHAR
),
359 NULL
, 0, NULL
, NULL
);
361 if (ft
) *ft
= info
->LastWriteTime
;
363 if (len
>= *name_len
|| (class_len
&& (cls_len
>= *class_len
)))
364 status
= STATUS_BUFFER_OVERFLOW
;
368 WideCharToMultiByte( CP_ACP
, 0, info
->Name
, info
->NameLength
/sizeof(WCHAR
),
369 name
, len
, NULL
, NULL
);
373 *class_len
= cls_len
;
376 WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
377 info
->ClassLength
/ sizeof(WCHAR
),
378 class, cls_len
, NULL
, NULL
);
385 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
386 return RtlNtStatusToDosError( status
);
390 /******************************************************************************
391 * RegEnumKeyW [ADVAPI32.140]
393 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
395 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
399 /******************************************************************************
400 * RegEnumKeyA [ADVAPI32.137]
402 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
404 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
408 /******************************************************************************
409 * RegQueryInfoKeyW [ADVAPI32.153]
412 * hkey [I] Handle to key to query
413 * class [O] Buffer for class string
414 * class_len [O] Size of class string buffer
415 * reserved [I] Reserved
416 * subkeys [O] Buffer for number of subkeys
417 * max_subkey [O] Buffer for longest subkey name length
418 * max_class [O] Buffer for longest class string length
419 * values [O] Buffer for number of value entries
420 * max_value [O] Buffer for longest value name length
421 * max_data [O] Buffer for longest value data length
422 * security [O] Buffer for security descriptor length
423 * modif [O] Modification time
425 * - win95 allows class to be valid and class_len to be NULL
426 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
427 * - both allow class to be NULL and class_len to be NULL
428 * (it's hard to test validity, so test !NULL instead)
430 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
431 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
432 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
433 LPDWORD security
, FILETIME
*modif
)
436 char buffer
[256], *buf_ptr
= buffer
;
437 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
440 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
441 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
443 if (class && !class_len
&& !(GetVersion() & 0x80000000 /*NT*/))
444 return ERROR_INVALID_PARAMETER
;
446 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
450 /* retry with a dynamically allocated buffer */
451 while (status
== STATUS_BUFFER_OVERFLOW
)
453 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
454 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
455 return ERROR_NOT_ENOUGH_MEMORY
;
456 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
457 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
462 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
464 status
= STATUS_BUFFER_OVERFLOW
;
468 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
469 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
474 if (!status
|| status
== STATUS_BUFFER_OVERFLOW
)
476 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
477 if (subkeys
) *subkeys
= info
->SubKeys
;
478 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
479 if (max_class
) *max_class
= info
->MaxClassLen
;
480 if (values
) *values
= info
->Values
;
481 if (max_value
) *max_value
= info
->MaxValueNameLen
;
482 if (max_data
) *max_data
= info
->MaxValueDataLen
;
483 if (modif
) *modif
= info
->LastWriteTime
;
486 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
487 return RtlNtStatusToDosError( status
);
491 /******************************************************************************
492 * RegQueryInfoKeyA [ADVAPI32.152]
494 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
495 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
496 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
497 LPDWORD security
, FILETIME
*modif
)
500 char buffer
[256], *buf_ptr
= buffer
;
501 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
504 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
505 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
507 if (class && !class_len
&& !(GetVersion() & 0x80000000 /*NT*/))
508 return ERROR_INVALID_PARAMETER
;
510 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
512 if (class || class_len
)
514 /* retry with a dynamically allocated buffer */
515 while (status
== STATUS_BUFFER_OVERFLOW
)
517 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
518 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
519 return ERROR_NOT_ENOUGH_MEMORY
;
520 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
521 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
526 DWORD len
= WideCharToMultiByte( CP_ACP
, 0,
527 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
528 info
->ClassLength
/sizeof(WCHAR
),
529 NULL
, 0, NULL
, NULL
);
532 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
535 if (class && !status
)
537 WideCharToMultiByte( CP_ACP
, 0,
538 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
539 info
->ClassLength
/sizeof(WCHAR
),
540 class, len
, NULL
, NULL
);
546 if (!status
|| status
== STATUS_BUFFER_OVERFLOW
)
548 if (subkeys
) *subkeys
= info
->SubKeys
;
549 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
550 if (max_class
) *max_class
= info
->MaxClassLen
;
551 if (values
) *values
= info
->Values
;
552 if (max_value
) *max_value
= info
->MaxValueNameLen
;
553 if (max_data
) *max_data
= info
->MaxValueDataLen
;
554 if (modif
) *modif
= info
->LastWriteTime
;
557 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
558 return RtlNtStatusToDosError( status
);
562 /******************************************************************************
563 * RegCloseKey [ADVAPI32.126]
565 * Releases the handle of the specified key
568 * hkey [I] Handle of key to close
571 * Success: ERROR_SUCCESS
572 * Failure: Error code
574 DWORD WINAPI
RegCloseKey( HKEY hkey
)
576 if (!hkey
|| hkey
>= 0x80000000) return ERROR_SUCCESS
;
577 return RtlNtStatusToDosError( NtClose( hkey
) );
581 /******************************************************************************
582 * RegDeleteKeyW [ADVAPI32.134]
585 * hkey [I] Handle to open key
586 * name [I] Name of subkey to delete
589 * Success: ERROR_SUCCESS
590 * Failure: Error code
592 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
597 if (!name
|| !*name
) return NtDeleteKey( hkey
);
598 if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, 0, &tmp
)))
600 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
607 /******************************************************************************
608 * RegDeleteKeyA [ADVAPI32.133]
610 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
615 if (!name
|| !*name
) return NtDeleteKey( hkey
);
616 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, 0, &tmp
)))
618 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
626 /******************************************************************************
627 * RegSetValueExW [ADVAPI32.170]
629 * Sets the data and type of a value under a register key
632 * hkey [I] Handle of key to set value for
633 * name [I] Name of value to set
634 * reserved [I] Reserved - must be zero
635 * type [I] Flag for value type
636 * data [I] Address of value data
637 * count [I] Size of value data
640 * Success: ERROR_SUCCESS
641 * Failure: Error code
644 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
645 * NT does definitely care (aj)
647 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
648 DWORD type
, CONST BYTE
*data
, DWORD count
)
650 UNICODE_STRING nameW
;
652 if (count
&& is_string(type
))
654 LPCWSTR str
= (LPCWSTR
)data
;
655 /* if user forgot to count terminating null, add it (yes NT does this) */
656 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
657 count
+= sizeof(WCHAR
);
660 RtlInitUnicodeString( &nameW
, name
);
661 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
665 /******************************************************************************
666 * RegSetValueExA [ADVAPI32.169]
668 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
669 CONST BYTE
*data
, DWORD count
)
671 UNICODE_STRING nameW
;
676 if (count
&& is_string(type
))
678 /* if user forgot to count terminating null, add it (yes NT does this) */
679 if (data
[count
-1] && !data
[count
]) count
++;
682 if (is_string( type
)) /* need to convert to Unicode */
684 DWORD lenW
= MultiByteToWideChar( CP_ACP
, 0, data
, count
, NULL
, 0 );
685 if (!(dataW
= HeapAlloc( GetProcessHeap(), 0, lenW
*sizeof(WCHAR
) )))
686 return ERROR_OUTOFMEMORY
;
687 MultiByteToWideChar( CP_ACP
, 0, data
, count
, dataW
, lenW
);
688 count
= lenW
* sizeof(WCHAR
);
689 data
= (BYTE
*)dataW
;
692 RtlInitAnsiString( &nameA
, name
);
693 /* FIXME: should use Unicode buffer in TEB */
694 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
696 status
= NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
);
697 RtlFreeUnicodeString( &nameW
);
699 if (dataW
) HeapFree( GetProcessHeap(), 0, dataW
);
700 return RtlNtStatusToDosError( status
);
704 /******************************************************************************
705 * RegSetValueW [ADVAPI32.171]
707 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR name
, DWORD type
, LPCWSTR data
, DWORD count
)
712 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey
, debugstr_w(name
), type
, debugstr_w(data
), count
);
714 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
716 if (name
&& name
[0]) /* need to create the subkey */
718 if ((ret
= RegCreateKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
721 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
,
722 (strlenW( data
) + 1) * sizeof(WCHAR
) );
723 if (subkey
!= hkey
) RegCloseKey( subkey
);
728 /******************************************************************************
729 * RegSetValueA [ADVAPI32.168]
731 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
736 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey
, debugstr_a(name
), type
, debugstr_a(data
), count
);
738 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
740 if (name
&& name
[0]) /* need to create the subkey */
742 if ((ret
= RegCreateKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
744 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
, strlen(data
)+1 );
745 if (subkey
!= hkey
) RegCloseKey( subkey
);
751 /******************************************************************************
752 * RegQueryValueExW [ADVAPI32.158]
754 * Retrieves type and data for a specified name associated with an open key
757 * hkey [I] Handle of key to query
758 * name [I] Name of value to query
759 * reserved [I] Reserved - must be NULL
760 * type [O] Address of buffer for value type. If NULL, the type
762 * data [O] Address of data buffer. If NULL, the actual data is
764 * count [I/O] Address of data buffer size
767 * ERROR_SUCCESS: Success
768 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
769 * buffer is left untouched. The MS-documentation is wrong (js) !!!
771 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
772 LPBYTE data
, LPDWORD count
)
775 UNICODE_STRING name_str
;
777 char buffer
[256], *buf_ptr
= buffer
;
778 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
779 static const int info_size
= sizeof(*info
) - sizeof(info
->Data
);
781 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
782 hkey
, debugstr_w(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
784 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
786 RtlInitUnicodeString( &name_str
, name
);
788 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
789 else total_size
= info_size
;
791 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
792 buffer
, total_size
, &total_size
);
793 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
797 /* retry with a dynamically allocated buffer */
798 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
800 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
801 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
802 return ERROR_NOT_ENOUGH_MEMORY
;
803 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
804 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
805 buf_ptr
, total_size
, &total_size
);
810 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
811 /* if the type is REG_SZ and data is not 0-terminated
812 * and there is enough space in the buffer NT appends a \0 */
813 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
815 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
816 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
819 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
822 if (type
) *type
= info
->Type
;
823 if (count
) *count
= total_size
- info_size
;
826 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
827 return RtlNtStatusToDosError(status
);
831 /******************************************************************************
832 * RegQueryValueExA [ADVAPI32.157]
835 * the documentation is wrong: if the buffer is too small it remains untouched
837 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
838 LPBYTE data
, LPDWORD count
)
842 UNICODE_STRING nameW
;
844 char buffer
[256], *buf_ptr
= buffer
;
845 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
846 static const int info_size
= sizeof(*info
) - sizeof(info
->Data
);
848 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
849 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
851 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
853 RtlInitAnsiString( &nameA
, name
);
854 /* FIXME: should use Unicode buffer in TEB */
855 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
856 return RtlNtStatusToDosError(status
);
858 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
859 buffer
, sizeof(buffer
), &total_size
);
860 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
862 /* we need to fetch the contents for a string type even if not requested,
863 * because we need to compute the length of the ASCII string. */
864 if (data
|| is_string(info
->Type
))
866 /* retry with a dynamically allocated buffer */
867 while (status
== STATUS_BUFFER_OVERFLOW
)
869 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
870 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
872 status
= STATUS_NO_MEMORY
;
875 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
876 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
877 buf_ptr
, total_size
, &total_size
);
882 if (is_string(info
->Type
))
884 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info_size
),
885 (total_size
- info_size
) /sizeof(WCHAR
),
886 NULL
, 0, NULL
, NULL
);
889 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
892 WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info_size
),
893 (total_size
- info_size
) /sizeof(WCHAR
),
894 data
, len
, NULL
, NULL
);
895 /* if the type is REG_SZ and data is not 0-terminated
896 * and there is enough space in the buffer NT appends a \0 */
897 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
900 total_size
= len
+ info_size
;
904 if (total_size
- info_size
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
905 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
908 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
911 if (type
) *type
= info
->Type
;
912 if (count
) *count
= total_size
- info_size
;
915 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
916 RtlFreeUnicodeString( &nameW
);
917 return RtlNtStatusToDosError(status
);
921 /******************************************************************************
922 * RegQueryValueW [ADVAPI32.159]
924 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
929 TRACE("(%x,%s,%p,%ld)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
933 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
935 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
936 if (subkey
!= hkey
) RegCloseKey( subkey
);
937 if (ret
== ERROR_FILE_NOT_FOUND
)
939 /* return empty string if default value not found */
941 if (count
) *count
= 1;
948 /******************************************************************************
949 * RegQueryValueA [ADVAPI32.156]
951 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
956 TRACE("(%x,%s,%p,%ld)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
960 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
962 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
963 if (subkey
!= hkey
) RegCloseKey( subkey
);
964 if (ret
== ERROR_FILE_NOT_FOUND
)
966 /* return empty string if default value not found */
968 if (count
) *count
= 1;
975 /******************************************************************************
976 * RegEnumValueW [ADVAPI32.142]
979 * hkey [I] Handle to key to query
980 * index [I] Index of value to query
981 * value [O] Value string
982 * val_count [I/O] Size of value buffer (in wchars)
983 * reserved [I] Reserved
985 * data [O] Value data
986 * count [I/O] Size of data buffer (in bytes)
989 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
990 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
993 struct enum_key_value_request
*req
= get_req_buffer();
995 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
996 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
998 /* NT only checks count, not val_count */
999 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1004 if ((ret
= reg_server_call( REQ_ENUM_KEY_VALUE
)) != ERROR_SUCCESS
) return ret
;
1006 len
= strlenW( req
->name
) + 1;
1007 if (len
> *val_count
) return ERROR_MORE_DATA
;
1008 memcpy( value
, req
->name
, len
* sizeof(WCHAR
) );
1009 *val_count
= len
- 1;
1013 if (*count
< req
->len
) ret
= ERROR_MORE_DATA
;
1017 unsigned int max
= server_remaining( req
->data
);
1018 unsigned int pos
= 0;
1019 while (pos
< req
->len
)
1021 unsigned int len
= min( req
->len
- pos
, max
);
1022 memcpy( data
+ pos
, req
->data
, len
);
1023 if ((pos
+= len
) >= req
->len
) break;
1025 if ((ret
= reg_server_call( REQ_ENUM_KEY_VALUE
)) != ERROR_SUCCESS
) return ret
;
1028 /* if the type is REG_SZ and data is not 0-terminated
1029 * and there is enough space in the buffer NT appends a \0 */
1030 if (req
->len
&& is_string(req
->type
) &&
1031 (req
->len
< *count
) && ((WCHAR
*)data
)[req
->len
-1]) ((WCHAR
*)data
)[req
->len
] = 0;
1033 if (type
) *type
= req
->type
;
1034 if (count
) *count
= req
->len
;
1039 /******************************************************************************
1040 * RegEnumValueA [ADVAPI32.141]
1042 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1043 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1045 DWORD ret
, len
, total_len
;
1046 struct enum_key_value_request
*req
= get_req_buffer();
1048 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1049 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1051 /* NT only checks count, not val_count */
1052 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1057 if ((ret
= reg_server_call( REQ_ENUM_KEY_VALUE
)) != ERROR_SUCCESS
) return ret
;
1059 len
= strlenW( req
->name
) + 1;
1060 if (len
> *val_count
) return ERROR_MORE_DATA
;
1061 memcpyWtoA( value
, req
->name
, len
);
1062 *val_count
= len
- 1;
1064 total_len
= is_string( req
->type
) ? req
->len
/sizeof(WCHAR
) : req
->len
;
1068 if (*count
< total_len
) ret
= ERROR_MORE_DATA
;
1072 unsigned int max
= server_remaining( req
->data
);
1073 unsigned int pos
= 0;
1074 while (pos
< req
->len
)
1076 unsigned int len
= min( req
->len
- pos
, max
);
1077 if (is_string( req
->type
))
1078 memcpyWtoA( data
+ pos
/sizeof(WCHAR
), (WCHAR
*)req
->data
, len
/sizeof(WCHAR
) );
1080 memcpy( data
+ pos
, req
->data
, len
);
1081 if ((pos
+= len
) >= req
->len
) break;
1083 if ((ret
= reg_server_call( REQ_ENUM_KEY_VALUE
)) != ERROR_SUCCESS
) return ret
;
1086 /* if the type is REG_SZ and data is not 0-terminated
1087 * and there is enough space in the buffer NT appends a \0 */
1088 if (total_len
&& is_string(req
->type
) && (total_len
< *count
) && data
[total_len
-1])
1089 data
[total_len
] = 0;
1092 if (count
) *count
= total_len
;
1093 if (type
) *type
= req
->type
;
1099 /******************************************************************************
1100 * RegDeleteValueW [ADVAPI32.136]
1103 * hkey [I] handle to key
1104 * name [I] name of value to delete
1109 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
1111 UNICODE_STRING nameW
;
1112 RtlInitUnicodeString( &nameW
, name
);
1113 return RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
1117 /******************************************************************************
1118 * RegDeleteValueA [ADVAPI32.135]
1120 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
1122 UNICODE_STRING nameW
;
1126 RtlInitAnsiString( &nameA
, name
);
1127 /* FIXME: should use Unicode buffer in TEB */
1128 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1130 status
= NtDeleteValueKey( hkey
, &nameW
);
1131 RtlFreeUnicodeString( &nameW
);
1133 return RtlNtStatusToDosError( status
);
1137 /******************************************************************************
1138 * RegLoadKeyW [ADVAPI32.185]
1141 * hkey [I] Handle of open key
1142 * subkey [I] Address of name of subkey
1143 * filename [I] Address of filename for registry information
1145 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
1148 DWORD ret
, len
, err
= GetLastError();
1150 TRACE( "(%x,%s,%s)\n", hkey
, debugstr_w(subkey
), debugstr_w(filename
) );
1152 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1153 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1155 len
= strlenW( subkey
) * sizeof(WCHAR
);
1156 if (len
> MAX_PATH
*sizeof(WCHAR
)) return ERROR_INVALID_PARAMETER
;
1158 if ((file
= CreateFileW( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1159 FILE_ATTRIBUTE_NORMAL
, -1 )) == INVALID_HANDLE_VALUE
)
1161 ret
= GetLastError();
1167 struct load_registry_request
*req
= server_alloc_req( sizeof(*req
), len
);
1170 memcpy( server_data_ptr(req
), subkey
, len
);
1171 ret
= reg_server_call( REQ_LOAD_REGISTRY
);
1174 CloseHandle( file
);
1177 SetLastError( err
); /* restore the last error code */
1182 /******************************************************************************
1183 * RegLoadKeyA [ADVAPI32.184]
1185 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
1188 DWORD ret
, len
, err
= GetLastError();
1190 TRACE( "(%x,%s,%s)\n", hkey
, debugstr_a(subkey
), debugstr_a(filename
) );
1192 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1193 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1195 len
= MultiByteToWideChar( CP_ACP
, 0, subkey
, strlen(subkey
), NULL
, 0 ) * sizeof(WCHAR
);
1196 if (len
> MAX_PATH
*sizeof(WCHAR
)) return ERROR_INVALID_PARAMETER
;
1198 if ((file
= CreateFileA( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1199 FILE_ATTRIBUTE_NORMAL
, -1 )) == INVALID_HANDLE_VALUE
)
1201 ret
= GetLastError();
1207 struct load_registry_request
*req
= server_alloc_req( sizeof(*req
), len
);
1210 MultiByteToWideChar( CP_ACP
, 0, subkey
, strlen(subkey
),
1211 server_data_ptr(req
), len
/sizeof(WCHAR
) );
1212 ret
= reg_server_call( REQ_LOAD_REGISTRY
);
1215 CloseHandle( file
);
1218 SetLastError( err
); /* restore the last error code */
1223 /******************************************************************************
1224 * RegSaveKeyA [ADVAPI32.165]
1227 * hkey [I] Handle of key where save begins
1228 * lpFile [I] Address of filename to save to
1229 * sa [I] Address of security structure
1231 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
1239 TRACE( "(%x,%s,%p)\n", hkey
, debugstr_a(file
), sa
);
1241 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
1243 err
= GetLastError();
1244 GetFullPathNameA( file
, sizeof(buffer
), buffer
, &name
);
1247 sprintf( name
, "reg%04x.tmp", count
++ );
1248 handle
= CreateFileA( buffer
, GENERIC_WRITE
, 0, NULL
,
1249 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, -1 );
1250 if (handle
!= INVALID_HANDLE_VALUE
) break;
1251 if ((ret
= GetLastError()) != ERROR_ALREADY_EXISTS
) goto done
;
1253 /* Something gone haywire ? Please report if this happens abnormally */
1255 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
);
1260 struct save_registry_request
*req
= server_alloc_req( sizeof(*req
), 0 );
1263 ret
= reg_server_call( REQ_SAVE_REGISTRY
);
1267 CloseHandle( handle
);
1270 if (!MoveFileExA( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
1272 ERR( "Failed to move %s to %s\n", buffer
, file
);
1273 ret
= GetLastError();
1276 if (ret
) DeleteFileA( buffer
);
1279 SetLastError( err
); /* restore last error code */
1284 /******************************************************************************
1285 * RegSaveKeyW [ADVAPI32.166]
1287 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
1289 LPSTR fileA
= HEAP_strdupWtoA( GetProcessHeap(), 0, file
);
1290 DWORD ret
= RegSaveKeyA( hkey
, fileA
, sa
);
1291 if (fileA
) HeapFree( GetProcessHeap(), 0, fileA
);