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.
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
36 #include "wine/unicode.h"
38 #include "wine/server.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
44 /* check if value type needs string conversion (Ansi<->Unicode) */
45 inline static int is_string( DWORD type
)
47 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
50 /* check if current version is NT or Win95 */
51 inline static int is_version_nt(void)
53 return !(GetVersion() & 0x80000000);
56 /* allowed bits for access mask */
57 #define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
59 /******************************************************************************
60 * RegCreateKeyExW [ADVAPI32.@]
63 * hkey [I] Handle of an open key
64 * name [I] Address of subkey name
65 * reserved [I] Reserved - must be 0
66 * class [I] Address of class string
67 * options [I] Special options flag
68 * access [I] Desired security access
69 * sa [I] Address of key security structure
70 * retkey [O] Address of buffer for opened handle
71 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
74 * in case of failing retkey remains untouched
76 * FIXME MAXIMUM_ALLOWED in access mask not supported by server
78 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
79 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
80 LPHKEY retkey
, LPDWORD dispos
)
82 OBJECT_ATTRIBUTES attr
;
83 UNICODE_STRING nameW
, classW
;
85 if (reserved
) return ERROR_INVALID_PARAMETER
;
86 if (!(access
& KEY_ACCESS_MASK
) || (access
& ~KEY_ACCESS_MASK
)) return ERROR_ACCESS_DENIED
;
88 attr
.Length
= sizeof(attr
);
89 attr
.RootDirectory
= hkey
;
90 attr
.ObjectName
= &nameW
;
92 attr
.SecurityDescriptor
= NULL
;
93 attr
.SecurityQualityOfService
= NULL
;
94 RtlInitUnicodeString( &nameW
, name
);
95 RtlInitUnicodeString( &classW
, class );
97 return RtlNtStatusToDosError( NtCreateKey( retkey
, access
, &attr
, 0,
98 &classW
, options
, dispos
) );
102 /******************************************************************************
103 * RegCreateKeyExA [ADVAPI32.@]
105 * FIXME MAXIMUM_ALLOWED in access mask not supported by server
107 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
108 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
109 LPHKEY retkey
, LPDWORD dispos
)
111 OBJECT_ATTRIBUTES attr
;
112 UNICODE_STRING classW
;
113 ANSI_STRING nameA
, classA
;
116 if (reserved
) return ERROR_INVALID_PARAMETER
;
117 if (!is_version_nt()) access
= KEY_ALL_ACCESS
; /* Win95 ignores the access mask */
118 else if (!(access
& KEY_ACCESS_MASK
) || (access
& ~KEY_ACCESS_MASK
)) return ERROR_ACCESS_DENIED
;
120 attr
.Length
= sizeof(attr
);
121 attr
.RootDirectory
= hkey
;
122 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
124 attr
.SecurityDescriptor
= NULL
;
125 attr
.SecurityQualityOfService
= NULL
;
126 RtlInitAnsiString( &nameA
, name
);
127 RtlInitAnsiString( &classA
, class );
129 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
132 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
134 status
= NtCreateKey( retkey
, access
, &attr
, 0, &classW
, options
, dispos
);
135 RtlFreeUnicodeString( &classW
);
138 return RtlNtStatusToDosError( status
);
142 /******************************************************************************
143 * RegCreateKeyW [ADVAPI32.@]
145 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR name
, LPHKEY retkey
)
147 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
148 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
149 return RegCreateKeyExW( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
150 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
154 /******************************************************************************
155 * RegCreateKeyA [ADVAPI32.@]
157 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
159 return RegCreateKeyExA( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
160 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
165 /******************************************************************************
166 * RegOpenKeyExW [ADVAPI32.@]
168 * Opens the specified key
170 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
173 * hkey [I] Handle of open key
174 * name [I] Name of subkey to open
175 * reserved [I] Reserved - must be zero
176 * access [I] Security access mask
177 * retkey [O] Handle to open key
180 * Success: ERROR_SUCCESS
181 * Failure: Error code
184 * in case of failing is retkey = 0
186 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, REGSAM access
, LPHKEY retkey
)
188 OBJECT_ATTRIBUTES attr
;
189 UNICODE_STRING nameW
;
191 attr
.Length
= sizeof(attr
);
192 attr
.RootDirectory
= hkey
;
193 attr
.ObjectName
= &nameW
;
195 attr
.SecurityDescriptor
= NULL
;
196 attr
.SecurityQualityOfService
= NULL
;
197 RtlInitUnicodeString( &nameW
, name
);
198 return RtlNtStatusToDosError( NtOpenKey( retkey
, access
, &attr
) );
202 /******************************************************************************
203 * RegOpenKeyExA [ADVAPI32.@]
205 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, REGSAM access
, LPHKEY retkey
)
207 OBJECT_ATTRIBUTES attr
;
211 if (!is_version_nt()) access
= KEY_ALL_ACCESS
; /* Win95 ignores the access mask */
213 attr
.Length
= sizeof(attr
);
214 attr
.RootDirectory
= hkey
;
215 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
217 attr
.SecurityDescriptor
= NULL
;
218 attr
.SecurityQualityOfService
= NULL
;
220 RtlInitAnsiString( &nameA
, name
);
221 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
224 status
= NtOpenKey( retkey
, access
, &attr
);
226 return RtlNtStatusToDosError( status
);
230 /******************************************************************************
231 * RegOpenKeyW [ADVAPI32.@]
234 * hkey [I] Handle of open key
235 * name [I] Address of name of subkey to open
236 * retkey [O] Handle to open key
239 * Success: ERROR_SUCCESS
240 * Failure: Error code
243 * in case of failing is retkey = 0
245 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, LPHKEY retkey
)
247 return RegOpenKeyExW( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
251 /******************************************************************************
252 * RegOpenKeyA [ADVAPI32.@]
254 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
256 return RegOpenKeyExA( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
260 /******************************************************************************
261 * RegOpenCurrentUser [ADVAPI32.@]
262 * FIXME: This function is supposed to retrieve a handle to the
263 * HKEY_CURRENT_USER for the user the current thread is impersonating.
264 * Since Wine does not currently allow threads to impersonate other users,
265 * this stub should work fine.
267 DWORD WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
269 return RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
274 /******************************************************************************
275 * RegEnumKeyExW [ADVAPI32.@]
278 * hkey [I] Handle to key to enumerate
279 * index [I] Index of subkey to enumerate
280 * name [O] Buffer for subkey name
281 * name_len [O] Size of subkey buffer
282 * reserved [I] Reserved
283 * class [O] Buffer for class string
284 * class_len [O] Size of class buffer
285 * ft [O] Time key last written to
287 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
288 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
291 char buffer
[256], *buf_ptr
= buffer
;
292 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
295 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
296 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
298 if (reserved
) return ERROR_INVALID_PARAMETER
;
300 if (!hkey
) return ERROR_INVALID_HANDLE
;
302 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
303 buffer
, sizeof(buffer
), &total_size
);
305 while (status
== STATUS_BUFFER_OVERFLOW
)
307 /* retry with a dynamically allocated buffer */
308 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
309 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
310 return ERROR_NOT_ENOUGH_MEMORY
;
311 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
312 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
313 buf_ptr
, total_size
, &total_size
);
318 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
319 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
321 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
323 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
324 status
= STATUS_BUFFER_OVERFLOW
;
328 memcpy( name
, info
->Name
, info
->NameLength
);
332 *class_len
= cls_len
;
335 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
342 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
343 return RtlNtStatusToDosError( status
);
347 /******************************************************************************
348 * RegEnumKeyExA [ADVAPI32.@]
350 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
351 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
354 char buffer
[256], *buf_ptr
= buffer
;
355 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
358 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
359 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
361 if (reserved
) return ERROR_INVALID_PARAMETER
;
363 if (!hkey
) return ERROR_INVALID_HANDLE
;
365 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
366 buffer
, sizeof(buffer
), &total_size
);
368 while (status
== STATUS_BUFFER_OVERFLOW
)
370 /* retry with a dynamically allocated buffer */
371 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
372 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
373 return ERROR_NOT_ENOUGH_MEMORY
;
374 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
375 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
376 buf_ptr
, total_size
, &total_size
);
383 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
384 RtlUnicodeToMultiByteSize( &cls_len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
386 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
388 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
389 status
= STATUS_BUFFER_OVERFLOW
;
393 RtlUnicodeToMultiByteN( name
, len
, NULL
, info
->Name
, info
->NameLength
);
397 *class_len
= cls_len
;
400 RtlUnicodeToMultiByteN( class, cls_len
, NULL
,
401 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
409 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
410 return RtlNtStatusToDosError( status
);
414 /******************************************************************************
415 * RegEnumKeyW [ADVAPI32.@]
417 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
419 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
423 /******************************************************************************
424 * RegEnumKeyA [ADVAPI32.@]
426 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
428 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
432 /******************************************************************************
433 * RegQueryInfoKeyW [ADVAPI32.@]
436 * hkey [I] Handle to key to query
437 * class [O] Buffer for class string
438 * class_len [O] Size of class string buffer
439 * reserved [I] Reserved
440 * subkeys [O] Buffer for number of subkeys
441 * max_subkey [O] Buffer for longest subkey name length
442 * max_class [O] Buffer for longest class string length
443 * values [O] Buffer for number of value entries
444 * max_value [O] Buffer for longest value name length
445 * max_data [O] Buffer for longest value data length
446 * security [O] Buffer for security descriptor length
447 * modif [O] Modification time
449 * - win95 allows class to be valid and class_len to be NULL
450 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
451 * - both allow class to be NULL and class_len to be NULL
452 * (it's hard to test validity, so test !NULL instead)
454 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
455 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
456 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
457 LPDWORD security
, FILETIME
*modif
)
460 char buffer
[256], *buf_ptr
= buffer
;
461 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
464 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
465 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
467 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
469 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
470 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
474 /* retry with a dynamically allocated buffer */
475 while (status
== STATUS_BUFFER_OVERFLOW
)
477 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
478 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
479 return ERROR_NOT_ENOUGH_MEMORY
;
480 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
481 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
484 if (status
) goto done
;
486 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
488 status
= STATUS_BUFFER_OVERFLOW
;
492 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
493 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
496 else status
= STATUS_SUCCESS
;
498 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
499 if (subkeys
) *subkeys
= info
->SubKeys
;
500 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
501 if (max_class
) *max_class
= info
->MaxClassLen
;
502 if (values
) *values
= info
->Values
;
503 if (max_value
) *max_value
= info
->MaxValueNameLen
;
504 if (max_data
) *max_data
= info
->MaxValueDataLen
;
505 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
508 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
509 return RtlNtStatusToDosError( status
);
513 /******************************************************************************
514 * RegQueryInfoKeyA [ADVAPI32.@]
516 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
517 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
518 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
519 LPDWORD security
, FILETIME
*modif
)
522 char buffer
[256], *buf_ptr
= buffer
;
523 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
524 DWORD total_size
, len
;
526 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
527 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
529 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
531 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
532 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
534 if (class || class_len
)
536 /* retry with a dynamically allocated buffer */
537 while (status
== STATUS_BUFFER_OVERFLOW
)
539 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
540 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
541 return ERROR_NOT_ENOUGH_MEMORY
;
542 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
543 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
546 if (status
) goto done
;
548 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
), info
->ClassLength
);
551 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
554 if (class && !status
)
556 RtlUnicodeToMultiByteN( class, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
561 else status
= STATUS_SUCCESS
;
563 if (subkeys
) *subkeys
= info
->SubKeys
;
564 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
565 if (max_class
) *max_class
= info
->MaxClassLen
;
566 if (values
) *values
= info
->Values
;
567 if (max_value
) *max_value
= info
->MaxValueNameLen
;
568 if (max_data
) *max_data
= info
->MaxValueDataLen
;
569 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
572 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
573 return RtlNtStatusToDosError( status
);
577 /******************************************************************************
578 * RegCloseKey [ADVAPI32.@]
580 * Releases the handle of the specified key
583 * hkey [I] Handle of key to close
586 * Success: ERROR_SUCCESS
587 * Failure: Error code
589 DWORD WINAPI
RegCloseKey( HKEY hkey
)
591 if (!hkey
|| hkey
>= 0x80000000) return ERROR_SUCCESS
;
592 return RtlNtStatusToDosError( NtClose( hkey
) );
596 /******************************************************************************
597 * RegDeleteKeyW [ADVAPI32.@]
600 * hkey [I] Handle to open key
601 * name [I] Name of subkey to delete
604 * Success: ERROR_SUCCESS
605 * Failure: Error code
607 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
614 ret
= RtlNtStatusToDosError( NtDeleteKey( hkey
) );
616 else if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, 0, &tmp
)))
618 if (!is_version_nt()) /* win95 does recursive key deletes */
620 WCHAR name
[MAX_PATH
];
622 while(!RegEnumKeyW(tmp
, 0, name
, sizeof name
))
624 if(RegDeleteKeyW(tmp
, name
)) /* recurse */
628 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
631 TRACE("%s ret=%08lx\n", debugstr_w(name
), ret
);
636 /******************************************************************************
637 * RegDeleteKeyA [ADVAPI32.@]
639 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
646 ret
= RtlNtStatusToDosError( NtDeleteKey( hkey
) );
648 else if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, KEY_ALL_ACCESS
, &tmp
)))
650 if (!is_version_nt()) /* win95 does recursive key deletes */
654 while(!RegEnumKeyA(tmp
, 0, name
, sizeof name
))
656 if(RegDeleteKeyA(tmp
, name
)) /* recurse */
660 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
663 TRACE("%s ret=%08lx\n", debugstr_a(name
), ret
);
669 /******************************************************************************
670 * RegSetValueExW [ADVAPI32.@]
672 * Sets the data and type of a value under a register key
675 * hkey [I] Handle of key to set value for
676 * name [I] Name of value to set
677 * reserved [I] Reserved - must be zero
678 * type [I] Flag for value type
679 * data [I] Address of value data
680 * count [I] Size of value data
683 * Success: ERROR_SUCCESS
684 * Failure: Error code
687 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
688 * NT does definitely care (aj)
690 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
691 DWORD type
, CONST BYTE
*data
, DWORD count
)
693 UNICODE_STRING nameW
;
695 if (!is_version_nt()) /* win95 */
697 if (type
== REG_SZ
) count
= (strlenW( (WCHAR
*)data
) + 1) * sizeof(WCHAR
);
699 else if (count
&& is_string(type
))
701 LPCWSTR str
= (LPCWSTR
)data
;
702 /* if user forgot to count terminating null, add it (yes NT does this) */
703 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
704 count
+= sizeof(WCHAR
);
707 RtlInitUnicodeString( &nameW
, name
);
708 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
712 /******************************************************************************
713 * RegSetValueExA [ADVAPI32.@]
715 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
716 CONST BYTE
*data
, DWORD count
)
722 if (!is_version_nt()) /* win95 */
724 if (type
== REG_SZ
) count
= strlen(data
) + 1;
726 else if (count
&& is_string(type
))
728 /* if user forgot to count terminating null, add it (yes NT does this) */
729 if (data
[count
-1] && !data
[count
]) count
++;
732 if (is_string( type
)) /* need to convert to Unicode */
735 RtlMultiByteToUnicodeSize( &lenW
, data
, count
);
736 if (!(dataW
= HeapAlloc( GetProcessHeap(), 0, lenW
))) return ERROR_OUTOFMEMORY
;
737 RtlMultiByteToUnicodeN( dataW
, lenW
, NULL
, data
, count
);
739 data
= (BYTE
*)dataW
;
742 RtlInitAnsiString( &nameA
, name
);
743 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
746 status
= NtSetValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
, 0, type
, data
, count
);
748 if (dataW
) HeapFree( GetProcessHeap(), 0, dataW
);
749 return RtlNtStatusToDosError( status
);
753 /******************************************************************************
754 * RegSetValueW [ADVAPI32.@]
756 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR name
, DWORD type
, LPCWSTR data
, DWORD count
)
761 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey
, debugstr_w(name
), type
, debugstr_w(data
), count
);
763 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
765 if (name
&& name
[0]) /* need to create the subkey */
767 if ((ret
= RegCreateKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
770 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
,
771 (strlenW( data
) + 1) * sizeof(WCHAR
) );
772 if (subkey
!= hkey
) RegCloseKey( subkey
);
777 /******************************************************************************
778 * RegSetValueA [ADVAPI32.@]
780 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
785 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey
, debugstr_a(name
), type
, debugstr_a(data
), count
);
787 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
789 if (name
&& name
[0]) /* need to create the subkey */
791 if ((ret
= RegCreateKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
793 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
, strlen(data
)+1 );
794 if (subkey
!= hkey
) RegCloseKey( subkey
);
800 /******************************************************************************
801 * RegQueryValueExW [ADVAPI32.@]
803 * Retrieves type and data for a specified name associated with an open key
806 * hkey [I] Handle of key to query
807 * name [I] Name of value to query
808 * reserved [I] Reserved - must be NULL
809 * type [O] Address of buffer for value type. If NULL, the type
811 * data [O] Address of data buffer. If NULL, the actual data is
813 * count [I/O] Address of data buffer size
816 * ERROR_SUCCESS: Success
817 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
818 * buffer is left untouched. The MS-documentation is wrong (js) !!!
820 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
821 LPBYTE data
, LPDWORD count
)
824 UNICODE_STRING name_str
;
826 char buffer
[256], *buf_ptr
= buffer
;
827 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
828 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
830 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
831 hkey
, debugstr_w(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
833 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
835 RtlInitUnicodeString( &name_str
, name
);
837 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
838 else total_size
= info_size
;
840 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
841 buffer
, total_size
, &total_size
);
842 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
846 /* retry with a dynamically allocated buffer */
847 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
849 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
850 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
851 return ERROR_NOT_ENOUGH_MEMORY
;
852 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
853 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
854 buf_ptr
, total_size
, &total_size
);
859 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
860 /* if the type is REG_SZ and data is not 0-terminated
861 * and there is enough space in the buffer NT appends a \0 */
862 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
864 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
865 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
868 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
870 else status
= STATUS_SUCCESS
;
872 if (type
) *type
= info
->Type
;
873 if (count
) *count
= total_size
- info_size
;
876 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
877 return RtlNtStatusToDosError(status
);
881 /******************************************************************************
882 * RegQueryValueExA [ADVAPI32.@]
885 * the documentation is wrong: if the buffer is too small it remains untouched
887 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
888 LPBYTE data
, LPDWORD count
)
893 char buffer
[256], *buf_ptr
= buffer
;
894 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
895 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
897 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
898 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
900 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
902 RtlInitAnsiString( &nameA
, name
);
903 if ((status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
905 return RtlNtStatusToDosError(status
);
907 status
= NtQueryValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
,
908 KeyValuePartialInformation
, buffer
, sizeof(buffer
), &total_size
);
909 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
911 /* we need to fetch the contents for a string type even if not requested,
912 * because we need to compute the length of the ASCII string. */
913 if (data
|| is_string(info
->Type
))
915 /* retry with a dynamically allocated buffer */
916 while (status
== STATUS_BUFFER_OVERFLOW
)
918 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
919 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
921 status
= STATUS_NO_MEMORY
;
924 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
925 status
= NtQueryValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
,
926 KeyValuePartialInformation
, buf_ptr
, total_size
, &total_size
);
929 if (status
) goto done
;
931 if (is_string(info
->Type
))
935 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
936 total_size
- info_size
);
939 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
942 RtlUnicodeToMultiByteN( data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
943 total_size
- info_size
);
944 /* if the type is REG_SZ and data is not 0-terminated
945 * and there is enough space in the buffer NT appends a \0 */
946 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
949 total_size
= len
+ info_size
;
953 if (total_size
- info_size
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
954 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
957 else status
= STATUS_SUCCESS
;
959 if (type
) *type
= info
->Type
;
960 if (count
) *count
= total_size
- info_size
;
963 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
964 return RtlNtStatusToDosError(status
);
968 /******************************************************************************
969 * RegQueryValueW [ADVAPI32.@]
971 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
976 TRACE("(%x,%s,%p,%ld)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
980 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
982 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
983 if (subkey
!= hkey
) RegCloseKey( subkey
);
984 if (ret
== ERROR_FILE_NOT_FOUND
)
986 /* return empty string if default value not found */
988 if (count
) *count
= 1;
995 /******************************************************************************
996 * RegQueryValueA [ADVAPI32.@]
998 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
1003 TRACE("(%x,%s,%p,%ld)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
1005 if (name
&& name
[0])
1007 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1009 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
1010 if (subkey
!= hkey
) RegCloseKey( subkey
);
1011 if (ret
== ERROR_FILE_NOT_FOUND
)
1013 /* return empty string if default value not found */
1014 if (data
) *data
= 0;
1015 if (count
) *count
= 1;
1016 ret
= ERROR_SUCCESS
;
1022 /******************************************************************************
1023 * RegEnumValueW [ADVAPI32.@]
1026 * hkey [I] Handle to key to query
1027 * index [I] Index of value to query
1028 * value [O] Value string
1029 * val_count [I/O] Size of value buffer (in wchars)
1030 * reserved [I] Reserved
1031 * type [O] Type code
1032 * data [O] Value data
1033 * count [I/O] Size of data buffer (in bytes)
1036 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
1037 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1041 char buffer
[256], *buf_ptr
= buffer
;
1042 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1043 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1045 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1046 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1048 /* NT only checks count, not val_count */
1049 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1051 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1052 if (data
) total_size
+= *count
;
1053 total_size
= min( sizeof(buffer
), total_size
);
1055 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1056 buffer
, total_size
, &total_size
);
1057 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1061 /* retry with a dynamically allocated buffer */
1062 while (status
== STATUS_BUFFER_OVERFLOW
)
1064 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1065 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1066 return ERROR_NOT_ENOUGH_MEMORY
;
1067 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1068 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1069 buf_ptr
, total_size
, &total_size
);
1072 if (status
) goto done
;
1076 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
1078 status
= STATUS_BUFFER_OVERFLOW
;
1081 memcpy( value
, info
->Name
, info
->NameLength
);
1082 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
1083 value
[*val_count
] = 0;
1088 if (total_size
- info
->DataOffset
> *count
)
1090 status
= STATUS_BUFFER_OVERFLOW
;
1093 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1094 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1096 /* if the type is REG_SZ and data is not 0-terminated
1097 * and there is enough space in the buffer NT appends a \0 */
1098 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
1099 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1103 else status
= STATUS_SUCCESS
;
1105 if (type
) *type
= info
->Type
;
1106 if (count
) *count
= info
->DataLength
;
1109 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1110 return RtlNtStatusToDosError(status
);
1114 /******************************************************************************
1115 * RegEnumValueA [ADVAPI32.@]
1117 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1118 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1122 char buffer
[256], *buf_ptr
= buffer
;
1123 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1124 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1126 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1127 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1129 /* NT only checks count, not val_count */
1130 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1132 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1133 if (data
) total_size
+= *count
;
1134 total_size
= min( sizeof(buffer
), total_size
);
1136 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1137 buffer
, total_size
, &total_size
);
1138 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1140 /* we need to fetch the contents for a string type even if not requested,
1141 * because we need to compute the length of the ASCII string. */
1142 if (value
|| data
|| is_string(info
->Type
))
1144 /* retry with a dynamically allocated buffer */
1145 while (status
== STATUS_BUFFER_OVERFLOW
)
1147 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1148 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1149 return ERROR_NOT_ENOUGH_MEMORY
;
1150 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1151 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1152 buf_ptr
, total_size
, &total_size
);
1155 if (status
) goto done
;
1161 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
1162 if (len
>= *val_count
)
1164 status
= STATUS_BUFFER_OVERFLOW
;
1167 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1172 if (is_string(info
->Type
))
1175 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1176 total_size
- info
->DataOffset
);
1181 status
= STATUS_BUFFER_OVERFLOW
;
1184 RtlUnicodeToMultiByteN( data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1185 total_size
- info
->DataOffset
);
1186 /* if the type is REG_SZ and data is not 0-terminated
1187 * and there is enough space in the buffer NT appends a \0 */
1188 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1190 info
->DataLength
= len
;
1194 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1195 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1198 else status
= STATUS_SUCCESS
;
1200 if (type
) *type
= info
->Type
;
1201 if (count
) *count
= info
->DataLength
;
1204 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1205 return RtlNtStatusToDosError(status
);
1210 /******************************************************************************
1211 * RegDeleteValueW [ADVAPI32.@]
1214 * hkey [I] handle to key
1215 * name [I] name of value to delete
1220 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
1222 UNICODE_STRING nameW
;
1223 RtlInitUnicodeString( &nameW
, name
);
1224 return RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
1228 /******************************************************************************
1229 * RegDeleteValueA [ADVAPI32.@]
1231 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
1236 RtlInitAnsiString( &nameA
, name
);
1237 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
1240 status
= NtDeleteValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
);
1242 return RtlNtStatusToDosError( status
);
1246 /******************************************************************************
1247 * RegLoadKeyW [ADVAPI32.@]
1250 * hkey [I] Handle of open key
1251 * subkey [I] Address of name of subkey
1252 * filename [I] Address of filename for registry information
1254 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
1257 DWORD ret
, len
, err
= GetLastError();
1259 TRACE( "(%x,%s,%s)\n", hkey
, debugstr_w(subkey
), debugstr_w(filename
) );
1261 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1262 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1264 len
= strlenW( subkey
) * sizeof(WCHAR
);
1265 if (len
> MAX_PATH
*sizeof(WCHAR
)) return ERROR_INVALID_PARAMETER
;
1267 if ((file
= CreateFileW( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1268 FILE_ATTRIBUTE_NORMAL
, 0 )) == INVALID_HANDLE_VALUE
)
1270 ret
= GetLastError();
1274 SERVER_START_REQ( load_registry
)
1278 wine_server_add_data( req
, subkey
, len
);
1279 ret
= RtlNtStatusToDosError( wine_server_call(req
) );
1282 CloseHandle( file
);
1285 SetLastError( err
); /* restore the last error code */
1290 /******************************************************************************
1291 * RegLoadKeyA [ADVAPI32.@]
1293 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
1295 WCHAR buffer
[MAX_PATH
];
1297 DWORD ret
, len
, err
= GetLastError();
1299 TRACE( "(%x,%s,%s)\n", hkey
, debugstr_a(subkey
), debugstr_a(filename
) );
1301 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1302 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1304 if (!(len
= MultiByteToWideChar( CP_ACP
, 0, subkey
, strlen(subkey
), buffer
, MAX_PATH
)))
1305 return ERROR_INVALID_PARAMETER
;
1307 if ((file
= CreateFileA( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1308 FILE_ATTRIBUTE_NORMAL
, 0 )) == INVALID_HANDLE_VALUE
)
1310 ret
= GetLastError();
1314 SERVER_START_REQ( load_registry
)
1318 wine_server_add_data( req
, buffer
, len
* sizeof(WCHAR
) );
1319 ret
= RtlNtStatusToDosError( wine_server_call(req
) );
1322 CloseHandle( file
);
1325 SetLastError( err
); /* restore the last error code */
1330 /******************************************************************************
1331 * RegSaveKeyA [ADVAPI32.@]
1334 * hkey [I] Handle of key where save begins
1335 * lpFile [I] Address of filename to save to
1336 * sa [I] Address of security structure
1338 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
1346 TRACE( "(%x,%s,%p)\n", hkey
, debugstr_a(file
), sa
);
1348 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
1350 err
= GetLastError();
1351 GetFullPathNameA( file
, sizeof(buffer
), buffer
, &name
);
1354 sprintf( name
, "reg%04x.tmp", count
++ );
1355 handle
= CreateFileA( buffer
, GENERIC_WRITE
, 0, NULL
,
1356 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
1357 if (handle
!= INVALID_HANDLE_VALUE
) break;
1358 if ((ret
= GetLastError()) != ERROR_ALREADY_EXISTS
) goto done
;
1360 /* Something gone haywire ? Please report if this happens abnormally */
1362 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
);
1365 SERVER_START_REQ( save_registry
)
1369 ret
= RtlNtStatusToDosError( wine_server_call( req
) );
1373 CloseHandle( handle
);
1376 if (!MoveFileExA( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
1378 ERR( "Failed to move %s to %s\n", buffer
, file
);
1379 ret
= GetLastError();
1382 if (ret
) DeleteFileA( buffer
);
1385 SetLastError( err
); /* restore last error code */
1390 /******************************************************************************
1391 * RegSaveKeyW [ADVAPI32.@]
1393 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
1395 LPSTR fileA
= HEAP_strdupWtoA( GetProcessHeap(), 0, file
);
1396 DWORD ret
= RegSaveKeyA( hkey
, fileA
, sa
);
1397 if (fileA
) HeapFree( GetProcessHeap(), 0, fileA
);
1402 /******************************************************************************
1403 * RegRestoreKeyW [ADVAPI32.@]
1406 * hkey [I] Handle of key where restore begins
1407 * lpFile [I] Address of filename containing saved tree
1408 * dwFlags [I] Optional flags
1410 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1412 TRACE("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1414 /* It seems to do this check before the hkey check */
1415 if (!lpFile
|| !*lpFile
)
1416 return ERROR_INVALID_PARAMETER
;
1418 FIXME("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1420 /* Check for file existence */
1422 return ERROR_SUCCESS
;
1426 /******************************************************************************
1427 * RegRestoreKeyA [ADVAPI32.@]
1429 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1431 LPWSTR lpFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile
);
1432 LONG ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1433 HeapFree( GetProcessHeap(), 0, lpFileW
);
1438 /******************************************************************************
1439 * RegUnLoadKeyW [ADVAPI32.@]
1442 * hkey [I] Handle of open key
1443 * lpSubKey [I] Address of name of subkey to unload
1445 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1447 FIXME("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1448 return ERROR_SUCCESS
;
1452 /******************************************************************************
1453 * RegUnLoadKeyA [ADVAPI32.@]
1455 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1457 LPWSTR lpSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey
);
1458 LONG ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
1459 if(lpSubKeyW
) HeapFree( GetProcessHeap(), 0, lpSubKeyW
);
1464 /******************************************************************************
1465 * RegReplaceKeyW [ADVAPI32.@]
1468 * hkey [I] Handle of open key
1469 * lpSubKey [I] Address of name of subkey
1470 * lpNewFile [I] Address of filename for file with new data
1471 * lpOldFile [I] Address of filename for backup file
1473 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1476 FIXME("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1477 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1478 return ERROR_SUCCESS
;
1482 /******************************************************************************
1483 * RegReplaceKeyA [ADVAPI32.@]
1485 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1488 LPWSTR lpSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey
);
1489 LPWSTR lpNewFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile
);
1490 LPWSTR lpOldFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile
);
1491 LONG ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
1492 HeapFree( GetProcessHeap(), 0, lpOldFileW
);
1493 HeapFree( GetProcessHeap(), 0, lpNewFileW
);
1494 HeapFree( GetProcessHeap(), 0, lpSubKeyW
);
1499 /******************************************************************************
1500 * RegSetKeySecurity [ADVAPI32.@]
1503 * hkey [I] Open handle of key to set
1504 * SecurityInfo [I] Descriptor contents
1505 * pSecurityDesc [I] Address of descriptor for key
1507 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1508 PSECURITY_DESCRIPTOR pSecurityDesc
)
1510 TRACE("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1512 /* It seems to perform this check before the hkey check */
1513 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1514 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1515 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1516 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1519 return ERROR_INVALID_PARAMETER
;
1522 return ERROR_INVALID_PARAMETER
;
1524 FIXME(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1526 return ERROR_SUCCESS
;
1530 /******************************************************************************
1531 * RegGetKeySecurity [ADVAPI32.@]
1532 * Retrieves a copy of security descriptor protecting the registry key
1535 * hkey [I] Open handle of key to set
1536 * SecurityInformation [I] Descriptor contents
1537 * pSecurityDescriptor [O] Address of descriptor for key
1538 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1541 * Success: ERROR_SUCCESS
1542 * Failure: Error code
1544 LONG WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
1545 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1546 LPDWORD lpcbSecurityDescriptor
)
1548 TRACE("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1549 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1551 /* FIXME: Check for valid SecurityInformation values */
1553 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1554 return ERROR_INSUFFICIENT_BUFFER
;
1556 FIXME("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1557 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1559 /* Do not leave security descriptor filled with garbage */
1560 RtlCreateSecurityDescriptor(pSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
1562 return ERROR_SUCCESS
;
1566 /******************************************************************************
1567 * RegFlushKey [ADVAPI32.@]
1568 * Immediately writes key to registry.
1569 * Only returns after data has been written to disk.
1571 * FIXME: does it really wait until data is written ?
1574 * hkey [I] Handle of key to write
1577 * Success: ERROR_SUCCESS
1578 * Failure: Error code
1580 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1582 FIXME( "(%x): stub\n", hkey
);
1583 return ERROR_SUCCESS
;
1587 /******************************************************************************
1588 * RegConnectRegistryW [ADVAPI32.@]
1591 * lpMachineName [I] Address of name of remote computer
1592 * hHey [I] Predefined registry handle
1593 * phkResult [I] Address of buffer for remote registry handle
1595 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1598 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1600 if (!lpMachineName
|| !*lpMachineName
) {
1601 /* Use the local machine name */
1602 return RegOpenKeyA( hKey
, "", phkResult
);
1605 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1606 return ERROR_BAD_NETPATH
;
1610 /******************************************************************************
1611 * RegConnectRegistryA [ADVAPI32.@]
1613 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
1615 LPWSTR machineW
= HEAP_strdupAtoW( GetProcessHeap(), 0, machine
);
1616 DWORD ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
1617 HeapFree( GetProcessHeap(), 0, machineW
);
1622 /******************************************************************************
1623 * RegNotifyChangeKeyValue [ADVAPI32.@]
1626 * hkey [I] Handle of key to watch
1627 * fWatchSubTree [I] Flag for subkey notification
1628 * fdwNotifyFilter [I] Changes to be reported
1629 * hEvent [I] Handle of signaled event
1630 * fAsync [I] Flag for asynchronous reporting
1632 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1633 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1636 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1638 return ERROR_SUCCESS
;