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"
41 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
43 /* allowed bits for access mask */
44 #define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
46 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
47 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
48 #define NB_SPECIAL_ROOT_KEYS ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
50 static HKEY special_root_keys
[NB_SPECIAL_ROOT_KEYS
];
52 static const WCHAR name_CLASSES_ROOT
[] =
53 {'M','a','c','h','i','n','e','\\',
54 'S','o','f','t','w','a','r','e','\\',
55 'C','l','a','s','s','e','s',0};
56 static const WCHAR name_LOCAL_MACHINE
[] =
57 {'M','a','c','h','i','n','e',0};
58 static const WCHAR name_USERS
[] =
60 static const WCHAR name_PERFORMANCE_DATA
[] =
61 {'P','e','r','f','D','a','t','a',0};
62 static const WCHAR name_CURRENT_CONFIG
[] =
63 {'M','a','c','h','i','n','e','\\',
64 'S','y','s','t','e','m','\\',
65 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
66 'H','a','r','d','w','a','r','e','P','r','o','f','i','l','e','s','\\',
67 'C','u','r','r','e','n','t',0};
68 static const WCHAR name_DYN_DATA
[] =
69 {'D','y','n','D','a','t','a',0};
71 #define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
72 static UNICODE_STRING root_key_names
[NB_SPECIAL_ROOT_KEYS
] =
74 DECL_STR(CLASSES_ROOT
),
75 { 0, 0, NULL
}, /* HKEY_CURRENT_USER is determined dynamically */
76 DECL_STR(LOCAL_MACHINE
),
78 DECL_STR(PERFORMANCE_DATA
),
79 DECL_STR(CURRENT_CONFIG
),
85 /* check if value type needs string conversion (Ansi<->Unicode) */
86 inline static int is_string( DWORD type
)
88 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
91 /* check if current version is NT or Win95 */
92 inline static int is_version_nt(void)
94 return !(GetVersion() & 0x80000000);
97 /* create one of the HKEY_* special root keys */
98 static HKEY
create_special_root_hkey( HKEY hkey
, DWORD access
)
101 int idx
= (UINT
)hkey
- (UINT
)HKEY_SPECIAL_ROOT_FIRST
;
103 if (hkey
== HKEY_CURRENT_USER
)
105 if (RtlOpenCurrentUser( access
, &hkey
)) return 0;
106 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey
);
110 OBJECT_ATTRIBUTES attr
;
112 attr
.Length
= sizeof(attr
);
113 attr
.RootDirectory
= 0;
114 attr
.ObjectName
= &root_key_names
[idx
];
116 attr
.SecurityDescriptor
= NULL
;
117 attr
.SecurityQualityOfService
= NULL
;
118 if (NtCreateKey( &hkey
, access
, &attr
, 0, NULL
, 0, NULL
)) return 0;
119 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
122 if (!(ret
= InterlockedCompareExchangePointer( (void **)&special_root_keys
[idx
], hkey
, 0 )))
125 NtClose( hkey
); /* somebody beat us to it */
129 /* map the hkey from special root to normal key if necessary */
130 inline static HKEY
get_special_root_hkey( HKEY hkey
)
134 if ((hkey
>= HKEY_SPECIAL_ROOT_FIRST
) && (hkey
<= HKEY_SPECIAL_ROOT_LAST
))
136 if (!(ret
= special_root_keys
[(UINT
)hkey
- (UINT
)HKEY_SPECIAL_ROOT_FIRST
]))
137 ret
= create_special_root_hkey( hkey
, KEY_ALL_ACCESS
);
143 /******************************************************************************
144 * RegCreateKeyExW [ADVAPI32.@]
147 * hkey [I] Handle of an open key
148 * name [I] Address of subkey name
149 * reserved [I] Reserved - must be 0
150 * class [I] Address of class string
151 * options [I] Special options flag
152 * access [I] Desired security access
153 * sa [I] Address of key security structure
154 * retkey [O] Address of buffer for opened handle
155 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
158 * in case of failing retkey remains untouched
160 * FIXME MAXIMUM_ALLOWED in access mask not supported by server
162 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
163 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
164 PHKEY retkey
, LPDWORD dispos
)
166 OBJECT_ATTRIBUTES attr
;
167 UNICODE_STRING nameW
, classW
;
169 if (reserved
) return ERROR_INVALID_PARAMETER
;
170 if (!(access
& KEY_ACCESS_MASK
) || (access
& ~KEY_ACCESS_MASK
)) return ERROR_ACCESS_DENIED
;
171 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
173 attr
.Length
= sizeof(attr
);
174 attr
.RootDirectory
= hkey
;
175 attr
.ObjectName
= &nameW
;
177 attr
.SecurityDescriptor
= NULL
;
178 attr
.SecurityQualityOfService
= NULL
;
179 RtlInitUnicodeString( &nameW
, name
);
180 RtlInitUnicodeString( &classW
, class );
182 return RtlNtStatusToDosError( NtCreateKey( retkey
, access
, &attr
, 0,
183 &classW
, options
, dispos
) );
187 /******************************************************************************
188 * RegCreateKeyExA [ADVAPI32.@]
190 * FIXME MAXIMUM_ALLOWED in access mask not supported by server
192 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
193 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
194 PHKEY retkey
, LPDWORD dispos
)
196 OBJECT_ATTRIBUTES attr
;
197 UNICODE_STRING classW
;
198 ANSI_STRING nameA
, classA
;
201 if (reserved
) return ERROR_INVALID_PARAMETER
;
202 if (!is_version_nt()) access
= KEY_ALL_ACCESS
; /* Win95 ignores the access mask */
203 else if (!(access
& KEY_ACCESS_MASK
) || (access
& ~KEY_ACCESS_MASK
)) return ERROR_ACCESS_DENIED
;
204 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
206 attr
.Length
= sizeof(attr
);
207 attr
.RootDirectory
= hkey
;
208 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
210 attr
.SecurityDescriptor
= NULL
;
211 attr
.SecurityQualityOfService
= NULL
;
212 RtlInitAnsiString( &nameA
, name
);
213 RtlInitAnsiString( &classA
, class );
215 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
218 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
220 status
= NtCreateKey( retkey
, access
, &attr
, 0, &classW
, options
, dispos
);
221 RtlFreeUnicodeString( &classW
);
224 return RtlNtStatusToDosError( status
);
228 /******************************************************************************
229 * RegCreateKeyW [ADVAPI32.@]
231 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR name
, PHKEY retkey
)
233 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
234 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
235 return RegCreateKeyExW( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
236 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
240 /******************************************************************************
241 * RegCreateKeyA [ADVAPI32.@]
243 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR name
, PHKEY retkey
)
245 return RegCreateKeyExA( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
246 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
251 /******************************************************************************
252 * RegOpenKeyExW [ADVAPI32.@]
254 * Opens the specified key
256 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
259 * hkey [I] Handle of open key
260 * name [I] Name of subkey to open
261 * reserved [I] Reserved - must be zero
262 * access [I] Security access mask
263 * retkey [O] Handle to open key
266 * Success: ERROR_SUCCESS
267 * Failure: Error code
270 * in case of failing is retkey = 0
272 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, REGSAM access
, PHKEY retkey
)
274 OBJECT_ATTRIBUTES attr
;
275 UNICODE_STRING nameW
;
277 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
279 attr
.Length
= sizeof(attr
);
280 attr
.RootDirectory
= hkey
;
281 attr
.ObjectName
= &nameW
;
283 attr
.SecurityDescriptor
= NULL
;
284 attr
.SecurityQualityOfService
= NULL
;
285 RtlInitUnicodeString( &nameW
, name
);
286 return RtlNtStatusToDosError( NtOpenKey( retkey
, access
, &attr
) );
290 /******************************************************************************
291 * RegOpenKeyExA [ADVAPI32.@]
293 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, REGSAM access
, PHKEY retkey
)
295 OBJECT_ATTRIBUTES attr
;
299 if (!is_version_nt()) access
= KEY_ALL_ACCESS
; /* Win95 ignores the access mask */
301 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
303 attr
.Length
= sizeof(attr
);
304 attr
.RootDirectory
= hkey
;
305 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
307 attr
.SecurityDescriptor
= NULL
;
308 attr
.SecurityQualityOfService
= NULL
;
310 RtlInitAnsiString( &nameA
, name
);
311 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
314 status
= NtOpenKey( retkey
, access
, &attr
);
316 return RtlNtStatusToDosError( status
);
320 /******************************************************************************
321 * RegOpenKeyW [ADVAPI32.@]
324 * hkey [I] Handle of open key
325 * name [I] Address of name of subkey to open
326 * retkey [O] Handle to open key
329 * Success: ERROR_SUCCESS
330 * Failure: Error code
333 * in case of failing is retkey = 0
335 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, PHKEY retkey
)
337 return RegOpenKeyExW( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
341 /******************************************************************************
342 * RegOpenKeyA [ADVAPI32.@]
344 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, PHKEY retkey
)
346 return RegOpenKeyExA( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
350 /******************************************************************************
351 * RegOpenCurrentUser [ADVAPI32.@]
352 * FIXME: This function is supposed to retrieve a handle to the
353 * HKEY_CURRENT_USER for the user the current thread is impersonating.
354 * Since Wine does not currently allow threads to impersonate other users,
355 * this stub should work fine.
357 DWORD WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
359 return RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
364 /******************************************************************************
365 * RegEnumKeyExW [ADVAPI32.@]
368 * hkey [I] Handle to key to enumerate
369 * index [I] Index of subkey to enumerate
370 * name [O] Buffer for subkey name
371 * name_len [O] Size of subkey buffer
372 * reserved [I] Reserved
373 * class [O] Buffer for class string
374 * class_len [O] Size of class buffer
375 * ft [O] Time key last written to
377 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
378 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
381 char buffer
[256], *buf_ptr
= buffer
;
382 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
385 TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
386 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
388 if (reserved
) return ERROR_INVALID_PARAMETER
;
389 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
391 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
392 buffer
, sizeof(buffer
), &total_size
);
394 while (status
== STATUS_BUFFER_OVERFLOW
)
396 /* retry with a dynamically allocated buffer */
397 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
398 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
399 return ERROR_NOT_ENOUGH_MEMORY
;
400 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
401 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
402 buf_ptr
, total_size
, &total_size
);
407 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
408 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
410 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
412 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
413 status
= STATUS_BUFFER_OVERFLOW
;
417 memcpy( name
, info
->Name
, info
->NameLength
);
421 *class_len
= cls_len
;
424 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
431 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
432 return RtlNtStatusToDosError( status
);
436 /******************************************************************************
437 * RegEnumKeyExA [ADVAPI32.@]
439 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
440 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
443 char buffer
[256], *buf_ptr
= buffer
;
444 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
447 TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
448 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
450 if (reserved
) return ERROR_INVALID_PARAMETER
;
451 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
453 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
454 buffer
, sizeof(buffer
), &total_size
);
456 while (status
== STATUS_BUFFER_OVERFLOW
)
458 /* retry with a dynamically allocated buffer */
459 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
460 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
461 return ERROR_NOT_ENOUGH_MEMORY
;
462 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
463 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
464 buf_ptr
, total_size
, &total_size
);
471 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
472 RtlUnicodeToMultiByteSize( &cls_len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
474 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
476 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
477 status
= STATUS_BUFFER_OVERFLOW
;
481 RtlUnicodeToMultiByteN( name
, len
, NULL
, info
->Name
, info
->NameLength
);
485 *class_len
= cls_len
;
488 RtlUnicodeToMultiByteN( class, cls_len
, NULL
,
489 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
497 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
498 return RtlNtStatusToDosError( status
);
502 /******************************************************************************
503 * RegEnumKeyW [ADVAPI32.@]
505 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
507 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
511 /******************************************************************************
512 * RegEnumKeyA [ADVAPI32.@]
514 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
516 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
520 /******************************************************************************
521 * RegQueryInfoKeyW [ADVAPI32.@]
524 * hkey [I] Handle to key to query
525 * class [O] Buffer for class string
526 * class_len [O] Size of class string buffer
527 * reserved [I] Reserved
528 * subkeys [O] Buffer for number of subkeys
529 * max_subkey [O] Buffer for longest subkey name length
530 * max_class [O] Buffer for longest class string length
531 * values [O] Buffer for number of value entries
532 * max_value [O] Buffer for longest value name length
533 * max_data [O] Buffer for longest value data length
534 * security [O] Buffer for security descriptor length
535 * modif [O] Modification time
537 * - win95 allows class to be valid and class_len to be NULL
538 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
539 * - both allow class to be NULL and class_len to be NULL
540 * (it's hard to test validity, so test !NULL instead)
542 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
543 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
544 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
545 LPDWORD security
, FILETIME
*modif
)
548 char buffer
[256], *buf_ptr
= buffer
;
549 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
552 TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
553 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
555 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
556 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
558 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
559 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
563 /* retry with a dynamically allocated buffer */
564 while (status
== STATUS_BUFFER_OVERFLOW
)
566 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
567 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
568 return ERROR_NOT_ENOUGH_MEMORY
;
569 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
570 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
573 if (status
) goto done
;
575 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
577 status
= STATUS_BUFFER_OVERFLOW
;
581 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
582 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
585 else status
= STATUS_SUCCESS
;
587 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
588 if (subkeys
) *subkeys
= info
->SubKeys
;
589 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
590 if (max_class
) *max_class
= info
->MaxClassLen
;
591 if (values
) *values
= info
->Values
;
592 if (max_value
) *max_value
= info
->MaxValueNameLen
;
593 if (max_data
) *max_data
= info
->MaxValueDataLen
;
594 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
597 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
598 return RtlNtStatusToDosError( status
);
602 /******************************************************************************
603 * RegQueryMultipleValuesA [ADVAPI32.@]
605 DWORD WINAPI
RegQueryMultipleValuesA(HKEY hkey
, PVALENTA val_list
, DWORD num_vals
,
606 LPSTR lpValueBuf
, LPDWORD ldwTotsize
)
609 DWORD maxBytes
= *ldwTotsize
;
611 LPSTR bufptr
= lpValueBuf
;
614 TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
616 for(i
=0; i
< num_vals
; ++i
)
619 val_list
[i
].ve_valuelen
=0;
620 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
621 if(status
!= ERROR_SUCCESS
)
626 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
628 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
629 bufptr
, &val_list
[i
].ve_valuelen
);
630 if(status
!= ERROR_SUCCESS
)
635 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
637 bufptr
+= val_list
[i
].ve_valuelen
;
640 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
642 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
646 /******************************************************************************
647 * RegQueryMultipleValuesW [ADVAPI32.@]
649 DWORD WINAPI
RegQueryMultipleValuesW(HKEY hkey
, PVALENTW val_list
, DWORD num_vals
,
650 LPWSTR lpValueBuf
, LPDWORD ldwTotsize
)
653 DWORD maxBytes
= *ldwTotsize
;
655 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
658 TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
660 for(i
=0; i
< num_vals
; ++i
)
662 val_list
[i
].ve_valuelen
=0;
663 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
664 if(status
!= ERROR_SUCCESS
)
669 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
671 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
672 bufptr
, &val_list
[i
].ve_valuelen
);
673 if(status
!= ERROR_SUCCESS
)
678 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
680 bufptr
+= val_list
[i
].ve_valuelen
;
683 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
685 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
688 /******************************************************************************
689 * RegQueryInfoKeyA [ADVAPI32.@]
691 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
692 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
693 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
694 LPDWORD security
, FILETIME
*modif
)
697 char buffer
[256], *buf_ptr
= buffer
;
698 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
699 DWORD total_size
, len
;
701 TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
702 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
704 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
705 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
707 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
708 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
710 if (class || class_len
)
712 /* retry with a dynamically allocated buffer */
713 while (status
== STATUS_BUFFER_OVERFLOW
)
715 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
716 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
717 return ERROR_NOT_ENOUGH_MEMORY
;
718 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
719 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
722 if (status
) goto done
;
724 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
), info
->ClassLength
);
727 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
730 if (class && !status
)
732 RtlUnicodeToMultiByteN( class, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
737 else status
= STATUS_SUCCESS
;
739 if (subkeys
) *subkeys
= info
->SubKeys
;
740 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
741 if (max_class
) *max_class
= info
->MaxClassLen
;
742 if (values
) *values
= info
->Values
;
743 if (max_value
) *max_value
= info
->MaxValueNameLen
;
744 if (max_data
) *max_data
= info
->MaxValueDataLen
;
745 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
748 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
749 return RtlNtStatusToDosError( status
);
753 /******************************************************************************
754 * RegCloseKey [ADVAPI32.@]
756 * Releases the handle of the specified key
759 * hkey [I] Handle of key to close
762 * Success: ERROR_SUCCESS
763 * Failure: Error code
765 DWORD WINAPI
RegCloseKey( HKEY hkey
)
767 if (!hkey
|| hkey
>= (HKEY
)0x80000000) return ERROR_SUCCESS
;
768 return RtlNtStatusToDosError( NtClose( hkey
) );
772 /******************************************************************************
773 * RegDeleteKeyW [ADVAPI32.@]
776 * hkey [I] Handle to open key
777 * name [I] Name of subkey to delete
780 * Success: ERROR_SUCCESS
781 * Failure: Error code
783 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
788 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
792 ret
= RtlNtStatusToDosError( NtDeleteKey( hkey
) );
794 else if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, KEY_ENUMERATE_SUB_KEYS
, &tmp
)))
796 if (!is_version_nt()) /* win95 does recursive key deletes */
798 WCHAR name
[MAX_PATH
];
800 while(!RegEnumKeyW(tmp
, 0, name
, sizeof name
))
802 if(RegDeleteKeyW(tmp
, name
)) /* recurse */
806 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
809 TRACE("%s ret=%08lx\n", debugstr_w(name
), ret
);
814 /******************************************************************************
815 * RegDeleteKeyA [ADVAPI32.@]
817 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
822 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
826 ret
= RtlNtStatusToDosError( NtDeleteKey( hkey
) );
828 else if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, KEY_ENUMERATE_SUB_KEYS
, &tmp
)))
830 if (!is_version_nt()) /* win95 does recursive key deletes */
834 while(!RegEnumKeyA(tmp
, 0, name
, sizeof name
))
836 if(RegDeleteKeyA(tmp
, name
)) /* recurse */
840 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
843 TRACE("%s ret=%08lx\n", debugstr_a(name
), ret
);
849 /******************************************************************************
850 * RegSetValueExW [ADVAPI32.@]
852 * Sets the data and type of a value under a register key
855 * hkey [I] Handle of key to set value for
856 * name [I] Name of value to set
857 * reserved [I] Reserved - must be zero
858 * type [I] Flag for value type
859 * data [I] Address of value data
860 * count [I] Size of value data
863 * Success: ERROR_SUCCESS
864 * Failure: Error code
867 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
868 * NT does definitely care (aj)
870 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
871 DWORD type
, CONST BYTE
*data
, DWORD count
)
873 UNICODE_STRING nameW
;
875 if (!is_version_nt()) /* win95 */
877 if (type
== REG_SZ
) count
= (strlenW( (WCHAR
*)data
) + 1) * sizeof(WCHAR
);
879 else if (count
&& is_string(type
))
881 LPCWSTR str
= (LPCWSTR
)data
;
882 /* if user forgot to count terminating null, add it (yes NT does this) */
883 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
884 count
+= sizeof(WCHAR
);
886 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
888 RtlInitUnicodeString( &nameW
, name
);
889 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
893 /******************************************************************************
894 * RegSetValueExA [ADVAPI32.@]
896 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
897 CONST BYTE
*data
, DWORD count
)
903 if (!is_version_nt()) /* win95 */
905 if (type
== REG_SZ
) count
= strlen(data
) + 1;
907 else if (count
&& is_string(type
))
909 /* if user forgot to count terminating null, add it (yes NT does this) */
910 if (data
[count
-1] && !data
[count
]) count
++;
913 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
915 if (is_string( type
)) /* need to convert to Unicode */
918 RtlMultiByteToUnicodeSize( &lenW
, data
, count
);
919 if (!(dataW
= HeapAlloc( GetProcessHeap(), 0, lenW
))) return ERROR_OUTOFMEMORY
;
920 RtlMultiByteToUnicodeN( dataW
, lenW
, NULL
, data
, count
);
922 data
= (BYTE
*)dataW
;
925 RtlInitAnsiString( &nameA
, name
);
926 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
929 status
= NtSetValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
, 0, type
, data
, count
);
931 if (dataW
) HeapFree( GetProcessHeap(), 0, dataW
);
932 return RtlNtStatusToDosError( status
);
936 /******************************************************************************
937 * RegSetValueW [ADVAPI32.@]
939 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR name
, DWORD type
, LPCWSTR data
, DWORD count
)
944 TRACE("(%p,%s,%ld,%s,%ld)\n", hkey
, debugstr_w(name
), type
, debugstr_w(data
), count
);
946 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
948 if (name
&& name
[0]) /* need to create the subkey */
950 if ((ret
= RegCreateKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
953 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
,
954 (strlenW( data
) + 1) * sizeof(WCHAR
) );
955 if (subkey
!= hkey
) RegCloseKey( subkey
);
960 /******************************************************************************
961 * RegSetValueA [ADVAPI32.@]
963 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
968 TRACE("(%p,%s,%ld,%s,%ld)\n", hkey
, debugstr_a(name
), type
, debugstr_a(data
), count
);
970 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
972 if (name
&& name
[0]) /* need to create the subkey */
974 if ((ret
= RegCreateKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
976 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
, strlen(data
)+1 );
977 if (subkey
!= hkey
) RegCloseKey( subkey
);
983 /******************************************************************************
984 * RegQueryValueExW [ADVAPI32.@]
986 * Retrieves type and data for a specified name associated with an open key
989 * hkey [I] Handle of key to query
990 * name [I] Name of value to query
991 * reserved [I] Reserved - must be NULL
992 * type [O] Address of buffer for value type. If NULL, the type
994 * data [O] Address of data buffer. If NULL, the actual data is
996 * count [I/O] Address of data buffer size
999 * ERROR_SUCCESS: Success
1000 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
1001 * buffer is left untouched. The MS-documentation is wrong (js) !!!
1003 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
1004 LPBYTE data
, LPDWORD count
)
1007 UNICODE_STRING name_str
;
1009 char buffer
[256], *buf_ptr
= buffer
;
1010 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1011 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1013 TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1014 hkey
, debugstr_w(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
1016 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1017 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1019 RtlInitUnicodeString( &name_str
, name
);
1021 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
1022 else total_size
= info_size
;
1024 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1025 buffer
, total_size
, &total_size
);
1026 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1030 /* retry with a dynamically allocated buffer */
1031 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
1033 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1034 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1035 return ERROR_NOT_ENOUGH_MEMORY
;
1036 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1037 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1038 buf_ptr
, total_size
, &total_size
);
1043 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1044 /* if the type is REG_SZ and data is not 0-terminated
1045 * and there is enough space in the buffer NT appends a \0 */
1046 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1048 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
1049 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1052 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1054 else status
= STATUS_SUCCESS
;
1056 if (type
) *type
= info
->Type
;
1057 if (count
) *count
= total_size
- info_size
;
1060 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1061 return RtlNtStatusToDosError(status
);
1065 /******************************************************************************
1066 * RegQueryValueExA [ADVAPI32.@]
1069 * the documentation is wrong: if the buffer is too small it remains untouched
1071 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1072 LPBYTE data
, LPDWORD count
)
1077 char buffer
[256], *buf_ptr
= buffer
;
1078 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1079 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1081 TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1082 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
1084 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1085 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1087 RtlInitAnsiString( &nameA
, name
);
1088 if ((status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
1090 return RtlNtStatusToDosError(status
);
1092 status
= NtQueryValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
,
1093 KeyValuePartialInformation
, buffer
, sizeof(buffer
), &total_size
);
1094 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1096 /* we need to fetch the contents for a string type even if not requested,
1097 * because we need to compute the length of the ASCII string. */
1098 if (data
|| is_string(info
->Type
))
1100 /* retry with a dynamically allocated buffer */
1101 while (status
== STATUS_BUFFER_OVERFLOW
)
1103 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1104 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1106 status
= STATUS_NO_MEMORY
;
1109 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1110 status
= NtQueryValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
,
1111 KeyValuePartialInformation
, buf_ptr
, total_size
, &total_size
);
1114 if (status
) goto done
;
1116 if (is_string(info
->Type
))
1120 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
1121 total_size
- info_size
);
1124 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1127 RtlUnicodeToMultiByteN( data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
1128 total_size
- info_size
);
1129 /* if the type is REG_SZ and data is not 0-terminated
1130 * and there is enough space in the buffer NT appends a \0 */
1131 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1134 total_size
= len
+ info_size
;
1138 if (total_size
- info_size
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1139 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1142 else status
= STATUS_SUCCESS
;
1144 if (type
) *type
= info
->Type
;
1145 if (count
) *count
= total_size
- info_size
;
1148 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1149 return RtlNtStatusToDosError(status
);
1153 /******************************************************************************
1154 * RegQueryValueW [ADVAPI32.@]
1156 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
1161 TRACE("(%p,%s,%p,%ld)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
1163 if (name
&& name
[0])
1165 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1167 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
1168 if (subkey
!= hkey
) RegCloseKey( subkey
);
1169 if (ret
== ERROR_FILE_NOT_FOUND
)
1171 /* return empty string if default value not found */
1172 if (data
) *data
= 0;
1173 if (count
) *count
= 1;
1174 ret
= ERROR_SUCCESS
;
1180 /******************************************************************************
1181 * RegQueryValueA [ADVAPI32.@]
1183 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
1188 TRACE("(%p,%s,%p,%ld)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
1190 if (name
&& name
[0])
1192 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1194 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
1195 if (subkey
!= hkey
) RegCloseKey( subkey
);
1196 if (ret
== ERROR_FILE_NOT_FOUND
)
1198 /* return empty string if default value not found */
1199 if (data
) *data
= 0;
1200 if (count
) *count
= 1;
1201 ret
= ERROR_SUCCESS
;
1207 /******************************************************************************
1208 * RegEnumValueW [ADVAPI32.@]
1211 * hkey [I] Handle to key to query
1212 * index [I] Index of value to query
1213 * value [O] Value string
1214 * val_count [I/O] Size of value buffer (in wchars)
1215 * reserved [I] Reserved
1216 * type [O] Type code
1217 * data [O] Value data
1218 * count [I/O] Size of data buffer (in bytes)
1221 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
1222 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1226 char buffer
[256], *buf_ptr
= buffer
;
1227 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1228 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1230 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1231 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1233 /* NT only checks count, not val_count */
1234 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1235 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1237 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1238 if (data
) total_size
+= *count
;
1239 total_size
= min( sizeof(buffer
), total_size
);
1241 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1242 buffer
, total_size
, &total_size
);
1243 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1247 /* retry with a dynamically allocated buffer */
1248 while (status
== STATUS_BUFFER_OVERFLOW
)
1250 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1251 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1252 return ERROR_NOT_ENOUGH_MEMORY
;
1253 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1254 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1255 buf_ptr
, total_size
, &total_size
);
1258 if (status
) goto done
;
1262 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
1264 status
= STATUS_BUFFER_OVERFLOW
;
1267 memcpy( value
, info
->Name
, info
->NameLength
);
1268 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
1269 value
[*val_count
] = 0;
1274 if (total_size
- info
->DataOffset
> *count
)
1276 status
= STATUS_BUFFER_OVERFLOW
;
1279 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1280 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1282 /* if the type is REG_SZ and data is not 0-terminated
1283 * and there is enough space in the buffer NT appends a \0 */
1284 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
1285 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1289 else status
= STATUS_SUCCESS
;
1292 if (type
) *type
= info
->Type
;
1293 if (count
) *count
= info
->DataLength
;
1296 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1297 return RtlNtStatusToDosError(status
);
1301 /******************************************************************************
1302 * RegEnumValueA [ADVAPI32.@]
1304 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1305 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1309 char buffer
[256], *buf_ptr
= buffer
;
1310 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1311 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1313 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1314 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1316 /* NT only checks count, not val_count */
1317 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1318 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1320 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1321 if (data
) total_size
+= *count
;
1322 total_size
= min( sizeof(buffer
), total_size
);
1324 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1325 buffer
, total_size
, &total_size
);
1326 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1328 /* we need to fetch the contents for a string type even if not requested,
1329 * because we need to compute the length of the ASCII string. */
1330 if (value
|| data
|| is_string(info
->Type
))
1332 /* retry with a dynamically allocated buffer */
1333 while (status
== STATUS_BUFFER_OVERFLOW
)
1335 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1336 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1337 return ERROR_NOT_ENOUGH_MEMORY
;
1338 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1339 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1340 buf_ptr
, total_size
, &total_size
);
1343 if (status
) goto done
;
1345 if (is_string(info
->Type
))
1348 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1349 total_size
- info
->DataOffset
);
1352 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1355 RtlUnicodeToMultiByteN( data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1356 total_size
- info
->DataOffset
);
1357 /* if the type is REG_SZ and data is not 0-terminated
1358 * and there is enough space in the buffer NT appends a \0 */
1359 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1362 info
->DataLength
= len
;
1366 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1367 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1370 if (value
&& !status
)
1374 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
1375 if (len
>= *val_count
)
1377 status
= STATUS_BUFFER_OVERFLOW
;
1380 len
= *val_count
- 1;
1381 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1387 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1393 else status
= STATUS_SUCCESS
;
1395 if (type
) *type
= info
->Type
;
1396 if (count
) *count
= info
->DataLength
;
1399 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1400 return RtlNtStatusToDosError(status
);
1405 /******************************************************************************
1406 * RegDeleteValueW [ADVAPI32.@]
1408 * See RegDeleteValueA.
1410 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
1412 UNICODE_STRING nameW
;
1414 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1416 RtlInitUnicodeString( &nameW
, name
);
1417 return RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
1421 /******************************************************************************
1422 * RegDeleteValueA [ADVAPI32.@]
1424 * Delete a value from the registry.
1427 * hkey [I] Registry handle of the key holding the value
1428 * name [I] Name of the value under hkey to delete
1432 * Failure: A standard Windows error code.
1434 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
1439 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1441 RtlInitAnsiString( &nameA
, name
);
1442 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
1444 status
= NtDeleteValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
);
1445 return RtlNtStatusToDosError( status
);
1449 /******************************************************************************
1450 * RegLoadKeyW [ADVAPI32.@]
1453 * hkey [I] Handle of open key
1454 * subkey [I] Address of name of subkey
1455 * filename [I] Address of filename for registry information
1457 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
1460 DWORD ret
, len
, err
= GetLastError();
1463 TRACE( "(%p,%s,%s)\n", hkey
, debugstr_w(subkey
), debugstr_w(filename
) );
1465 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1466 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1467 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1469 len
= strlenW( subkey
) * sizeof(WCHAR
);
1470 if (len
> MAX_PATH
*sizeof(WCHAR
)) return ERROR_INVALID_PARAMETER
;
1472 if ((file
= CreateFileW( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1473 FILE_ATTRIBUTE_NORMAL
, 0 )) == INVALID_HANDLE_VALUE
)
1475 ret
= GetLastError();
1479 RegCreateKeyW(hkey
,subkey
,&shkey
);
1481 SERVER_START_REQ( load_registry
)
1485 wine_server_add_data( req
, subkey
, len
);
1486 ret
= RtlNtStatusToDosError( wine_server_call(req
) );
1489 CloseHandle( file
);
1493 SetLastError( err
); /* restore the last error code */
1498 /******************************************************************************
1499 * RegLoadKeyA [ADVAPI32.@]
1501 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
1503 WCHAR buffer
[MAX_PATH
];
1505 DWORD ret
, len
, err
= GetLastError();
1508 TRACE( "(%p,%s,%s)\n", hkey
, debugstr_a(subkey
), debugstr_a(filename
) );
1510 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1511 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1512 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1514 if (!(len
= MultiByteToWideChar( CP_ACP
, 0, subkey
, strlen(subkey
), buffer
, MAX_PATH
)))
1515 return ERROR_INVALID_PARAMETER
;
1517 if ((file
= CreateFileA( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1518 FILE_ATTRIBUTE_NORMAL
, 0 )) == INVALID_HANDLE_VALUE
)
1520 ret
= GetLastError();
1524 RegCreateKeyA(hkey
,subkey
,&shkey
);
1526 SERVER_START_REQ( load_registry
)
1530 wine_server_add_data( req
, buffer
, len
* sizeof(WCHAR
) );
1531 ret
= RtlNtStatusToDosError( wine_server_call(req
) );
1534 CloseHandle( file
);
1538 SetLastError( err
); /* restore the last error code */
1543 /******************************************************************************
1544 * RegSaveKeyW [ADVAPI32.@]
1547 * hkey [I] Handle of key where save begins
1548 * lpFile [I] Address of filename to save to
1549 * sa [I] Address of security structure
1551 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
1553 static const WCHAR format
[] =
1554 {'r','e','g','%','0','4','x','.','t','m','p',0};
1555 WCHAR buffer
[MAX_PATH
];
1561 TRACE( "(%p,%s,%p)\n", hkey
, debugstr_w(file
), sa
);
1563 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
1564 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1566 err
= GetLastError();
1567 GetFullPathNameW( file
, sizeof(buffer
)/sizeof(WCHAR
), buffer
, &nameW
);
1571 snprintfW( nameW
, 16, format
, count
++ );
1572 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
1573 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
1574 if (handle
!= INVALID_HANDLE_VALUE
) break;
1575 if ((ret
= GetLastError()) != ERROR_ALREADY_EXISTS
) goto done
;
1577 /* Something gone haywire ? Please report if this happens abnormally */
1579 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", debugstr_w(buffer
), count
);
1582 SERVER_START_REQ( save_registry
)
1586 ret
= RtlNtStatusToDosError( wine_server_call( req
) );
1590 CloseHandle( handle
);
1593 if (!MoveFileExW( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
1595 ERR( "Failed to move %s to %s\n", debugstr_w(buffer
),
1597 ret
= GetLastError();
1600 if (ret
) DeleteFileW( buffer
);
1603 SetLastError( err
); /* restore last error code */
1608 /******************************************************************************
1609 * RegSaveKeyA [ADVAPI32.@]
1611 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
1613 UNICODE_STRING
*fileW
= &NtCurrentTeb()->StaticUnicodeString
;
1617 RtlInitAnsiString(&fileA
, file
);
1618 if ((status
= RtlAnsiStringToUnicodeString(fileW
, &fileA
, FALSE
)))
1619 return RtlNtStatusToDosError( status
);
1620 return RegSaveKeyW(hkey
, fileW
->Buffer
, sa
);
1624 /******************************************************************************
1625 * RegRestoreKeyW [ADVAPI32.@]
1628 * hkey [I] Handle of key where restore begins
1629 * lpFile [I] Address of filename containing saved tree
1630 * dwFlags [I] Optional flags
1632 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1634 TRACE("(%p,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1636 /* It seems to do this check before the hkey check */
1637 if (!lpFile
|| !*lpFile
)
1638 return ERROR_INVALID_PARAMETER
;
1640 FIXME("(%p,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1642 /* Check for file existence */
1644 return ERROR_SUCCESS
;
1648 /******************************************************************************
1649 * RegRestoreKeyA [ADVAPI32.@]
1651 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1653 UNICODE_STRING lpFileW
;
1656 RtlCreateUnicodeStringFromAsciiz( &lpFileW
, lpFile
);
1657 ret
= RegRestoreKeyW( hkey
, lpFileW
.Buffer
, dwFlags
);
1658 RtlFreeUnicodeString( &lpFileW
);
1663 /******************************************************************************
1664 * RegUnLoadKeyW [ADVAPI32.@]
1667 * hkey [I] Handle of open key
1668 * lpSubKey [I] Address of name of subkey to unload
1670 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1672 FIXME("(%p,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1673 return ERROR_SUCCESS
;
1677 /******************************************************************************
1678 * RegUnLoadKeyA [ADVAPI32.@]
1680 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1682 UNICODE_STRING lpSubKeyW
;
1685 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
1686 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
.Buffer
);
1687 RtlFreeUnicodeString( &lpSubKeyW
);
1692 /******************************************************************************
1693 * RegReplaceKeyW [ADVAPI32.@]
1696 * hkey [I] Handle of open key
1697 * lpSubKey [I] Address of name of subkey
1698 * lpNewFile [I] Address of filename for file with new data
1699 * lpOldFile [I] Address of filename for backup file
1701 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1704 FIXME("(%p,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1705 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1706 return ERROR_SUCCESS
;
1710 /******************************************************************************
1711 * RegReplaceKeyA [ADVAPI32.@]
1713 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1716 UNICODE_STRING lpSubKeyW
;
1717 UNICODE_STRING lpNewFileW
;
1718 UNICODE_STRING lpOldFileW
;
1721 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
1722 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW
, lpOldFile
);
1723 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW
, lpNewFile
);
1724 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
.Buffer
, lpNewFileW
.Buffer
, lpOldFileW
.Buffer
);
1725 RtlFreeUnicodeString( &lpOldFileW
);
1726 RtlFreeUnicodeString( &lpNewFileW
);
1727 RtlFreeUnicodeString( &lpSubKeyW
);
1732 /******************************************************************************
1733 * RegSetKeySecurity [ADVAPI32.@]
1736 * hkey [I] Open handle of key to set
1737 * SecurityInfo [I] Descriptor contents
1738 * pSecurityDesc [I] Address of descriptor for key
1740 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1741 PSECURITY_DESCRIPTOR pSecurityDesc
)
1743 TRACE("(%p,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1745 /* It seems to perform this check before the hkey check */
1746 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1747 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1748 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1749 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1752 return ERROR_INVALID_PARAMETER
;
1755 return ERROR_INVALID_PARAMETER
;
1757 FIXME(":(%p,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1759 return ERROR_SUCCESS
;
1763 /******************************************************************************
1764 * RegGetKeySecurity [ADVAPI32.@]
1765 * Retrieves a copy of security descriptor protecting the registry key
1768 * hkey [I] Open handle of key to set
1769 * SecurityInformation [I] Descriptor contents
1770 * pSecurityDescriptor [O] Address of descriptor for key
1771 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1774 * Success: ERROR_SUCCESS
1775 * Failure: Error code
1777 LONG WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
1778 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1779 LPDWORD lpcbSecurityDescriptor
)
1781 TRACE("(%p,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1782 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1784 /* FIXME: Check for valid SecurityInformation values */
1786 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1787 return ERROR_INSUFFICIENT_BUFFER
;
1789 FIXME("(%p,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1790 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1792 /* Do not leave security descriptor filled with garbage */
1793 RtlCreateSecurityDescriptor(pSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
1795 return ERROR_SUCCESS
;
1799 /******************************************************************************
1800 * RegFlushKey [ADVAPI32.@]
1801 * Immediately writes key to registry.
1802 * Only returns after data has been written to disk.
1804 * FIXME: does it really wait until data is written ?
1807 * hkey [I] Handle of key to write
1810 * Success: ERROR_SUCCESS
1811 * Failure: Error code
1813 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1815 FIXME( "(%p): stub\n", hkey
);
1816 return ERROR_SUCCESS
;
1820 /******************************************************************************
1821 * RegConnectRegistryW [ADVAPI32.@]
1824 * lpMachineName [I] Address of name of remote computer
1825 * hHey [I] Predefined registry handle
1826 * phkResult [I] Address of buffer for remote registry handle
1828 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1831 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1833 if (!lpMachineName
|| !*lpMachineName
) {
1834 /* Use the local machine name */
1835 return RegOpenKeyW( hKey
, NULL
, phkResult
);
1838 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1839 return ERROR_BAD_NETPATH
;
1843 /******************************************************************************
1844 * RegConnectRegistryA [ADVAPI32.@]
1846 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, PHKEY reskey
)
1848 UNICODE_STRING machineW
;
1851 RtlCreateUnicodeStringFromAsciiz( &machineW
, machine
);
1852 ret
= RegConnectRegistryW( machineW
.Buffer
, hkey
, reskey
);
1853 RtlFreeUnicodeString( &machineW
);
1858 /******************************************************************************
1859 * RegNotifyChangeKeyValue [ADVAPI32.@]
1862 * hkey [I] Handle of key to watch
1863 * fWatchSubTree [I] Flag for subkey notification
1864 * fdwNotifyFilter [I] Changes to be reported
1865 * hEvent [I] Handle of signaled event
1866 * fAsync [I] Flag for asynchronous reporting
1868 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1869 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1874 TRACE("(%p,%i,%ld,%p,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1878 hEvent
= CreateEventA(NULL
, 0, 0, NULL
);
1880 SERVER_START_REQ( set_registry_notification
)
1883 req
->event
= hEvent
;
1884 req
->subtree
= fWatchSubTree
;
1885 req
->filter
= fdwNotifyFilter
;
1886 ret
= RtlNtStatusToDosError( wine_server_call(req
) );
1892 if( ret
== ERROR_SUCCESS
)
1893 WaitForSingleObject( hEvent
, INFINITE
);
1894 CloseHandle( hEvent
);