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
35 #include "wine/unicode.h"
37 #include "wine/server.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
43 /* check if value type needs string conversion (Ansi<->Unicode) */
44 inline static int is_string( DWORD type
)
46 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
49 /* check if current version is NT or Win95 */
50 inline static int is_version_nt(void)
52 return !(GetVersion() & 0x80000000);
55 /* allowed bits for access mask */
56 #define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
58 /******************************************************************************
59 * RegCreateKeyExW [ADVAPI32.@]
62 * hkey [I] Handle of an open key
63 * name [I] Address of subkey name
64 * reserved [I] Reserved - must be 0
65 * class [I] Address of class string
66 * options [I] Special options flag
67 * access [I] Desired security access
68 * sa [I] Address of key security structure
69 * retkey [O] Address of buffer for opened handle
70 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
73 * in case of failing retkey remains untouched
75 * FIXME MAXIMUM_ALLOWED in access mask not supported by server
77 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
78 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
79 LPHKEY retkey
, LPDWORD dispos
)
81 OBJECT_ATTRIBUTES attr
;
82 UNICODE_STRING nameW
, classW
;
84 if (reserved
) return ERROR_INVALID_PARAMETER
;
85 if (!(access
& KEY_ACCESS_MASK
) || (access
& ~KEY_ACCESS_MASK
)) return ERROR_ACCESS_DENIED
;
87 attr
.Length
= sizeof(attr
);
88 attr
.RootDirectory
= hkey
;
89 attr
.ObjectName
= &nameW
;
91 attr
.SecurityDescriptor
= NULL
;
92 attr
.SecurityQualityOfService
= NULL
;
93 RtlInitUnicodeString( &nameW
, name
);
94 RtlInitUnicodeString( &classW
, class );
96 return RtlNtStatusToDosError( NtCreateKey( retkey
, access
, &attr
, 0,
97 &classW
, options
, dispos
) );
101 /******************************************************************************
102 * RegCreateKeyExA [ADVAPI32.@]
104 * FIXME MAXIMUM_ALLOWED in access mask not supported by server
106 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
107 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
108 LPHKEY retkey
, LPDWORD dispos
)
110 OBJECT_ATTRIBUTES attr
;
111 UNICODE_STRING classW
;
112 ANSI_STRING nameA
, classA
;
115 if (reserved
) return ERROR_INVALID_PARAMETER
;
116 if (!is_version_nt()) access
= KEY_ALL_ACCESS
; /* Win95 ignores the access mask */
117 else if (!(access
& KEY_ACCESS_MASK
) || (access
& ~KEY_ACCESS_MASK
)) return ERROR_ACCESS_DENIED
;
119 attr
.Length
= sizeof(attr
);
120 attr
.RootDirectory
= hkey
;
121 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
123 attr
.SecurityDescriptor
= NULL
;
124 attr
.SecurityQualityOfService
= NULL
;
125 RtlInitAnsiString( &nameA
, name
);
126 RtlInitAnsiString( &classA
, class );
128 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
131 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
133 status
= NtCreateKey( retkey
, access
, &attr
, 0, &classW
, options
, dispos
);
134 RtlFreeUnicodeString( &classW
);
137 return RtlNtStatusToDosError( status
);
141 /******************************************************************************
142 * RegCreateKeyW [ADVAPI32.@]
144 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR name
, LPHKEY retkey
)
146 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
147 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
148 return RegCreateKeyExW( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
149 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
153 /******************************************************************************
154 * RegCreateKeyA [ADVAPI32.@]
156 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
158 return RegCreateKeyExA( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
159 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
164 /******************************************************************************
165 * RegOpenKeyExW [ADVAPI32.@]
167 * Opens the specified key
169 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
172 * hkey [I] Handle of open key
173 * name [I] Name of subkey to open
174 * reserved [I] Reserved - must be zero
175 * access [I] Security access mask
176 * retkey [O] Handle to open key
179 * Success: ERROR_SUCCESS
180 * Failure: Error code
183 * in case of failing is retkey = 0
185 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, REGSAM access
, LPHKEY retkey
)
187 OBJECT_ATTRIBUTES attr
;
188 UNICODE_STRING nameW
;
190 attr
.Length
= sizeof(attr
);
191 attr
.RootDirectory
= hkey
;
192 attr
.ObjectName
= &nameW
;
194 attr
.SecurityDescriptor
= NULL
;
195 attr
.SecurityQualityOfService
= NULL
;
196 RtlInitUnicodeString( &nameW
, name
);
197 return RtlNtStatusToDosError( NtOpenKey( retkey
, access
, &attr
) );
201 /******************************************************************************
202 * RegOpenKeyExA [ADVAPI32.@]
204 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, REGSAM access
, LPHKEY retkey
)
206 OBJECT_ATTRIBUTES attr
;
210 if (!is_version_nt()) access
= KEY_ALL_ACCESS
; /* Win95 ignores the access mask */
212 attr
.Length
= sizeof(attr
);
213 attr
.RootDirectory
= hkey
;
214 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
216 attr
.SecurityDescriptor
= NULL
;
217 attr
.SecurityQualityOfService
= NULL
;
219 RtlInitAnsiString( &nameA
, name
);
220 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
223 status
= NtOpenKey( retkey
, access
, &attr
);
225 return RtlNtStatusToDosError( status
);
229 /******************************************************************************
230 * RegOpenKeyW [ADVAPI32.@]
233 * hkey [I] Handle of open key
234 * name [I] Address of name of subkey to open
235 * retkey [O] Handle to open key
238 * Success: ERROR_SUCCESS
239 * Failure: Error code
242 * in case of failing is retkey = 0
244 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, LPHKEY retkey
)
246 return RegOpenKeyExW( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
250 /******************************************************************************
251 * RegOpenKeyA [ADVAPI32.@]
253 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
255 return RegOpenKeyExA( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
259 /******************************************************************************
260 * RegOpenCurrentUser [ADVAPI32.@]
261 * FIXME: This function is supposed to retrieve a handle to the
262 * HKEY_CURRENT_USER for the user the current thread is impersonating.
263 * Since Wine does not currently allow threads to impersonate other users,
264 * this stub should work fine.
266 DWORD WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
268 return RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
273 /******************************************************************************
274 * RegEnumKeyExW [ADVAPI32.@]
277 * hkey [I] Handle to key to enumerate
278 * index [I] Index of subkey to enumerate
279 * name [O] Buffer for subkey name
280 * name_len [O] Size of subkey buffer
281 * reserved [I] Reserved
282 * class [O] Buffer for class string
283 * class_len [O] Size of class buffer
284 * ft [O] Time key last written to
286 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
287 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
290 char buffer
[256], *buf_ptr
= buffer
;
291 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
294 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
295 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
297 if (reserved
) return ERROR_INVALID_PARAMETER
;
299 if (!hkey
) return ERROR_INVALID_HANDLE
;
301 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
302 buffer
, sizeof(buffer
), &total_size
);
304 while (status
== STATUS_BUFFER_OVERFLOW
)
306 /* retry with a dynamically allocated buffer */
307 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
308 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
309 return ERROR_NOT_ENOUGH_MEMORY
;
310 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
311 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
312 buf_ptr
, total_size
, &total_size
);
317 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
318 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
320 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
322 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
323 status
= STATUS_BUFFER_OVERFLOW
;
327 memcpy( name
, info
->Name
, info
->NameLength
);
331 *class_len
= cls_len
;
334 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
341 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
342 return RtlNtStatusToDosError( status
);
346 /******************************************************************************
347 * RegEnumKeyExA [ADVAPI32.@]
349 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
350 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
353 char buffer
[256], *buf_ptr
= buffer
;
354 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
357 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
358 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
360 if (reserved
) return ERROR_INVALID_PARAMETER
;
362 if (!hkey
) return ERROR_INVALID_HANDLE
;
364 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
365 buffer
, sizeof(buffer
), &total_size
);
367 while (status
== STATUS_BUFFER_OVERFLOW
)
369 /* retry with a dynamically allocated buffer */
370 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
371 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
372 return ERROR_NOT_ENOUGH_MEMORY
;
373 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
374 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
375 buf_ptr
, total_size
, &total_size
);
382 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
383 RtlUnicodeToMultiByteSize( &cls_len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
385 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
387 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
388 status
= STATUS_BUFFER_OVERFLOW
;
392 RtlUnicodeToMultiByteN( name
, len
, NULL
, info
->Name
, info
->NameLength
);
396 *class_len
= cls_len
;
399 RtlUnicodeToMultiByteN( class, cls_len
, NULL
,
400 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
408 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
409 return RtlNtStatusToDosError( status
);
413 /******************************************************************************
414 * RegEnumKeyW [ADVAPI32.@]
416 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
418 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
422 /******************************************************************************
423 * RegEnumKeyA [ADVAPI32.@]
425 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
427 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
431 /******************************************************************************
432 * RegQueryInfoKeyW [ADVAPI32.@]
435 * hkey [I] Handle to key to query
436 * class [O] Buffer for class string
437 * class_len [O] Size of class string buffer
438 * reserved [I] Reserved
439 * subkeys [O] Buffer for number of subkeys
440 * max_subkey [O] Buffer for longest subkey name length
441 * max_class [O] Buffer for longest class string length
442 * values [O] Buffer for number of value entries
443 * max_value [O] Buffer for longest value name length
444 * max_data [O] Buffer for longest value data length
445 * security [O] Buffer for security descriptor length
446 * modif [O] Modification time
448 * - win95 allows class to be valid and class_len to be NULL
449 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
450 * - both allow class to be NULL and class_len to be NULL
451 * (it's hard to test validity, so test !NULL instead)
453 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
454 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
455 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
456 LPDWORD security
, FILETIME
*modif
)
459 char buffer
[256], *buf_ptr
= buffer
;
460 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
463 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
464 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
466 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
468 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
469 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
473 /* retry with a dynamically allocated buffer */
474 while (status
== STATUS_BUFFER_OVERFLOW
)
476 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
477 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
478 return ERROR_NOT_ENOUGH_MEMORY
;
479 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
480 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
483 if (status
) goto done
;
485 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
487 status
= STATUS_BUFFER_OVERFLOW
;
491 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
492 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
495 else status
= STATUS_SUCCESS
;
497 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
498 if (subkeys
) *subkeys
= info
->SubKeys
;
499 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
500 if (max_class
) *max_class
= info
->MaxClassLen
;
501 if (values
) *values
= info
->Values
;
502 if (max_value
) *max_value
= info
->MaxValueNameLen
;
503 if (max_data
) *max_data
= info
->MaxValueDataLen
;
504 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
507 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
508 return RtlNtStatusToDosError( status
);
512 /******************************************************************************
513 * RegQueryMultipleValuesA [ADVAPI32.@]
515 DWORD WINAPI
RegQueryMultipleValuesA(HKEY hkey
, PVALENTA val_list
, DWORD num_vals
,
516 LPSTR lpValueBuf
, LPDWORD ldwTotsize
)
519 DWORD maxBytes
= *ldwTotsize
;
521 LPSTR bufptr
= lpValueBuf
;
524 TRACE("(%x,%p,%ld,%p,%p=%ld)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
526 for(i
=0; i
< num_vals
; ++i
)
529 val_list
[i
].ve_valuelen
=0;
530 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
531 if(status
!= ERROR_SUCCESS
)
536 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
538 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
539 bufptr
, &val_list
[i
].ve_valuelen
);
540 if(status
!= ERROR_SUCCESS
)
545 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
547 bufptr
+= val_list
[i
].ve_valuelen
;
550 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
552 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
556 /******************************************************************************
557 * RegQueryMultipleValuesW [ADVAPI32.@]
559 DWORD WINAPI
RegQueryMultipleValuesW(HKEY hkey
, PVALENTW val_list
, DWORD num_vals
,
560 LPWSTR lpValueBuf
, LPDWORD ldwTotsize
)
563 DWORD maxBytes
= *ldwTotsize
;
565 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
568 TRACE("(%x,%p,%ld,%p,%p=%ld)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
570 for(i
=0; i
< num_vals
; ++i
)
572 val_list
[i
].ve_valuelen
=0;
573 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
574 if(status
!= ERROR_SUCCESS
)
579 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
581 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
582 bufptr
, &val_list
[i
].ve_valuelen
);
583 if(status
!= ERROR_SUCCESS
)
588 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
590 bufptr
+= val_list
[i
].ve_valuelen
;
593 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
595 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
598 /******************************************************************************
599 * RegQueryInfoKeyA [ADVAPI32.@]
601 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
602 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
603 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
604 LPDWORD security
, FILETIME
*modif
)
607 char buffer
[256], *buf_ptr
= buffer
;
608 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
609 DWORD total_size
, len
;
611 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
612 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
614 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
616 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
617 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
619 if (class || class_len
)
621 /* retry with a dynamically allocated buffer */
622 while (status
== STATUS_BUFFER_OVERFLOW
)
624 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
625 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
626 return ERROR_NOT_ENOUGH_MEMORY
;
627 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
628 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
631 if (status
) goto done
;
633 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
), info
->ClassLength
);
636 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
639 if (class && !status
)
641 RtlUnicodeToMultiByteN( class, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
646 else status
= STATUS_SUCCESS
;
648 if (subkeys
) *subkeys
= info
->SubKeys
;
649 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
650 if (max_class
) *max_class
= info
->MaxClassLen
;
651 if (values
) *values
= info
->Values
;
652 if (max_value
) *max_value
= info
->MaxValueNameLen
;
653 if (max_data
) *max_data
= info
->MaxValueDataLen
;
654 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
657 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
658 return RtlNtStatusToDosError( status
);
662 /******************************************************************************
663 * RegCloseKey [ADVAPI32.@]
665 * Releases the handle of the specified key
668 * hkey [I] Handle of key to close
671 * Success: ERROR_SUCCESS
672 * Failure: Error code
674 DWORD WINAPI
RegCloseKey( HKEY hkey
)
676 if (!hkey
|| hkey
>= (HKEY
)0x80000000) return ERROR_SUCCESS
;
677 return RtlNtStatusToDosError( NtClose( hkey
) );
681 /******************************************************************************
682 * RegDeleteKeyW [ADVAPI32.@]
685 * hkey [I] Handle to open key
686 * name [I] Name of subkey to delete
689 * Success: ERROR_SUCCESS
690 * Failure: Error code
692 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
699 ret
= RtlNtStatusToDosError( NtDeleteKey( hkey
) );
701 else if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, 0, &tmp
)))
703 if (!is_version_nt()) /* win95 does recursive key deletes */
705 WCHAR name
[MAX_PATH
];
707 while(!RegEnumKeyW(tmp
, 0, name
, sizeof name
))
709 if(RegDeleteKeyW(tmp
, name
)) /* recurse */
713 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
716 TRACE("%s ret=%08lx\n", debugstr_w(name
), ret
);
721 /******************************************************************************
722 * RegDeleteKeyA [ADVAPI32.@]
724 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
731 ret
= RtlNtStatusToDosError( NtDeleteKey( hkey
) );
733 else if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, KEY_ALL_ACCESS
, &tmp
)))
735 if (!is_version_nt()) /* win95 does recursive key deletes */
739 while(!RegEnumKeyA(tmp
, 0, name
, sizeof name
))
741 if(RegDeleteKeyA(tmp
, name
)) /* recurse */
745 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
748 TRACE("%s ret=%08lx\n", debugstr_a(name
), ret
);
754 /******************************************************************************
755 * RegSetValueExW [ADVAPI32.@]
757 * Sets the data and type of a value under a register key
760 * hkey [I] Handle of key to set value for
761 * name [I] Name of value to set
762 * reserved [I] Reserved - must be zero
763 * type [I] Flag for value type
764 * data [I] Address of value data
765 * count [I] Size of value data
768 * Success: ERROR_SUCCESS
769 * Failure: Error code
772 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
773 * NT does definitely care (aj)
775 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
776 DWORD type
, CONST BYTE
*data
, DWORD count
)
778 UNICODE_STRING nameW
;
780 if (!is_version_nt()) /* win95 */
782 if (type
== REG_SZ
) count
= (strlenW( (WCHAR
*)data
) + 1) * sizeof(WCHAR
);
784 else if (count
&& is_string(type
))
786 LPCWSTR str
= (LPCWSTR
)data
;
787 /* if user forgot to count terminating null, add it (yes NT does this) */
788 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
789 count
+= sizeof(WCHAR
);
792 RtlInitUnicodeString( &nameW
, name
);
793 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
797 /******************************************************************************
798 * RegSetValueExA [ADVAPI32.@]
800 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
801 CONST BYTE
*data
, DWORD count
)
807 if (!is_version_nt()) /* win95 */
809 if (type
== REG_SZ
) count
= strlen(data
) + 1;
811 else if (count
&& is_string(type
))
813 /* if user forgot to count terminating null, add it (yes NT does this) */
814 if (data
[count
-1] && !data
[count
]) count
++;
817 if (is_string( type
)) /* need to convert to Unicode */
820 RtlMultiByteToUnicodeSize( &lenW
, data
, count
);
821 if (!(dataW
= HeapAlloc( GetProcessHeap(), 0, lenW
))) return ERROR_OUTOFMEMORY
;
822 RtlMultiByteToUnicodeN( dataW
, lenW
, NULL
, data
, count
);
824 data
= (BYTE
*)dataW
;
827 RtlInitAnsiString( &nameA
, name
);
828 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
831 status
= NtSetValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
, 0, type
, data
, count
);
833 if (dataW
) HeapFree( GetProcessHeap(), 0, dataW
);
834 return RtlNtStatusToDosError( status
);
838 /******************************************************************************
839 * RegSetValueW [ADVAPI32.@]
841 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR name
, DWORD type
, LPCWSTR data
, DWORD count
)
846 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey
, debugstr_w(name
), type
, debugstr_w(data
), count
);
848 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
850 if (name
&& name
[0]) /* need to create the subkey */
852 if ((ret
= RegCreateKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
855 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
,
856 (strlenW( data
) + 1) * sizeof(WCHAR
) );
857 if (subkey
!= hkey
) RegCloseKey( subkey
);
862 /******************************************************************************
863 * RegSetValueA [ADVAPI32.@]
865 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
870 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey
, debugstr_a(name
), type
, debugstr_a(data
), count
);
872 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
874 if (name
&& name
[0]) /* need to create the subkey */
876 if ((ret
= RegCreateKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
878 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
, strlen(data
)+1 );
879 if (subkey
!= hkey
) RegCloseKey( subkey
);
885 /******************************************************************************
886 * RegQueryValueExW [ADVAPI32.@]
888 * Retrieves type and data for a specified name associated with an open key
891 * hkey [I] Handle of key to query
892 * name [I] Name of value to query
893 * reserved [I] Reserved - must be NULL
894 * type [O] Address of buffer for value type. If NULL, the type
896 * data [O] Address of data buffer. If NULL, the actual data is
898 * count [I/O] Address of data buffer size
901 * ERROR_SUCCESS: Success
902 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
903 * buffer is left untouched. The MS-documentation is wrong (js) !!!
905 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
906 LPBYTE data
, LPDWORD count
)
909 UNICODE_STRING name_str
;
911 char buffer
[256], *buf_ptr
= buffer
;
912 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
913 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
915 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
916 hkey
, debugstr_w(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
918 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
920 RtlInitUnicodeString( &name_str
, name
);
922 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
923 else total_size
= info_size
;
925 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
926 buffer
, total_size
, &total_size
);
927 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
931 /* retry with a dynamically allocated buffer */
932 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
934 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
935 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
936 return ERROR_NOT_ENOUGH_MEMORY
;
937 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
938 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
939 buf_ptr
, total_size
, &total_size
);
944 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
945 /* if the type is REG_SZ and data is not 0-terminated
946 * and there is enough space in the buffer NT appends a \0 */
947 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
949 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
950 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
953 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
955 else status
= STATUS_SUCCESS
;
957 if (type
) *type
= info
->Type
;
958 if (count
) *count
= total_size
- info_size
;
961 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
962 return RtlNtStatusToDosError(status
);
966 /******************************************************************************
967 * RegQueryValueExA [ADVAPI32.@]
970 * the documentation is wrong: if the buffer is too small it remains untouched
972 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
973 LPBYTE data
, LPDWORD count
)
978 char buffer
[256], *buf_ptr
= buffer
;
979 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
980 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
982 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
983 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
985 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
987 RtlInitAnsiString( &nameA
, name
);
988 if ((status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
990 return RtlNtStatusToDosError(status
);
992 status
= NtQueryValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
,
993 KeyValuePartialInformation
, buffer
, sizeof(buffer
), &total_size
);
994 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
996 /* we need to fetch the contents for a string type even if not requested,
997 * because we need to compute the length of the ASCII string. */
998 if (data
|| is_string(info
->Type
))
1000 /* retry with a dynamically allocated buffer */
1001 while (status
== STATUS_BUFFER_OVERFLOW
)
1003 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1004 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1006 status
= STATUS_NO_MEMORY
;
1009 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1010 status
= NtQueryValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
,
1011 KeyValuePartialInformation
, buf_ptr
, total_size
, &total_size
);
1014 if (status
) goto done
;
1016 if (is_string(info
->Type
))
1020 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
1021 total_size
- info_size
);
1024 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1027 RtlUnicodeToMultiByteN( data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
1028 total_size
- info_size
);
1029 /* if the type is REG_SZ and data is not 0-terminated
1030 * and there is enough space in the buffer NT appends a \0 */
1031 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1034 total_size
= len
+ info_size
;
1038 if (total_size
- info_size
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1039 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1042 else status
= STATUS_SUCCESS
;
1044 if (type
) *type
= info
->Type
;
1045 if (count
) *count
= total_size
- info_size
;
1048 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1049 return RtlNtStatusToDosError(status
);
1053 /******************************************************************************
1054 * RegQueryValueW [ADVAPI32.@]
1056 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
1061 TRACE("(%x,%s,%p,%ld)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
1063 if (name
&& name
[0])
1065 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1067 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
1068 if (subkey
!= hkey
) RegCloseKey( subkey
);
1069 if (ret
== ERROR_FILE_NOT_FOUND
)
1071 /* return empty string if default value not found */
1072 if (data
) *data
= 0;
1073 if (count
) *count
= 1;
1074 ret
= ERROR_SUCCESS
;
1080 /******************************************************************************
1081 * RegQueryValueA [ADVAPI32.@]
1083 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
1088 TRACE("(%x,%s,%p,%ld)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
1090 if (name
&& name
[0])
1092 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1094 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
1095 if (subkey
!= hkey
) RegCloseKey( subkey
);
1096 if (ret
== ERROR_FILE_NOT_FOUND
)
1098 /* return empty string if default value not found */
1099 if (data
) *data
= 0;
1100 if (count
) *count
= 1;
1101 ret
= ERROR_SUCCESS
;
1107 /******************************************************************************
1108 * RegEnumValueW [ADVAPI32.@]
1111 * hkey [I] Handle to key to query
1112 * index [I] Index of value to query
1113 * value [O] Value string
1114 * val_count [I/O] Size of value buffer (in wchars)
1115 * reserved [I] Reserved
1116 * type [O] Type code
1117 * data [O] Value data
1118 * count [I/O] Size of data buffer (in bytes)
1121 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
1122 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1126 char buffer
[256], *buf_ptr
= buffer
;
1127 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1128 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1130 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1131 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1133 /* NT only checks count, not val_count */
1134 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1136 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1137 if (data
) total_size
+= *count
;
1138 total_size
= min( sizeof(buffer
), total_size
);
1140 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1141 buffer
, total_size
, &total_size
);
1142 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1146 /* retry with a dynamically allocated buffer */
1147 while (status
== STATUS_BUFFER_OVERFLOW
)
1149 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1150 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1151 return ERROR_NOT_ENOUGH_MEMORY
;
1152 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1153 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1154 buf_ptr
, total_size
, &total_size
);
1157 if (status
) goto done
;
1161 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
1163 status
= STATUS_BUFFER_OVERFLOW
;
1166 memcpy( value
, info
->Name
, info
->NameLength
);
1167 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
1168 value
[*val_count
] = 0;
1173 if (total_size
- info
->DataOffset
> *count
)
1175 status
= STATUS_BUFFER_OVERFLOW
;
1178 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1179 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1181 /* if the type is REG_SZ and data is not 0-terminated
1182 * and there is enough space in the buffer NT appends a \0 */
1183 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
1184 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1188 else status
= STATUS_SUCCESS
;
1191 if (type
) *type
= info
->Type
;
1192 if (count
) *count
= info
->DataLength
;
1195 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1196 return RtlNtStatusToDosError(status
);
1200 /******************************************************************************
1201 * RegEnumValueA [ADVAPI32.@]
1203 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1204 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1208 char buffer
[256], *buf_ptr
= buffer
;
1209 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1210 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1212 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1213 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1215 /* NT only checks count, not val_count */
1216 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1218 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1219 if (data
) total_size
+= *count
;
1220 total_size
= min( sizeof(buffer
), total_size
);
1222 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1223 buffer
, total_size
, &total_size
);
1224 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1226 /* we need to fetch the contents for a string type even if not requested,
1227 * because we need to compute the length of the ASCII string. */
1228 if (value
|| data
|| is_string(info
->Type
))
1230 /* retry with a dynamically allocated buffer */
1231 while (status
== STATUS_BUFFER_OVERFLOW
)
1233 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1234 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1235 return ERROR_NOT_ENOUGH_MEMORY
;
1236 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1237 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1238 buf_ptr
, total_size
, &total_size
);
1241 if (status
) goto done
;
1243 if (is_string(info
->Type
))
1246 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1247 total_size
- info
->DataOffset
);
1250 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1253 RtlUnicodeToMultiByteN( data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1254 total_size
- info
->DataOffset
);
1255 /* if the type is REG_SZ and data is not 0-terminated
1256 * and there is enough space in the buffer NT appends a \0 */
1257 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1260 info
->DataLength
= len
;
1264 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1265 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1268 if (value
&& !status
)
1272 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
1273 if (len
>= *val_count
)
1275 status
= STATUS_BUFFER_OVERFLOW
;
1278 len
= *val_count
- 1;
1279 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1285 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1291 else status
= STATUS_SUCCESS
;
1293 if (type
) *type
= info
->Type
;
1294 if (count
) *count
= info
->DataLength
;
1297 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1298 return RtlNtStatusToDosError(status
);
1303 /******************************************************************************
1304 * RegDeleteValueW [ADVAPI32.@]
1307 * hkey [I] handle to key
1308 * name [I] name of value to delete
1313 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
1315 UNICODE_STRING nameW
;
1316 RtlInitUnicodeString( &nameW
, name
);
1317 return RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
1321 /******************************************************************************
1322 * RegDeleteValueA [ADVAPI32.@]
1324 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
1329 RtlInitAnsiString( &nameA
, name
);
1330 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
1333 status
= NtDeleteValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
);
1335 return RtlNtStatusToDosError( status
);
1339 /******************************************************************************
1340 * RegLoadKeyW [ADVAPI32.@]
1343 * hkey [I] Handle of open key
1344 * subkey [I] Address of name of subkey
1345 * filename [I] Address of filename for registry information
1347 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
1350 DWORD ret
, len
, err
= GetLastError();
1352 TRACE( "(%x,%s,%s)\n", hkey
, debugstr_w(subkey
), debugstr_w(filename
) );
1354 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1355 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1357 len
= strlenW( subkey
) * sizeof(WCHAR
);
1358 if (len
> MAX_PATH
*sizeof(WCHAR
)) return ERROR_INVALID_PARAMETER
;
1360 if ((file
= CreateFileW( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1361 FILE_ATTRIBUTE_NORMAL
, 0 )) == INVALID_HANDLE_VALUE
)
1363 ret
= GetLastError();
1367 SERVER_START_REQ( load_registry
)
1371 wine_server_add_data( req
, subkey
, len
);
1372 ret
= RtlNtStatusToDosError( wine_server_call(req
) );
1375 CloseHandle( file
);
1378 SetLastError( err
); /* restore the last error code */
1383 /******************************************************************************
1384 * RegLoadKeyA [ADVAPI32.@]
1386 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
1388 WCHAR buffer
[MAX_PATH
];
1390 DWORD ret
, len
, err
= GetLastError();
1392 TRACE( "(%x,%s,%s)\n", hkey
, debugstr_a(subkey
), debugstr_a(filename
) );
1394 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1395 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1397 if (!(len
= MultiByteToWideChar( CP_ACP
, 0, subkey
, strlen(subkey
), buffer
, MAX_PATH
)))
1398 return ERROR_INVALID_PARAMETER
;
1400 if ((file
= CreateFileA( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1401 FILE_ATTRIBUTE_NORMAL
, 0 )) == INVALID_HANDLE_VALUE
)
1403 ret
= GetLastError();
1407 SERVER_START_REQ( load_registry
)
1411 wine_server_add_data( req
, buffer
, len
* sizeof(WCHAR
) );
1412 ret
= RtlNtStatusToDosError( wine_server_call(req
) );
1415 CloseHandle( file
);
1418 SetLastError( err
); /* restore the last error code */
1423 /******************************************************************************
1424 * RegSaveKeyA [ADVAPI32.@]
1427 * hkey [I] Handle of key where save begins
1428 * lpFile [I] Address of filename to save to
1429 * sa [I] Address of security structure
1431 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
1439 TRACE( "(%x,%s,%p)\n", hkey
, debugstr_a(file
), sa
);
1441 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
1443 err
= GetLastError();
1444 GetFullPathNameA( file
, sizeof(buffer
), buffer
, &name
);
1447 sprintf( name
, "reg%04x.tmp", count
++ );
1448 handle
= CreateFileA( buffer
, GENERIC_WRITE
, 0, NULL
,
1449 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
1450 if (handle
!= INVALID_HANDLE_VALUE
) break;
1451 if ((ret
= GetLastError()) != ERROR_ALREADY_EXISTS
) goto done
;
1453 /* Something gone haywire ? Please report if this happens abnormally */
1455 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
);
1458 SERVER_START_REQ( save_registry
)
1462 ret
= RtlNtStatusToDosError( wine_server_call( req
) );
1466 CloseHandle( handle
);
1469 if (!MoveFileExA( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
1471 ERR( "Failed to move %s to %s\n", buffer
, file
);
1472 ret
= GetLastError();
1475 if (ret
) DeleteFileA( buffer
);
1478 SetLastError( err
); /* restore last error code */
1483 /******************************************************************************
1484 * RegSaveKeyW [ADVAPI32.@]
1486 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
1488 LPSTR fileA
= HEAP_strdupWtoA( GetProcessHeap(), 0, file
);
1489 DWORD ret
= RegSaveKeyA( hkey
, fileA
, sa
);
1490 if (fileA
) HeapFree( GetProcessHeap(), 0, fileA
);
1495 /******************************************************************************
1496 * RegRestoreKeyW [ADVAPI32.@]
1499 * hkey [I] Handle of key where restore begins
1500 * lpFile [I] Address of filename containing saved tree
1501 * dwFlags [I] Optional flags
1503 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1505 TRACE("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1507 /* It seems to do this check before the hkey check */
1508 if (!lpFile
|| !*lpFile
)
1509 return ERROR_INVALID_PARAMETER
;
1511 FIXME("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1513 /* Check for file existence */
1515 return ERROR_SUCCESS
;
1519 /******************************************************************************
1520 * RegRestoreKeyA [ADVAPI32.@]
1522 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1524 LPWSTR lpFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile
);
1525 LONG ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1526 HeapFree( GetProcessHeap(), 0, lpFileW
);
1531 /******************************************************************************
1532 * RegUnLoadKeyW [ADVAPI32.@]
1535 * hkey [I] Handle of open key
1536 * lpSubKey [I] Address of name of subkey to unload
1538 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1540 FIXME("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1541 return ERROR_SUCCESS
;
1545 /******************************************************************************
1546 * RegUnLoadKeyA [ADVAPI32.@]
1548 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1550 LPWSTR lpSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey
);
1551 LONG ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
1552 if(lpSubKeyW
) HeapFree( GetProcessHeap(), 0, lpSubKeyW
);
1557 /******************************************************************************
1558 * RegReplaceKeyW [ADVAPI32.@]
1561 * hkey [I] Handle of open key
1562 * lpSubKey [I] Address of name of subkey
1563 * lpNewFile [I] Address of filename for file with new data
1564 * lpOldFile [I] Address of filename for backup file
1566 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1569 FIXME("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1570 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1571 return ERROR_SUCCESS
;
1575 /******************************************************************************
1576 * RegReplaceKeyA [ADVAPI32.@]
1578 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1581 LPWSTR lpSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey
);
1582 LPWSTR lpNewFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile
);
1583 LPWSTR lpOldFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile
);
1584 LONG ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
1585 HeapFree( GetProcessHeap(), 0, lpOldFileW
);
1586 HeapFree( GetProcessHeap(), 0, lpNewFileW
);
1587 HeapFree( GetProcessHeap(), 0, lpSubKeyW
);
1592 /******************************************************************************
1593 * RegSetKeySecurity [ADVAPI32.@]
1596 * hkey [I] Open handle of key to set
1597 * SecurityInfo [I] Descriptor contents
1598 * pSecurityDesc [I] Address of descriptor for key
1600 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1601 PSECURITY_DESCRIPTOR pSecurityDesc
)
1603 TRACE("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1605 /* It seems to perform this check before the hkey check */
1606 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1607 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1608 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1609 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1612 return ERROR_INVALID_PARAMETER
;
1615 return ERROR_INVALID_PARAMETER
;
1617 FIXME(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1619 return ERROR_SUCCESS
;
1623 /******************************************************************************
1624 * RegGetKeySecurity [ADVAPI32.@]
1625 * Retrieves a copy of security descriptor protecting the registry key
1628 * hkey [I] Open handle of key to set
1629 * SecurityInformation [I] Descriptor contents
1630 * pSecurityDescriptor [O] Address of descriptor for key
1631 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1634 * Success: ERROR_SUCCESS
1635 * Failure: Error code
1637 LONG WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
1638 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1639 LPDWORD lpcbSecurityDescriptor
)
1641 TRACE("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1642 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1644 /* FIXME: Check for valid SecurityInformation values */
1646 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1647 return ERROR_INSUFFICIENT_BUFFER
;
1649 FIXME("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1650 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1652 /* Do not leave security descriptor filled with garbage */
1653 RtlCreateSecurityDescriptor(pSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
1655 return ERROR_SUCCESS
;
1659 /******************************************************************************
1660 * RegFlushKey [ADVAPI32.@]
1661 * Immediately writes key to registry.
1662 * Only returns after data has been written to disk.
1664 * FIXME: does it really wait until data is written ?
1667 * hkey [I] Handle of key to write
1670 * Success: ERROR_SUCCESS
1671 * Failure: Error code
1673 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1675 FIXME( "(%x): stub\n", hkey
);
1676 return ERROR_SUCCESS
;
1680 /******************************************************************************
1681 * RegConnectRegistryW [ADVAPI32.@]
1684 * lpMachineName [I] Address of name of remote computer
1685 * hHey [I] Predefined registry handle
1686 * phkResult [I] Address of buffer for remote registry handle
1688 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1691 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1693 if (!lpMachineName
|| !*lpMachineName
) {
1694 /* Use the local machine name */
1695 return RegOpenKeyA( hKey
, "", phkResult
);
1698 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1699 return ERROR_BAD_NETPATH
;
1703 /******************************************************************************
1704 * RegConnectRegistryA [ADVAPI32.@]
1706 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
1708 LPWSTR machineW
= HEAP_strdupAtoW( GetProcessHeap(), 0, machine
);
1709 DWORD ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
1710 HeapFree( GetProcessHeap(), 0, machineW
);
1715 /******************************************************************************
1716 * RegNotifyChangeKeyValue [ADVAPI32.@]
1719 * hkey [I] Handle of key to watch
1720 * fWatchSubTree [I] Flag for subkey notification
1721 * fdwNotifyFilter [I] Changes to be reported
1722 * hEvent [I] Handle of signaled event
1723 * fAsync [I] Flag for asynchronous reporting
1725 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1726 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1729 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1731 return ERROR_SUCCESS
;