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"
26 #include "debugtools.h"
28 DEFAULT_DEBUG_CHANNEL(reg
);
31 /* Unicode->Ansi conversion without string delimiters */
32 static LPSTR
memcpyWtoA( LPSTR dst
, LPCWSTR src
, INT n
)
35 while (n
-- > 0) *p
++ = (CHAR
)*src
++;
39 /* check if value type needs string conversion (Ansi<->Unicode) */
40 static inline int is_string( DWORD type
)
42 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
45 /* do a server call without setting the last error code */
46 static inline int reg_server_call( enum request req
)
48 unsigned int res
= server_call_noerr( req
);
49 if (res
) res
= RtlNtStatusToDosError(res
);
53 /******************************************************************************
54 * RegCreateKeyExW [ADVAPI32.131]
57 * hkey [I] Handle of an open key
58 * name [I] Address of subkey name
59 * reserved [I] Reserved - must be 0
60 * class [I] Address of class string
61 * options [I] Special options flag
62 * access [I] Desired security access
63 * sa [I] Address of key security structure
64 * retkey [O] Address of buffer for opened handle
65 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
68 * in case of failing retkey remains untouched
70 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
71 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
72 LPHKEY retkey
, LPDWORD dispos
)
74 OBJECT_ATTRIBUTES attr
;
75 UNICODE_STRING nameW
, classW
;
77 if (reserved
) return ERROR_INVALID_PARAMETER
;
78 if (!(access
& KEY_ALL_ACCESS
) || (access
& ~KEY_ALL_ACCESS
)) return ERROR_ACCESS_DENIED
;
80 attr
.Length
= sizeof(attr
);
81 attr
.RootDirectory
= hkey
;
82 attr
.ObjectName
= &nameW
;
84 attr
.SecurityDescriptor
= NULL
;
85 attr
.SecurityQualityOfService
= NULL
;
86 RtlInitUnicodeString( &nameW
, name
);
87 RtlInitUnicodeString( &classW
, class );
89 return RtlNtStatusToDosError( NtCreateKey( retkey
, access
, &attr
, 0,
90 &classW
, options
, dispos
) );
94 /******************************************************************************
95 * RegCreateKeyExA [ADVAPI32.130]
97 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
98 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
99 LPHKEY retkey
, LPDWORD dispos
)
101 OBJECT_ATTRIBUTES attr
;
102 UNICODE_STRING nameW
, classW
;
103 ANSI_STRING nameA
, classA
;
106 if (reserved
) return ERROR_INVALID_PARAMETER
;
107 if (!(access
& KEY_ALL_ACCESS
) || (access
& ~KEY_ALL_ACCESS
)) return ERROR_ACCESS_DENIED
;
109 attr
.Length
= sizeof(attr
);
110 attr
.RootDirectory
= hkey
;
111 attr
.ObjectName
= &nameW
;
113 attr
.SecurityDescriptor
= NULL
;
114 attr
.SecurityQualityOfService
= NULL
;
115 RtlInitAnsiString( &nameA
, name
);
116 RtlInitAnsiString( &classA
, class );
118 /* FIXME: should use Unicode buffer in TEB */
119 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
121 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
123 status
= NtCreateKey( retkey
, access
, &attr
, 0, &classW
, options
, dispos
);
124 RtlFreeUnicodeString( &classW
);
126 RtlFreeUnicodeString( &nameW
);
128 return RtlNtStatusToDosError( status
);
132 /******************************************************************************
133 * RegCreateKeyW [ADVAPI32.132]
135 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR name
, LPHKEY retkey
)
137 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
138 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
139 return RegCreateKeyExW( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
140 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
144 /******************************************************************************
145 * RegCreateKeyA [ADVAPI32.129]
147 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
149 return RegCreateKeyExA( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
150 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
155 /******************************************************************************
156 * RegOpenKeyExW [ADVAPI32.150]
158 * Opens the specified key
160 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
163 * hkey [I] Handle of open key
164 * name [I] Name of subkey to open
165 * reserved [I] Reserved - must be zero
166 * access [I] Security access mask
167 * retkey [O] Handle to open key
170 * Success: ERROR_SUCCESS
171 * Failure: Error code
174 * in case of failing is retkey = 0
176 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, REGSAM access
, LPHKEY retkey
)
178 OBJECT_ATTRIBUTES attr
;
179 UNICODE_STRING nameW
;
181 attr
.Length
= sizeof(attr
);
182 attr
.RootDirectory
= hkey
;
183 attr
.ObjectName
= &nameW
;
185 attr
.SecurityDescriptor
= NULL
;
186 attr
.SecurityQualityOfService
= NULL
;
187 RtlInitUnicodeString( &nameW
, name
);
188 return RtlNtStatusToDosError( NtOpenKey( retkey
, access
, &attr
) );
192 /******************************************************************************
193 * RegOpenKeyExA [ADVAPI32.149]
195 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, REGSAM access
, LPHKEY retkey
)
197 OBJECT_ATTRIBUTES attr
;
198 UNICODE_STRING nameW
;
202 attr
.Length
= sizeof(attr
);
203 attr
.RootDirectory
= hkey
;
204 attr
.ObjectName
= &nameW
;
206 attr
.SecurityDescriptor
= NULL
;
207 attr
.SecurityQualityOfService
= NULL
;
209 RtlInitAnsiString( &nameA
, name
);
210 /* FIXME: should use Unicode buffer in TEB */
211 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
213 status
= NtOpenKey( retkey
, access
, &attr
);
214 RtlFreeUnicodeString( &nameW
);
216 return RtlNtStatusToDosError( status
);
220 /******************************************************************************
221 * RegOpenKeyW [ADVAPI32.151]
224 * hkey [I] Handle of open key
225 * name [I] Address of name of subkey to open
226 * retkey [O] Handle to open key
229 * Success: ERROR_SUCCESS
230 * Failure: Error code
233 * in case of failing is retkey = 0
235 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, LPHKEY retkey
)
237 return RegOpenKeyExW( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
241 /******************************************************************************
242 * RegOpenKeyA [ADVAPI32.148]
244 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
246 return RegOpenKeyExA( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
250 /******************************************************************************
251 * RegOpenCurrentUser [ADVAPI32]
252 * FIXME: This function is supposed to retrieve a handle to the
253 * HKEY_CURRENT_USER for the user the current thread is impersonating.
254 * Since Wine does not currently allow threads to impersonate other users,
255 * this stub should work fine.
257 DWORD WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
259 return RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
264 /******************************************************************************
265 * RegEnumKeyExW [ADVAPI32.139]
268 * hkey [I] Handle to key to enumerate
269 * index [I] Index of subkey to enumerate
270 * name [O] Buffer for subkey name
271 * name_len [O] Size of subkey buffer
272 * reserved [I] Reserved
273 * class [O] Buffer for class string
274 * class_len [O] Size of class buffer
275 * ft [O] Time key last written to
277 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
278 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
281 char buffer
[256], *buf_ptr
= buffer
;
282 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
285 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
286 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
288 if (reserved
) return ERROR_INVALID_PARAMETER
;
290 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
291 buffer
, sizeof(buffer
), &total_size
);
293 while (status
== STATUS_BUFFER_OVERFLOW
)
295 /* retry with a dynamically allocated buffer */
296 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
297 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
298 return ERROR_NOT_ENOUGH_MEMORY
;
299 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
300 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
301 buf_ptr
, total_size
, &total_size
);
306 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
307 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
309 if (ft
) *ft
= info
->LastWriteTime
;
311 if (len
>= *name_len
|| (class_len
&& (cls_len
>= *class_len
)))
312 status
= STATUS_BUFFER_OVERFLOW
;
316 memcpy( name
, info
->Name
, info
->NameLength
);
320 *class_len
= cls_len
;
323 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
330 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
331 return RtlNtStatusToDosError( status
);
335 /******************************************************************************
336 * RegEnumKeyExA [ADVAPI32.138]
338 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
339 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
342 char buffer
[256], *buf_ptr
= buffer
;
343 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
346 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
347 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
349 if (reserved
) return ERROR_INVALID_PARAMETER
;
351 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
352 buffer
, sizeof(buffer
), &total_size
);
354 while (status
== STATUS_BUFFER_OVERFLOW
)
356 /* retry with a dynamically allocated buffer */
357 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
358 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
359 return ERROR_NOT_ENOUGH_MEMORY
;
360 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
361 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
362 buf_ptr
, total_size
, &total_size
);
367 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, info
->Name
, info
->NameLength
/sizeof(WCHAR
),
368 NULL
, 0, NULL
, NULL
);
369 DWORD cls_len
= WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
370 info
->ClassLength
/ sizeof(WCHAR
),
371 NULL
, 0, NULL
, NULL
);
373 if (ft
) *ft
= info
->LastWriteTime
;
375 if (len
>= *name_len
|| (class_len
&& (cls_len
>= *class_len
)))
376 status
= STATUS_BUFFER_OVERFLOW
;
380 WideCharToMultiByte( CP_ACP
, 0, info
->Name
, info
->NameLength
/sizeof(WCHAR
),
381 name
, len
, NULL
, NULL
);
385 *class_len
= cls_len
;
388 WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
389 info
->ClassLength
/ sizeof(WCHAR
),
390 class, cls_len
, NULL
, NULL
);
397 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
398 return RtlNtStatusToDosError( status
);
402 /******************************************************************************
403 * RegEnumKeyW [ADVAPI32.140]
405 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
407 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
411 /******************************************************************************
412 * RegEnumKeyA [ADVAPI32.137]
414 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
416 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
420 /******************************************************************************
421 * RegQueryInfoKeyW [ADVAPI32.153]
424 * hkey [I] Handle to key to query
425 * class [O] Buffer for class string
426 * class_len [O] Size of class string buffer
427 * reserved [I] Reserved
428 * subkeys [O] Buffer for number of subkeys
429 * max_subkey [O] Buffer for longest subkey name length
430 * max_class [O] Buffer for longest class string length
431 * values [O] Buffer for number of value entries
432 * max_value [O] Buffer for longest value name length
433 * max_data [O] Buffer for longest value data length
434 * security [O] Buffer for security descriptor length
435 * modif [O] Modification time
437 * - win95 allows class to be valid and class_len to be NULL
438 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
439 * - both allow class to be NULL and class_len to be NULL
440 * (it's hard to test validity, so test !NULL instead)
442 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
443 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
444 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
445 LPDWORD security
, FILETIME
*modif
)
448 char buffer
[256], *buf_ptr
= buffer
;
449 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
452 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
453 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
455 if (class && !class_len
&& !(GetVersion() & 0x80000000 /*NT*/))
456 return ERROR_INVALID_PARAMETER
;
458 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
462 /* retry with a dynamically allocated buffer */
463 while (status
== STATUS_BUFFER_OVERFLOW
)
465 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
466 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
467 return ERROR_NOT_ENOUGH_MEMORY
;
468 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
469 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
474 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
476 status
= STATUS_BUFFER_OVERFLOW
;
480 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
481 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
486 if (!status
|| status
== STATUS_BUFFER_OVERFLOW
)
488 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
489 if (subkeys
) *subkeys
= info
->SubKeys
;
490 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
491 if (max_class
) *max_class
= info
->MaxClassLen
;
492 if (values
) *values
= info
->Values
;
493 if (max_value
) *max_value
= info
->MaxValueNameLen
;
494 if (max_data
) *max_data
= info
->MaxValueDataLen
;
495 if (modif
) *modif
= info
->LastWriteTime
;
498 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
499 return RtlNtStatusToDosError( status
);
503 /******************************************************************************
504 * RegQueryInfoKeyA [ADVAPI32.152]
506 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
507 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
508 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
509 LPDWORD security
, FILETIME
*modif
)
512 char buffer
[256], *buf_ptr
= buffer
;
513 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
516 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
517 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
519 if (class && !class_len
&& !(GetVersion() & 0x80000000 /*NT*/))
520 return ERROR_INVALID_PARAMETER
;
522 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
524 if (class || class_len
)
526 /* retry with a dynamically allocated buffer */
527 while (status
== STATUS_BUFFER_OVERFLOW
)
529 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
530 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
531 return ERROR_NOT_ENOUGH_MEMORY
;
532 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
533 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
538 DWORD len
= WideCharToMultiByte( CP_ACP
, 0,
539 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
540 info
->ClassLength
/sizeof(WCHAR
),
541 NULL
, 0, NULL
, NULL
);
544 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
547 if (class && !status
)
549 WideCharToMultiByte( CP_ACP
, 0,
550 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
551 info
->ClassLength
/sizeof(WCHAR
),
552 class, len
, NULL
, NULL
);
558 if (!status
|| status
== STATUS_BUFFER_OVERFLOW
)
560 if (subkeys
) *subkeys
= info
->SubKeys
;
561 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
562 if (max_class
) *max_class
= info
->MaxClassLen
;
563 if (values
) *values
= info
->Values
;
564 if (max_value
) *max_value
= info
->MaxValueNameLen
;
565 if (max_data
) *max_data
= info
->MaxValueDataLen
;
566 if (modif
) *modif
= info
->LastWriteTime
;
569 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
570 return RtlNtStatusToDosError( status
);
574 /******************************************************************************
575 * RegCloseKey [ADVAPI32.126]
577 * Releases the handle of the specified key
580 * hkey [I] Handle of key to close
583 * Success: ERROR_SUCCESS
584 * Failure: Error code
586 DWORD WINAPI
RegCloseKey( HKEY hkey
)
588 if (!hkey
|| hkey
>= 0x80000000) return ERROR_SUCCESS
;
589 return RtlNtStatusToDosError( NtClose( hkey
) );
593 /******************************************************************************
594 * RegDeleteKeyW [ADVAPI32.134]
597 * hkey [I] Handle to open key
598 * name [I] Name of subkey to delete
601 * Success: ERROR_SUCCESS
602 * Failure: Error code
604 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
609 if (!name
|| !*name
) return NtDeleteKey( hkey
);
610 if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, 0, &tmp
)))
612 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
619 /******************************************************************************
620 * RegDeleteKeyA [ADVAPI32.133]
622 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
627 if (!name
|| !*name
) return NtDeleteKey( hkey
);
628 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, 0, &tmp
)))
630 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
638 /******************************************************************************
639 * RegSetValueExW [ADVAPI32.170]
641 * Sets the data and type of a value under a register key
644 * hkey [I] Handle of key to set value for
645 * name [I] Name of value to set
646 * reserved [I] Reserved - must be zero
647 * type [I] Flag for value type
648 * data [I] Address of value data
649 * count [I] Size of value data
652 * Success: ERROR_SUCCESS
653 * Failure: Error code
656 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
657 * NT does definitely care (aj)
659 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
660 DWORD type
, CONST BYTE
*data
, DWORD count
)
662 UNICODE_STRING nameW
;
664 if (count
&& is_string(type
))
666 LPCWSTR str
= (LPCWSTR
)data
;
667 /* if user forgot to count terminating null, add it (yes NT does this) */
668 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
669 count
+= sizeof(WCHAR
);
672 RtlInitUnicodeString( &nameW
, name
);
673 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
677 /******************************************************************************
678 * RegSetValueExA [ADVAPI32.169]
680 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
681 CONST BYTE
*data
, DWORD count
)
683 UNICODE_STRING nameW
;
688 if (count
&& is_string(type
))
690 /* if user forgot to count terminating null, add it (yes NT does this) */
691 if (data
[count
-1] && !data
[count
]) count
++;
694 if (is_string( type
)) /* need to convert to Unicode */
696 DWORD lenW
= MultiByteToWideChar( CP_ACP
, 0, data
, count
, NULL
, 0 );
697 if (!(dataW
= HeapAlloc( GetProcessHeap(), 0, lenW
*sizeof(WCHAR
) )))
698 return ERROR_OUTOFMEMORY
;
699 MultiByteToWideChar( CP_ACP
, 0, data
, count
, dataW
, lenW
);
700 count
= lenW
* sizeof(WCHAR
);
701 data
= (BYTE
*)dataW
;
704 RtlInitAnsiString( &nameA
, name
);
705 /* FIXME: should use Unicode buffer in TEB */
706 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
708 status
= NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
);
709 RtlFreeUnicodeString( &nameW
);
711 if (dataW
) HeapFree( GetProcessHeap(), 0, dataW
);
712 return RtlNtStatusToDosError( status
);
716 /******************************************************************************
717 * RegSetValueW [ADVAPI32.171]
719 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR name
, DWORD type
, LPCWSTR data
, DWORD count
)
724 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey
, debugstr_w(name
), type
, debugstr_w(data
), count
);
726 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
728 if (name
&& name
[0]) /* need to create the subkey */
730 if ((ret
= RegCreateKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
733 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
,
734 (strlenW( data
) + 1) * sizeof(WCHAR
) );
735 if (subkey
!= hkey
) RegCloseKey( subkey
);
740 /******************************************************************************
741 * RegSetValueA [ADVAPI32.168]
743 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
748 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey
, debugstr_a(name
), type
, debugstr_a(data
), count
);
750 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
752 if (name
&& name
[0]) /* need to create the subkey */
754 if ((ret
= RegCreateKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
756 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
, strlen(data
)+1 );
757 if (subkey
!= hkey
) RegCloseKey( subkey
);
763 /******************************************************************************
764 * RegQueryValueExW [ADVAPI32.158]
766 * Retrieves type and data for a specified name associated with an open key
769 * hkey [I] Handle of key to query
770 * name [I] Name of value to query
771 * reserved [I] Reserved - must be NULL
772 * type [O] Address of buffer for value type. If NULL, the type
774 * data [O] Address of data buffer. If NULL, the actual data is
776 * count [I/O] Address of data buffer size
779 * ERROR_SUCCESS: Success
780 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
781 * buffer is left untouched. The MS-documentation is wrong (js) !!!
783 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
784 LPBYTE data
, LPDWORD count
)
787 UNICODE_STRING name_str
;
789 char buffer
[256], *buf_ptr
= buffer
;
790 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
791 static const int info_size
= sizeof(*info
) - sizeof(info
->Data
);
793 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
794 hkey
, debugstr_w(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
796 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
798 RtlInitUnicodeString( &name_str
, name
);
800 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
801 else total_size
= info_size
;
803 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
804 buffer
, total_size
, &total_size
);
805 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
809 /* retry with a dynamically allocated buffer */
810 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
812 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
813 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
814 return ERROR_NOT_ENOUGH_MEMORY
;
815 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
816 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
817 buf_ptr
, total_size
, &total_size
);
822 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
823 /* if the type is REG_SZ and data is not 0-terminated
824 * and there is enough space in the buffer NT appends a \0 */
825 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
827 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
828 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
831 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
834 if (type
) *type
= info
->Type
;
835 if (count
) *count
= total_size
- info_size
;
838 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
839 return RtlNtStatusToDosError(status
);
843 /******************************************************************************
844 * RegQueryValueExA [ADVAPI32.157]
847 * the documentation is wrong: if the buffer is too small it remains untouched
849 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
850 LPBYTE data
, LPDWORD count
)
854 UNICODE_STRING nameW
;
856 char buffer
[256], *buf_ptr
= buffer
;
857 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
858 static const int info_size
= sizeof(*info
) - sizeof(info
->Data
);
860 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
861 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
863 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
865 RtlInitAnsiString( &nameA
, name
);
866 /* FIXME: should use Unicode buffer in TEB */
867 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
868 return RtlNtStatusToDosError(status
);
870 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
871 buffer
, sizeof(buffer
), &total_size
);
872 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
874 /* we need to fetch the contents for a string type even if not requested,
875 * because we need to compute the length of the ASCII string. */
876 if (data
|| is_string(info
->Type
))
878 /* retry with a dynamically allocated buffer */
879 while (status
== STATUS_BUFFER_OVERFLOW
)
881 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
882 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
884 status
= STATUS_NO_MEMORY
;
887 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
888 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
889 buf_ptr
, total_size
, &total_size
);
894 if (is_string(info
->Type
))
896 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info_size
),
897 (total_size
- info_size
) /sizeof(WCHAR
),
898 NULL
, 0, NULL
, NULL
);
901 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
904 WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info_size
),
905 (total_size
- info_size
) /sizeof(WCHAR
),
906 data
, len
, NULL
, NULL
);
907 /* if the type is REG_SZ and data is not 0-terminated
908 * and there is enough space in the buffer NT appends a \0 */
909 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
912 total_size
= len
+ info_size
;
916 if (total_size
- info_size
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
917 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
920 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
923 if (type
) *type
= info
->Type
;
924 if (count
) *count
= total_size
- info_size
;
927 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
928 RtlFreeUnicodeString( &nameW
);
929 return RtlNtStatusToDosError(status
);
933 /******************************************************************************
934 * RegQueryValueW [ADVAPI32.159]
936 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
941 TRACE("(%x,%s,%p,%ld)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
945 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
947 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
948 if (subkey
!= hkey
) RegCloseKey( subkey
);
949 if (ret
== ERROR_FILE_NOT_FOUND
)
951 /* return empty string if default value not found */
953 if (count
) *count
= 1;
960 /******************************************************************************
961 * RegQueryValueA [ADVAPI32.156]
963 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
968 TRACE("(%x,%s,%p,%ld)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
972 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
974 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
975 if (subkey
!= hkey
) RegCloseKey( subkey
);
976 if (ret
== ERROR_FILE_NOT_FOUND
)
978 /* return empty string if default value not found */
980 if (count
) *count
= 1;
987 /******************************************************************************
988 * RegEnumValueW [ADVAPI32.142]
991 * hkey [I] Handle to key to query
992 * index [I] Index of value to query
993 * value [O] Value string
994 * val_count [I/O] Size of value buffer (in wchars)
995 * reserved [I] Reserved
997 * data [O] Value data
998 * count [I/O] Size of data buffer (in bytes)
1001 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
1002 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1005 struct enum_key_value_request
*req
= get_req_buffer();
1007 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1008 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1010 /* NT only checks count, not val_count */
1011 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1016 if ((ret
= reg_server_call( REQ_ENUM_KEY_VALUE
)) != ERROR_SUCCESS
) return ret
;
1018 len
= strlenW( req
->name
) + 1;
1019 if (len
> *val_count
) return ERROR_MORE_DATA
;
1020 memcpy( value
, req
->name
, len
* sizeof(WCHAR
) );
1021 *val_count
= len
- 1;
1025 if (*count
< req
->len
) ret
= ERROR_MORE_DATA
;
1029 unsigned int max
= server_remaining( req
->data
);
1030 unsigned int pos
= 0;
1031 while (pos
< req
->len
)
1033 unsigned int len
= min( req
->len
- pos
, max
);
1034 memcpy( data
+ pos
, req
->data
, len
);
1035 if ((pos
+= len
) >= req
->len
) break;
1037 if ((ret
= reg_server_call( REQ_ENUM_KEY_VALUE
)) != ERROR_SUCCESS
) return ret
;
1040 /* if the type is REG_SZ and data is not 0-terminated
1041 * and there is enough space in the buffer NT appends a \0 */
1042 if (req
->len
&& is_string(req
->type
) &&
1043 (req
->len
< *count
) && ((WCHAR
*)data
)[req
->len
-1]) ((WCHAR
*)data
)[req
->len
] = 0;
1045 if (type
) *type
= req
->type
;
1046 if (count
) *count
= req
->len
;
1051 /******************************************************************************
1052 * RegEnumValueA [ADVAPI32.141]
1054 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1055 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1057 DWORD ret
, len
, total_len
;
1058 struct enum_key_value_request
*req
= get_req_buffer();
1060 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1061 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1063 /* NT only checks count, not val_count */
1064 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1069 if ((ret
= reg_server_call( REQ_ENUM_KEY_VALUE
)) != ERROR_SUCCESS
) return ret
;
1071 len
= strlenW( req
->name
) + 1;
1072 if (len
> *val_count
) return ERROR_MORE_DATA
;
1073 memcpyWtoA( value
, req
->name
, len
);
1074 *val_count
= len
- 1;
1076 total_len
= is_string( req
->type
) ? req
->len
/sizeof(WCHAR
) : req
->len
;
1080 if (*count
< total_len
) ret
= ERROR_MORE_DATA
;
1084 unsigned int max
= server_remaining( req
->data
);
1085 unsigned int pos
= 0;
1086 while (pos
< req
->len
)
1088 unsigned int len
= min( req
->len
- pos
, max
);
1089 if (is_string( req
->type
))
1090 memcpyWtoA( data
+ pos
/sizeof(WCHAR
), (WCHAR
*)req
->data
, len
/sizeof(WCHAR
) );
1092 memcpy( data
+ pos
, req
->data
, len
);
1093 if ((pos
+= len
) >= req
->len
) break;
1095 if ((ret
= reg_server_call( REQ_ENUM_KEY_VALUE
)) != ERROR_SUCCESS
) return ret
;
1098 /* if the type is REG_SZ and data is not 0-terminated
1099 * and there is enough space in the buffer NT appends a \0 */
1100 if (total_len
&& is_string(req
->type
) && (total_len
< *count
) && data
[total_len
-1])
1101 data
[total_len
] = 0;
1104 if (count
) *count
= total_len
;
1105 if (type
) *type
= req
->type
;
1111 /******************************************************************************
1112 * RegDeleteValueW [ADVAPI32.136]
1115 * hkey [I] handle to key
1116 * name [I] name of value to delete
1121 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
1123 UNICODE_STRING nameW
;
1124 RtlInitUnicodeString( &nameW
, name
);
1125 return RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
1129 /******************************************************************************
1130 * RegDeleteValueA [ADVAPI32.135]
1132 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
1134 UNICODE_STRING nameW
;
1138 RtlInitAnsiString( &nameA
, name
);
1139 /* FIXME: should use Unicode buffer in TEB */
1140 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1142 status
= NtDeleteValueKey( hkey
, &nameW
);
1143 RtlFreeUnicodeString( &nameW
);
1145 return RtlNtStatusToDosError( status
);
1149 /******************************************************************************
1150 * RegLoadKeyW [ADVAPI32.185]
1153 * hkey [I] Handle of open key
1154 * subkey [I] Address of name of subkey
1155 * filename [I] Address of filename for registry information
1157 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
1160 DWORD ret
, len
, err
= GetLastError();
1162 TRACE( "(%x,%s,%s)\n", hkey
, debugstr_w(subkey
), debugstr_w(filename
) );
1164 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1165 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1167 len
= strlenW( subkey
) * sizeof(WCHAR
);
1168 if (len
> MAX_PATH
*sizeof(WCHAR
)) return ERROR_INVALID_PARAMETER
;
1170 if ((file
= CreateFileW( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1171 FILE_ATTRIBUTE_NORMAL
, -1 )) == INVALID_HANDLE_VALUE
)
1173 ret
= GetLastError();
1179 struct load_registry_request
*req
= server_alloc_req( sizeof(*req
), len
);
1182 memcpy( server_data_ptr(req
), subkey
, len
);
1183 ret
= reg_server_call( REQ_LOAD_REGISTRY
);
1186 CloseHandle( file
);
1189 SetLastError( err
); /* restore the last error code */
1194 /******************************************************************************
1195 * RegLoadKeyA [ADVAPI32.184]
1197 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
1200 DWORD ret
, len
, err
= GetLastError();
1202 TRACE( "(%x,%s,%s)\n", hkey
, debugstr_a(subkey
), debugstr_a(filename
) );
1204 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1205 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1207 len
= MultiByteToWideChar( CP_ACP
, 0, subkey
, strlen(subkey
), NULL
, 0 ) * sizeof(WCHAR
);
1208 if (len
> MAX_PATH
*sizeof(WCHAR
)) return ERROR_INVALID_PARAMETER
;
1210 if ((file
= CreateFileA( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1211 FILE_ATTRIBUTE_NORMAL
, -1 )) == INVALID_HANDLE_VALUE
)
1213 ret
= GetLastError();
1219 struct load_registry_request
*req
= server_alloc_req( sizeof(*req
), len
);
1222 MultiByteToWideChar( CP_ACP
, 0, subkey
, strlen(subkey
),
1223 server_data_ptr(req
), len
/sizeof(WCHAR
) );
1224 ret
= reg_server_call( REQ_LOAD_REGISTRY
);
1227 CloseHandle( file
);
1230 SetLastError( err
); /* restore the last error code */
1235 /******************************************************************************
1236 * RegSaveKeyA [ADVAPI32.165]
1239 * hkey [I] Handle of key where save begins
1240 * lpFile [I] Address of filename to save to
1241 * sa [I] Address of security structure
1243 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
1251 TRACE( "(%x,%s,%p)\n", hkey
, debugstr_a(file
), sa
);
1253 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
1255 err
= GetLastError();
1256 GetFullPathNameA( file
, sizeof(buffer
), buffer
, &name
);
1259 sprintf( name
, "reg%04x.tmp", count
++ );
1260 handle
= CreateFileA( buffer
, GENERIC_WRITE
, 0, NULL
,
1261 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, -1 );
1262 if (handle
!= INVALID_HANDLE_VALUE
) break;
1263 if ((ret
= GetLastError()) != ERROR_ALREADY_EXISTS
) goto done
;
1265 /* Something gone haywire ? Please report if this happens abnormally */
1267 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
);
1272 struct save_registry_request
*req
= server_alloc_req( sizeof(*req
), 0 );
1275 ret
= reg_server_call( REQ_SAVE_REGISTRY
);
1279 CloseHandle( handle
);
1282 if (!MoveFileExA( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
1284 ERR( "Failed to move %s to %s\n", buffer
, file
);
1285 ret
= GetLastError();
1288 if (ret
) DeleteFileA( buffer
);
1291 SetLastError( err
); /* restore last error code */
1296 /******************************************************************************
1297 * RegSaveKeyW [ADVAPI32.166]
1299 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
1301 LPSTR fileA
= HEAP_strdupWtoA( GetProcessHeap(), 0, file
);
1302 DWORD ret
= RegSaveKeyA( hkey
, fileA
, sa
);
1303 if (fileA
) HeapFree( GetProcessHeap(), 0, fileA
);