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/unicode.h"
25 #include "debugtools.h"
27 DEFAULT_DEBUG_CHANNEL(reg
);
30 /* check if value type needs string conversion (Ansi<->Unicode) */
31 static inline int is_string( DWORD type
)
33 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
36 /* do a server call without setting the last error code */
37 static inline int reg_server_call( enum request req
)
39 unsigned int res
= server_call_noerr( req
);
40 if (res
) res
= RtlNtStatusToDosError(res
);
44 /******************************************************************************
45 * RegCreateKeyExW [ADVAPI32.131]
48 * hkey [I] Handle of an open key
49 * name [I] Address of subkey name
50 * reserved [I] Reserved - must be 0
51 * class [I] Address of class string
52 * options [I] Special options flag
53 * access [I] Desired security access
54 * sa [I] Address of key security structure
55 * retkey [O] Address of buffer for opened handle
56 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
59 * in case of failing retkey remains untouched
61 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
62 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
63 LPHKEY retkey
, LPDWORD dispos
)
65 OBJECT_ATTRIBUTES attr
;
66 UNICODE_STRING nameW
, classW
;
68 if (reserved
) return ERROR_INVALID_PARAMETER
;
69 if (!(access
& KEY_ALL_ACCESS
) || (access
& ~KEY_ALL_ACCESS
)) return ERROR_ACCESS_DENIED
;
71 attr
.Length
= sizeof(attr
);
72 attr
.RootDirectory
= hkey
;
73 attr
.ObjectName
= &nameW
;
75 attr
.SecurityDescriptor
= NULL
;
76 attr
.SecurityQualityOfService
= NULL
;
77 RtlInitUnicodeString( &nameW
, name
);
78 RtlInitUnicodeString( &classW
, class );
80 return RtlNtStatusToDosError( NtCreateKey( retkey
, access
, &attr
, 0,
81 &classW
, options
, dispos
) );
85 /******************************************************************************
86 * RegCreateKeyExA [ADVAPI32.130]
88 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
89 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
90 LPHKEY retkey
, LPDWORD dispos
)
92 OBJECT_ATTRIBUTES attr
;
93 UNICODE_STRING nameW
, classW
;
94 ANSI_STRING nameA
, classA
;
97 if (reserved
) return ERROR_INVALID_PARAMETER
;
98 if (!(access
& KEY_ALL_ACCESS
) || (access
& ~KEY_ALL_ACCESS
)) return ERROR_ACCESS_DENIED
;
100 attr
.Length
= sizeof(attr
);
101 attr
.RootDirectory
= hkey
;
102 attr
.ObjectName
= &nameW
;
104 attr
.SecurityDescriptor
= NULL
;
105 attr
.SecurityQualityOfService
= NULL
;
106 RtlInitAnsiString( &nameA
, name
);
107 RtlInitAnsiString( &classA
, class );
109 /* FIXME: should use Unicode buffer in TEB */
110 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
112 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
114 status
= NtCreateKey( retkey
, access
, &attr
, 0, &classW
, options
, dispos
);
115 RtlFreeUnicodeString( &classW
);
117 RtlFreeUnicodeString( &nameW
);
119 return RtlNtStatusToDosError( status
);
123 /******************************************************************************
124 * RegCreateKeyW [ADVAPI32.132]
126 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR name
, LPHKEY retkey
)
128 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
129 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
130 return RegCreateKeyExW( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
131 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
135 /******************************************************************************
136 * RegCreateKeyA [ADVAPI32.129]
138 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
140 return RegCreateKeyExA( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
141 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
146 /******************************************************************************
147 * RegOpenKeyExW [ADVAPI32.150]
149 * Opens the specified key
151 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
154 * hkey [I] Handle of open key
155 * name [I] Name of subkey to open
156 * reserved [I] Reserved - must be zero
157 * access [I] Security access mask
158 * retkey [O] Handle to open key
161 * Success: ERROR_SUCCESS
162 * Failure: Error code
165 * in case of failing is retkey = 0
167 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, REGSAM access
, LPHKEY retkey
)
169 OBJECT_ATTRIBUTES attr
;
170 UNICODE_STRING nameW
;
172 attr
.Length
= sizeof(attr
);
173 attr
.RootDirectory
= hkey
;
174 attr
.ObjectName
= &nameW
;
176 attr
.SecurityDescriptor
= NULL
;
177 attr
.SecurityQualityOfService
= NULL
;
178 RtlInitUnicodeString( &nameW
, name
);
179 return RtlNtStatusToDosError( NtOpenKey( retkey
, access
, &attr
) );
183 /******************************************************************************
184 * RegOpenKeyExA [ADVAPI32.149]
186 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, REGSAM access
, LPHKEY retkey
)
188 OBJECT_ATTRIBUTES attr
;
189 UNICODE_STRING nameW
;
193 attr
.Length
= sizeof(attr
);
194 attr
.RootDirectory
= hkey
;
195 attr
.ObjectName
= &nameW
;
197 attr
.SecurityDescriptor
= NULL
;
198 attr
.SecurityQualityOfService
= NULL
;
200 RtlInitAnsiString( &nameA
, name
);
201 /* FIXME: should use Unicode buffer in TEB */
202 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
204 status
= NtOpenKey( retkey
, access
, &attr
);
205 RtlFreeUnicodeString( &nameW
);
207 return RtlNtStatusToDosError( status
);
211 /******************************************************************************
212 * RegOpenKeyW [ADVAPI32.151]
215 * hkey [I] Handle of open key
216 * name [I] Address of name of subkey to open
217 * retkey [O] Handle to open key
220 * Success: ERROR_SUCCESS
221 * Failure: Error code
224 * in case of failing is retkey = 0
226 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, LPHKEY retkey
)
228 return RegOpenKeyExW( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
232 /******************************************************************************
233 * RegOpenKeyA [ADVAPI32.148]
235 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
237 return RegOpenKeyExA( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
241 /******************************************************************************
242 * RegOpenCurrentUser [ADVAPI32]
243 * FIXME: This function is supposed to retrieve a handle to the
244 * HKEY_CURRENT_USER for the user the current thread is impersonating.
245 * Since Wine does not currently allow threads to impersonate other users,
246 * this stub should work fine.
248 DWORD WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
250 return RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
255 /******************************************************************************
256 * RegEnumKeyExW [ADVAPI32.139]
259 * hkey [I] Handle to key to enumerate
260 * index [I] Index of subkey to enumerate
261 * name [O] Buffer for subkey name
262 * name_len [O] Size of subkey buffer
263 * reserved [I] Reserved
264 * class [O] Buffer for class string
265 * class_len [O] Size of class buffer
266 * ft [O] Time key last written to
268 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
269 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
272 char buffer
[256], *buf_ptr
= buffer
;
273 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
276 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
277 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
279 if (reserved
) return ERROR_INVALID_PARAMETER
;
281 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
282 buffer
, sizeof(buffer
), &total_size
);
284 while (status
== STATUS_BUFFER_OVERFLOW
)
286 /* retry with a dynamically allocated buffer */
287 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
288 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
289 return ERROR_NOT_ENOUGH_MEMORY
;
290 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
291 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
292 buf_ptr
, total_size
, &total_size
);
297 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
298 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
300 if (ft
) *ft
= info
->LastWriteTime
;
302 if (len
>= *name_len
|| (class_len
&& (cls_len
>= *class_len
)))
303 status
= STATUS_BUFFER_OVERFLOW
;
307 memcpy( name
, info
->Name
, info
->NameLength
);
311 *class_len
= cls_len
;
314 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
321 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
322 return RtlNtStatusToDosError( status
);
326 /******************************************************************************
327 * RegEnumKeyExA [ADVAPI32.138]
329 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
330 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
333 char buffer
[256], *buf_ptr
= buffer
;
334 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
337 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
338 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
340 if (reserved
) return ERROR_INVALID_PARAMETER
;
342 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
343 buffer
, sizeof(buffer
), &total_size
);
345 while (status
== STATUS_BUFFER_OVERFLOW
)
347 /* retry with a dynamically allocated buffer */
348 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
349 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
350 return ERROR_NOT_ENOUGH_MEMORY
;
351 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
352 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
353 buf_ptr
, total_size
, &total_size
);
358 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, info
->Name
, info
->NameLength
/sizeof(WCHAR
),
359 NULL
, 0, NULL
, NULL
);
360 DWORD cls_len
= WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
361 info
->ClassLength
/ sizeof(WCHAR
),
362 NULL
, 0, NULL
, NULL
);
364 if (ft
) *ft
= info
->LastWriteTime
;
366 if (len
>= *name_len
|| (class_len
&& (cls_len
>= *class_len
)))
367 status
= STATUS_BUFFER_OVERFLOW
;
371 WideCharToMultiByte( CP_ACP
, 0, info
->Name
, info
->NameLength
/sizeof(WCHAR
),
372 name
, len
, NULL
, NULL
);
376 *class_len
= cls_len
;
379 WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
380 info
->ClassLength
/ sizeof(WCHAR
),
381 class, cls_len
, NULL
, NULL
);
388 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
389 return RtlNtStatusToDosError( status
);
393 /******************************************************************************
394 * RegEnumKeyW [ADVAPI32.140]
396 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
398 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
402 /******************************************************************************
403 * RegEnumKeyA [ADVAPI32.137]
405 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
407 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
411 /******************************************************************************
412 * RegQueryInfoKeyW [ADVAPI32.153]
415 * hkey [I] Handle to key to query
416 * class [O] Buffer for class string
417 * class_len [O] Size of class string buffer
418 * reserved [I] Reserved
419 * subkeys [O] Buffer for number of subkeys
420 * max_subkey [O] Buffer for longest subkey name length
421 * max_class [O] Buffer for longest class string length
422 * values [O] Buffer for number of value entries
423 * max_value [O] Buffer for longest value name length
424 * max_data [O] Buffer for longest value data length
425 * security [O] Buffer for security descriptor length
426 * modif [O] Modification time
428 * - win95 allows class to be valid and class_len to be NULL
429 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
430 * - both allow class to be NULL and class_len to be NULL
431 * (it's hard to test validity, so test !NULL instead)
433 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
434 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
435 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
436 LPDWORD security
, FILETIME
*modif
)
439 char buffer
[256], *buf_ptr
= buffer
;
440 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
443 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
444 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
446 if (class && !class_len
&& !(GetVersion() & 0x80000000 /*NT*/))
447 return ERROR_INVALID_PARAMETER
;
449 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
450 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
454 /* retry with a dynamically allocated buffer */
455 while (status
== STATUS_BUFFER_OVERFLOW
)
457 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
458 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
459 return ERROR_NOT_ENOUGH_MEMORY
;
460 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
461 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
464 if (status
) goto done
;
466 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
468 status
= STATUS_BUFFER_OVERFLOW
;
472 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
473 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
476 else status
= STATUS_SUCCESS
;
478 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
479 if (subkeys
) *subkeys
= info
->SubKeys
;
480 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
481 if (max_class
) *max_class
= info
->MaxClassLen
;
482 if (values
) *values
= info
->Values
;
483 if (max_value
) *max_value
= info
->MaxValueNameLen
;
484 if (max_data
) *max_data
= info
->MaxValueDataLen
;
485 if (modif
) *modif
= info
->LastWriteTime
;
488 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
489 return RtlNtStatusToDosError( status
);
493 /******************************************************************************
494 * RegQueryInfoKeyA [ADVAPI32.152]
496 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
497 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
498 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
499 LPDWORD security
, FILETIME
*modif
)
502 char buffer
[256], *buf_ptr
= buffer
;
503 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
504 DWORD total_size
, len
;
506 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
507 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
509 if (class && !class_len
&& !(GetVersion() & 0x80000000 /*NT*/))
510 return ERROR_INVALID_PARAMETER
;
512 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
513 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
515 if (class || class_len
)
517 /* retry with a dynamically allocated buffer */
518 while (status
== STATUS_BUFFER_OVERFLOW
)
520 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
521 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
522 return ERROR_NOT_ENOUGH_MEMORY
;
523 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
524 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
527 if (status
) goto done
;
529 len
= WideCharToMultiByte( CP_ACP
, 0,
530 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
531 info
->ClassLength
/sizeof(WCHAR
),
532 NULL
, 0, NULL
, NULL
);
535 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
538 if (class && !status
)
540 WideCharToMultiByte( CP_ACP
, 0,
541 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
542 info
->ClassLength
/sizeof(WCHAR
),
543 class, len
, NULL
, NULL
);
547 else status
= STATUS_SUCCESS
;
549 if (subkeys
) *subkeys
= info
->SubKeys
;
550 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
551 if (max_class
) *max_class
= info
->MaxClassLen
;
552 if (values
) *values
= info
->Values
;
553 if (max_value
) *max_value
= info
->MaxValueNameLen
;
554 if (max_data
) *max_data
= info
->MaxValueDataLen
;
555 if (modif
) *modif
= info
->LastWriteTime
;
558 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
559 return RtlNtStatusToDosError( status
);
563 /******************************************************************************
564 * RegCloseKey [ADVAPI32.126]
566 * Releases the handle of the specified key
569 * hkey [I] Handle of key to close
572 * Success: ERROR_SUCCESS
573 * Failure: Error code
575 DWORD WINAPI
RegCloseKey( HKEY hkey
)
577 if (!hkey
|| hkey
>= 0x80000000) return ERROR_SUCCESS
;
578 return RtlNtStatusToDosError( NtClose( hkey
) );
582 /******************************************************************************
583 * RegDeleteKeyW [ADVAPI32.134]
586 * hkey [I] Handle to open key
587 * name [I] Name of subkey to delete
590 * Success: ERROR_SUCCESS
591 * Failure: Error code
593 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
598 if (!name
|| !*name
) return NtDeleteKey( hkey
);
599 if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, 0, &tmp
)))
601 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
608 /******************************************************************************
609 * RegDeleteKeyA [ADVAPI32.133]
611 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
616 if (!name
|| !*name
) return NtDeleteKey( hkey
);
617 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, 0, &tmp
)))
619 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
627 /******************************************************************************
628 * RegSetValueExW [ADVAPI32.170]
630 * Sets the data and type of a value under a register key
633 * hkey [I] Handle of key to set value for
634 * name [I] Name of value to set
635 * reserved [I] Reserved - must be zero
636 * type [I] Flag for value type
637 * data [I] Address of value data
638 * count [I] Size of value data
641 * Success: ERROR_SUCCESS
642 * Failure: Error code
645 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
646 * NT does definitely care (aj)
648 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
649 DWORD type
, CONST BYTE
*data
, DWORD count
)
651 UNICODE_STRING nameW
;
653 if (count
&& is_string(type
))
655 LPCWSTR str
= (LPCWSTR
)data
;
656 /* if user forgot to count terminating null, add it (yes NT does this) */
657 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
658 count
+= sizeof(WCHAR
);
661 RtlInitUnicodeString( &nameW
, name
);
662 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
666 /******************************************************************************
667 * RegSetValueExA [ADVAPI32.169]
669 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
670 CONST BYTE
*data
, DWORD count
)
672 UNICODE_STRING nameW
;
677 if (count
&& is_string(type
))
679 /* if user forgot to count terminating null, add it (yes NT does this) */
680 if (data
[count
-1] && !data
[count
]) count
++;
683 if (is_string( type
)) /* need to convert to Unicode */
685 DWORD lenW
= MultiByteToWideChar( CP_ACP
, 0, data
, count
, NULL
, 0 );
686 if (!(dataW
= HeapAlloc( GetProcessHeap(), 0, lenW
*sizeof(WCHAR
) )))
687 return ERROR_OUTOFMEMORY
;
688 MultiByteToWideChar( CP_ACP
, 0, data
, count
, dataW
, lenW
);
689 count
= lenW
* sizeof(WCHAR
);
690 data
= (BYTE
*)dataW
;
693 RtlInitAnsiString( &nameA
, name
);
694 /* FIXME: should use Unicode buffer in TEB */
695 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
697 status
= NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
);
698 RtlFreeUnicodeString( &nameW
);
700 if (dataW
) HeapFree( GetProcessHeap(), 0, dataW
);
701 return RtlNtStatusToDosError( status
);
705 /******************************************************************************
706 * RegSetValueW [ADVAPI32.171]
708 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR name
, DWORD type
, LPCWSTR data
, DWORD count
)
713 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey
, debugstr_w(name
), type
, debugstr_w(data
), count
);
715 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
717 if (name
&& name
[0]) /* need to create the subkey */
719 if ((ret
= RegCreateKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
722 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
,
723 (strlenW( data
) + 1) * sizeof(WCHAR
) );
724 if (subkey
!= hkey
) RegCloseKey( subkey
);
729 /******************************************************************************
730 * RegSetValueA [ADVAPI32.168]
732 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
737 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey
, debugstr_a(name
), type
, debugstr_a(data
), count
);
739 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
741 if (name
&& name
[0]) /* need to create the subkey */
743 if ((ret
= RegCreateKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
745 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
, strlen(data
)+1 );
746 if (subkey
!= hkey
) RegCloseKey( subkey
);
752 /******************************************************************************
753 * RegQueryValueExW [ADVAPI32.158]
755 * Retrieves type and data for a specified name associated with an open key
758 * hkey [I] Handle of key to query
759 * name [I] Name of value to query
760 * reserved [I] Reserved - must be NULL
761 * type [O] Address of buffer for value type. If NULL, the type
763 * data [O] Address of data buffer. If NULL, the actual data is
765 * count [I/O] Address of data buffer size
768 * ERROR_SUCCESS: Success
769 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
770 * buffer is left untouched. The MS-documentation is wrong (js) !!!
772 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
773 LPBYTE data
, LPDWORD count
)
776 UNICODE_STRING name_str
;
778 char buffer
[256], *buf_ptr
= buffer
;
779 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
780 static const int info_size
= sizeof(*info
) - sizeof(info
->Data
);
782 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
783 hkey
, debugstr_w(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
785 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
787 RtlInitUnicodeString( &name_str
, name
);
789 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
790 else total_size
= info_size
;
792 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
793 buffer
, total_size
, &total_size
);
794 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
798 /* retry with a dynamically allocated buffer */
799 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
801 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
802 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
803 return ERROR_NOT_ENOUGH_MEMORY
;
804 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
805 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
806 buf_ptr
, total_size
, &total_size
);
811 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
812 /* if the type is REG_SZ and data is not 0-terminated
813 * and there is enough space in the buffer NT appends a \0 */
814 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
816 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
817 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
820 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
822 else status
= STATUS_SUCCESS
;
824 if (type
) *type
= info
->Type
;
825 if (count
) *count
= total_size
- info_size
;
828 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
829 return RtlNtStatusToDosError(status
);
833 /******************************************************************************
834 * RegQueryValueExA [ADVAPI32.157]
837 * the documentation is wrong: if the buffer is too small it remains untouched
839 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
840 LPBYTE data
, LPDWORD count
)
844 UNICODE_STRING nameW
;
846 char buffer
[256], *buf_ptr
= buffer
;
847 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
848 static const int info_size
= sizeof(*info
) - sizeof(info
->Data
);
850 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
851 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
853 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
855 RtlInitAnsiString( &nameA
, name
);
856 /* FIXME: should use Unicode buffer in TEB */
857 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
858 return RtlNtStatusToDosError(status
);
860 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
861 buffer
, sizeof(buffer
), &total_size
);
862 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
864 /* we need to fetch the contents for a string type even if not requested,
865 * because we need to compute the length of the ASCII string. */
866 if (data
|| is_string(info
->Type
))
868 /* retry with a dynamically allocated buffer */
869 while (status
== STATUS_BUFFER_OVERFLOW
)
871 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
872 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
874 status
= STATUS_NO_MEMORY
;
877 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
878 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
879 buf_ptr
, total_size
, &total_size
);
882 if (status
) goto done
;
884 if (is_string(info
->Type
))
886 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info_size
),
887 (total_size
- info_size
) /sizeof(WCHAR
),
888 NULL
, 0, NULL
, NULL
);
891 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
894 WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info_size
),
895 (total_size
- info_size
) /sizeof(WCHAR
),
896 data
, len
, NULL
, NULL
);
897 /* if the type is REG_SZ and data is not 0-terminated
898 * and there is enough space in the buffer NT appends a \0 */
899 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
902 total_size
= len
+ info_size
;
906 if (total_size
- info_size
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
907 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
910 else status
= STATUS_SUCCESS
;
912 if (type
) *type
= info
->Type
;
913 if (count
) *count
= total_size
- info_size
;
916 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
917 RtlFreeUnicodeString( &nameW
);
918 return RtlNtStatusToDosError(status
);
922 /******************************************************************************
923 * RegQueryValueW [ADVAPI32.159]
925 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
930 TRACE("(%x,%s,%p,%ld)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
934 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
936 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
937 if (subkey
!= hkey
) RegCloseKey( subkey
);
938 if (ret
== ERROR_FILE_NOT_FOUND
)
940 /* return empty string if default value not found */
942 if (count
) *count
= 1;
949 /******************************************************************************
950 * RegQueryValueA [ADVAPI32.156]
952 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
957 TRACE("(%x,%s,%p,%ld)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
961 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
963 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
964 if (subkey
!= hkey
) RegCloseKey( subkey
);
965 if (ret
== ERROR_FILE_NOT_FOUND
)
967 /* return empty string if default value not found */
969 if (count
) *count
= 1;
976 /******************************************************************************
977 * RegEnumValueW [ADVAPI32.142]
980 * hkey [I] Handle to key to query
981 * index [I] Index of value to query
982 * value [O] Value string
983 * val_count [I/O] Size of value buffer (in wchars)
984 * reserved [I] Reserved
986 * data [O] Value data
987 * count [I/O] Size of data buffer (in bytes)
990 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
991 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
995 char buffer
[256], *buf_ptr
= buffer
;
996 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
997 static const int info_size
= sizeof(*info
) - sizeof(info
->Name
);
999 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1000 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1002 /* NT only checks count, not val_count */
1003 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1005 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1006 if (data
) total_size
+= *count
;
1007 total_size
= min( sizeof(buffer
), total_size
);
1009 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1010 buffer
, total_size
, &total_size
);
1011 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1015 /* retry with a dynamically allocated buffer */
1016 while (status
== STATUS_BUFFER_OVERFLOW
)
1018 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1019 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1020 return ERROR_NOT_ENOUGH_MEMORY
;
1021 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1022 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1023 buf_ptr
, total_size
, &total_size
);
1026 if (status
) goto done
;
1030 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
1032 status
= STATUS_BUFFER_OVERFLOW
;
1035 memcpy( value
, info
->Name
, info
->NameLength
);
1036 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
1037 value
[*val_count
] = 0;
1042 if (total_size
- info
->DataOffset
> *count
)
1044 status
= STATUS_BUFFER_OVERFLOW
;
1047 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1048 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1050 /* if the type is REG_SZ and data is not 0-terminated
1051 * and there is enough space in the buffer NT appends a \0 */
1052 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
1053 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1057 else status
= STATUS_SUCCESS
;
1059 if (type
) *type
= info
->Type
;
1060 if (count
) *count
= info
->DataLength
;
1063 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1064 return RtlNtStatusToDosError(status
);
1068 /******************************************************************************
1069 * RegEnumValueA [ADVAPI32.141]
1071 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1072 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1076 char buffer
[256], *buf_ptr
= buffer
;
1077 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1078 static const int info_size
= sizeof(*info
) - sizeof(info
->Name
);
1080 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1081 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1083 /* NT only checks count, not val_count */
1084 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1086 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1087 if (data
) total_size
+= *count
;
1088 total_size
= min( sizeof(buffer
), total_size
);
1090 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1091 buffer
, total_size
, &total_size
);
1092 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1094 /* we need to fetch the contents for a string type even if not requested,
1095 * because we need to compute the length of the ASCII string. */
1096 if (value
|| data
|| is_string(info
->Type
))
1098 /* retry with a dynamically allocated buffer */
1099 while (status
== STATUS_BUFFER_OVERFLOW
)
1101 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1102 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1103 return ERROR_NOT_ENOUGH_MEMORY
;
1104 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1105 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1106 buf_ptr
, total_size
, &total_size
);
1109 if (status
) goto done
;
1113 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, info
->Name
, info
->NameLength
/sizeof(WCHAR
),
1114 NULL
, 0, NULL
, NULL
);
1115 if (len
>= *val_count
)
1117 status
= STATUS_BUFFER_OVERFLOW
;
1120 WideCharToMultiByte( CP_ACP
, 0, info
->Name
, info
->NameLength
/sizeof(WCHAR
),
1121 value
, len
, NULL
, NULL
);
1126 if (is_string(info
->Type
))
1128 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1129 (total_size
- info
->DataOffset
) / sizeof(WCHAR
),
1130 NULL
, 0, NULL
, NULL
);
1135 status
= STATUS_BUFFER_OVERFLOW
;
1138 WideCharToMultiByte( CP_ACP
, 0, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1139 (total_size
- info
->DataOffset
) / sizeof(WCHAR
),
1140 data
, len
, NULL
, NULL
);
1141 /* if the type is REG_SZ and data is not 0-terminated
1142 * and there is enough space in the buffer NT appends a \0 */
1143 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1145 info
->DataLength
= len
;
1149 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1150 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1153 else status
= STATUS_SUCCESS
;
1155 if (type
) *type
= info
->Type
;
1156 if (count
) *count
= info
->DataLength
;
1159 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1160 return RtlNtStatusToDosError(status
);
1165 /******************************************************************************
1166 * RegDeleteValueW [ADVAPI32.136]
1169 * hkey [I] handle to key
1170 * name [I] name of value to delete
1175 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
1177 UNICODE_STRING nameW
;
1178 RtlInitUnicodeString( &nameW
, name
);
1179 return RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
1183 /******************************************************************************
1184 * RegDeleteValueA [ADVAPI32.135]
1186 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
1188 UNICODE_STRING nameW
;
1192 RtlInitAnsiString( &nameA
, name
);
1193 /* FIXME: should use Unicode buffer in TEB */
1194 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1196 status
= NtDeleteValueKey( hkey
, &nameW
);
1197 RtlFreeUnicodeString( &nameW
);
1199 return RtlNtStatusToDosError( status
);
1203 /******************************************************************************
1204 * RegLoadKeyW [ADVAPI32.185]
1207 * hkey [I] Handle of open key
1208 * subkey [I] Address of name of subkey
1209 * filename [I] Address of filename for registry information
1211 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
1214 DWORD ret
, len
, err
= GetLastError();
1216 TRACE( "(%x,%s,%s)\n", hkey
, debugstr_w(subkey
), debugstr_w(filename
) );
1218 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1219 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1221 len
= strlenW( subkey
) * sizeof(WCHAR
);
1222 if (len
> MAX_PATH
*sizeof(WCHAR
)) return ERROR_INVALID_PARAMETER
;
1224 if ((file
= CreateFileW( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1225 FILE_ATTRIBUTE_NORMAL
, 0 )) == INVALID_HANDLE_VALUE
)
1227 ret
= GetLastError();
1233 struct load_registry_request
*req
= server_alloc_req( sizeof(*req
), len
);
1236 memcpy( server_data_ptr(req
), subkey
, len
);
1237 ret
= reg_server_call( REQ_LOAD_REGISTRY
);
1240 CloseHandle( file
);
1243 SetLastError( err
); /* restore the last error code */
1248 /******************************************************************************
1249 * RegLoadKeyA [ADVAPI32.184]
1251 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
1254 DWORD ret
, len
, err
= GetLastError();
1256 TRACE( "(%x,%s,%s)\n", hkey
, debugstr_a(subkey
), debugstr_a(filename
) );
1258 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1259 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1261 len
= MultiByteToWideChar( CP_ACP
, 0, subkey
, strlen(subkey
), NULL
, 0 ) * sizeof(WCHAR
);
1262 if (len
> MAX_PATH
*sizeof(WCHAR
)) return ERROR_INVALID_PARAMETER
;
1264 if ((file
= CreateFileA( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1265 FILE_ATTRIBUTE_NORMAL
, 0 )) == INVALID_HANDLE_VALUE
)
1267 ret
= GetLastError();
1273 struct load_registry_request
*req
= server_alloc_req( sizeof(*req
), len
);
1276 MultiByteToWideChar( CP_ACP
, 0, subkey
, strlen(subkey
),
1277 server_data_ptr(req
), len
/sizeof(WCHAR
) );
1278 ret
= reg_server_call( REQ_LOAD_REGISTRY
);
1281 CloseHandle( file
);
1284 SetLastError( err
); /* restore the last error code */
1289 /******************************************************************************
1290 * RegSaveKeyA [ADVAPI32.165]
1293 * hkey [I] Handle of key where save begins
1294 * lpFile [I] Address of filename to save to
1295 * sa [I] Address of security structure
1297 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
1305 TRACE( "(%x,%s,%p)\n", hkey
, debugstr_a(file
), sa
);
1307 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
1309 err
= GetLastError();
1310 GetFullPathNameA( file
, sizeof(buffer
), buffer
, &name
);
1313 sprintf( name
, "reg%04x.tmp", count
++ );
1314 handle
= CreateFileA( buffer
, GENERIC_WRITE
, 0, NULL
,
1315 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
1316 if (handle
!= INVALID_HANDLE_VALUE
) break;
1317 if ((ret
= GetLastError()) != ERROR_ALREADY_EXISTS
) goto done
;
1319 /* Something gone haywire ? Please report if this happens abnormally */
1321 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
);
1326 struct save_registry_request
*req
= server_alloc_req( sizeof(*req
), 0 );
1329 ret
= reg_server_call( REQ_SAVE_REGISTRY
);
1333 CloseHandle( handle
);
1336 if (!MoveFileExA( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
1338 ERR( "Failed to move %s to %s\n", buffer
, file
);
1339 ret
= GetLastError();
1342 if (ret
) DeleteFileA( buffer
);
1345 SetLastError( err
); /* restore last error code */
1350 /******************************************************************************
1351 * RegSaveKeyW [ADVAPI32.166]
1353 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
1355 LPSTR fileA
= HEAP_strdupWtoA( GetProcessHeap(), 0, file
);
1356 DWORD ret
= RegSaveKeyA( hkey
, fileA
, sa
);
1357 if (fileA
) HeapFree( GetProcessHeap(), 0, fileA
);
1362 /******************************************************************************
1363 * RegRestoreKeyW [ADVAPI32.164]
1366 * hkey [I] Handle of key where restore begins
1367 * lpFile [I] Address of filename containing saved tree
1368 * dwFlags [I] Optional flags
1370 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1372 TRACE("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1374 /* It seems to do this check before the hkey check */
1375 if (!lpFile
|| !*lpFile
)
1376 return ERROR_INVALID_PARAMETER
;
1378 FIXME("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1380 /* Check for file existence */
1382 return ERROR_SUCCESS
;
1386 /******************************************************************************
1387 * RegRestoreKeyA [ADVAPI32.163]
1389 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1391 LPWSTR lpFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile
);
1392 LONG ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1393 HeapFree( GetProcessHeap(), 0, lpFileW
);
1398 /******************************************************************************
1399 * RegUnLoadKeyW [ADVAPI32.173]
1402 * hkey [I] Handle of open key
1403 * lpSubKey [I] Address of name of subkey to unload
1405 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1407 FIXME("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1408 return ERROR_SUCCESS
;
1412 /******************************************************************************
1413 * RegUnLoadKeyA [ADVAPI32.172]
1415 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1417 LPWSTR lpSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey
);
1418 LONG ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
1419 if(lpSubKeyW
) HeapFree( GetProcessHeap(), 0, lpSubKeyW
);
1424 /******************************************************************************
1425 * RegReplaceKeyW [ADVAPI32.162]
1428 * hkey [I] Handle of open key
1429 * lpSubKey [I] Address of name of subkey
1430 * lpNewFile [I] Address of filename for file with new data
1431 * lpOldFile [I] Address of filename for backup file
1433 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1436 FIXME("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1437 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1438 return ERROR_SUCCESS
;
1442 /******************************************************************************
1443 * RegReplaceKeyA [ADVAPI32.161]
1445 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1448 LPWSTR lpSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey
);
1449 LPWSTR lpNewFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile
);
1450 LPWSTR lpOldFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile
);
1451 LONG ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
1452 HeapFree( GetProcessHeap(), 0, lpOldFileW
);
1453 HeapFree( GetProcessHeap(), 0, lpNewFileW
);
1454 HeapFree( GetProcessHeap(), 0, lpSubKeyW
);
1459 /******************************************************************************
1460 * RegSetKeySecurity [ADVAPI32.167]
1463 * hkey [I] Open handle of key to set
1464 * SecurityInfo [I] Descriptor contents
1465 * pSecurityDesc [I] Address of descriptor for key
1467 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1468 PSECURITY_DESCRIPTOR pSecurityDesc
)
1470 TRACE("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1472 /* It seems to perform this check before the hkey check */
1473 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1474 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1475 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1476 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1479 return ERROR_INVALID_PARAMETER
;
1482 return ERROR_INVALID_PARAMETER
;
1484 FIXME(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1486 return ERROR_SUCCESS
;
1490 /******************************************************************************
1491 * RegGetKeySecurity [ADVAPI32.144]
1492 * Retrieves a copy of security descriptor protecting the registry key
1495 * hkey [I] Open handle of key to set
1496 * SecurityInformation [I] Descriptor contents
1497 * pSecurityDescriptor [O] Address of descriptor for key
1498 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1501 * Success: ERROR_SUCCESS
1502 * Failure: Error code
1504 LONG WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
1505 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1506 LPDWORD lpcbSecurityDescriptor
)
1508 TRACE("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1509 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1511 /* FIXME: Check for valid SecurityInformation values */
1513 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1514 return ERROR_INSUFFICIENT_BUFFER
;
1516 FIXME("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1517 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1519 return ERROR_SUCCESS
;
1523 /******************************************************************************
1524 * RegFlushKey [ADVAPI32.143]
1525 * Immediately writes key to registry.
1526 * Only returns after data has been written to disk.
1528 * FIXME: does it really wait until data is written ?
1531 * hkey [I] Handle of key to write
1534 * Success: ERROR_SUCCESS
1535 * Failure: Error code
1537 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1539 FIXME( "(%x): stub\n", hkey
);
1540 return ERROR_SUCCESS
;
1544 /******************************************************************************
1545 * RegConnectRegistryW [ADVAPI32.128]
1548 * lpMachineName [I] Address of name of remote computer
1549 * hHey [I] Predefined registry handle
1550 * phkResult [I] Address of buffer for remote registry handle
1552 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1555 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1557 if (!lpMachineName
|| !*lpMachineName
) {
1558 /* Use the local machine name */
1559 return RegOpenKeyA( hKey
, "", phkResult
);
1562 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1563 return ERROR_BAD_NETPATH
;
1567 /******************************************************************************
1568 * RegConnectRegistryA [ADVAPI32.127]
1570 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
1572 LPWSTR machineW
= HEAP_strdupAtoW( GetProcessHeap(), 0, machine
);
1573 DWORD ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
1574 HeapFree( GetProcessHeap(), 0, machineW
);
1579 /******************************************************************************
1580 * RegNotifyChangeKeyValue [ADVAPI32.???]
1583 * hkey [I] Handle of key to watch
1584 * fWatchSubTree [I] Flag for subkey notification
1585 * fdwNotifyFilter [I] Changes to be reported
1586 * hEvent [I] Handle of signaled event
1587 * fAsync [I] Flag for asynchronous reporting
1589 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1590 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1593 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1595 return ERROR_SUCCESS
;