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
);
42 /* allowed bits for access mask */
43 #define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
45 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
46 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
47 #define NB_SPECIAL_ROOT_KEYS ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
49 static HKEY special_root_keys
[NB_SPECIAL_ROOT_KEYS
];
51 static const WCHAR name_CLASSES_ROOT
[] =
52 {'M','a','c','h','i','n','e','\\',
53 'S','o','f','t','w','a','r','e','\\',
54 'C','l','a','s','s','e','s',0};
55 static const WCHAR name_LOCAL_MACHINE
[] =
56 {'M','a','c','h','i','n','e',0};
57 static const WCHAR name_USERS
[] =
59 static const WCHAR name_PERFORMANCE_DATA
[] =
60 {'P','e','r','f','D','a','t','a',0};
61 static const WCHAR name_CURRENT_CONFIG
[] =
62 {'M','a','c','h','i','n','e','\\',
63 'S','y','s','t','e','m','\\',
64 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
65 'H','a','r','d','w','a','r','e','P','r','o','f','i','l','e','s','\\',
66 'C','u','r','r','e','n','t',0};
67 static const WCHAR name_DYN_DATA
[] =
68 {'D','y','n','D','a','t','a',0};
70 #define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
71 static UNICODE_STRING root_key_names
[NB_SPECIAL_ROOT_KEYS
] =
73 DECL_STR(CLASSES_ROOT
),
74 { 0, 0, NULL
}, /* HKEY_CURRENT_USER is determined dynamically */
75 DECL_STR(LOCAL_MACHINE
),
77 DECL_STR(PERFORMANCE_DATA
),
78 DECL_STR(CURRENT_CONFIG
),
84 /* check if value type needs string conversion (Ansi<->Unicode) */
85 inline static int is_string( DWORD type
)
87 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
90 /* check if current version is NT or Win95 */
91 inline static int is_version_nt(void)
93 return !(GetVersion() & 0x80000000);
96 /* create one of the HKEY_* special root keys */
97 static HKEY
create_special_root_hkey( HKEY hkey
, DWORD access
)
100 int idx
= (UINT
)hkey
- (UINT
)HKEY_SPECIAL_ROOT_FIRST
;
102 if (hkey
== HKEY_CURRENT_USER
)
104 if (RtlOpenCurrentUser( access
, &hkey
)) return 0;
105 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey
);
109 OBJECT_ATTRIBUTES attr
;
111 attr
.Length
= sizeof(attr
);
112 attr
.RootDirectory
= 0;
113 attr
.ObjectName
= &root_key_names
[idx
];
115 attr
.SecurityDescriptor
= NULL
;
116 attr
.SecurityQualityOfService
= NULL
;
117 if (NtCreateKey( &hkey
, access
, &attr
, 0, NULL
, 0, NULL
)) return 0;
118 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
121 if (!(ret
= InterlockedCompareExchangePointer( (void **)&special_root_keys
[idx
], hkey
, 0 )))
124 NtClose( hkey
); /* somebody beat us to it */
128 /* map the hkey from special root to normal key if necessary */
129 inline static HKEY
get_special_root_hkey( HKEY hkey
)
133 if ((hkey
>= HKEY_SPECIAL_ROOT_FIRST
) && (hkey
<= HKEY_SPECIAL_ROOT_LAST
))
135 if (!(ret
= special_root_keys
[(UINT
)hkey
- (UINT
)HKEY_SPECIAL_ROOT_FIRST
]))
136 ret
= create_special_root_hkey( hkey
, KEY_ALL_ACCESS
);
142 /******************************************************************************
143 * RegCreateKeyExW [ADVAPI32.@]
146 * hkey [I] Handle of an open key
147 * name [I] Address of subkey name
148 * reserved [I] Reserved - must be 0
149 * class [I] Address of class string
150 * options [I] Special options flag
151 * access [I] Desired security access
152 * sa [I] Address of key security structure
153 * retkey [O] Address of buffer for opened handle
154 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
157 * in case of failing retkey remains untouched
159 * FIXME MAXIMUM_ALLOWED in access mask not supported by server
161 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
162 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
163 PHKEY retkey
, LPDWORD dispos
)
165 OBJECT_ATTRIBUTES attr
;
166 UNICODE_STRING nameW
, classW
;
168 if (reserved
) return ERROR_INVALID_PARAMETER
;
169 if (!(access
& KEY_ACCESS_MASK
) || (access
& ~KEY_ACCESS_MASK
)) return ERROR_ACCESS_DENIED
;
170 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
172 attr
.Length
= sizeof(attr
);
173 attr
.RootDirectory
= hkey
;
174 attr
.ObjectName
= &nameW
;
176 attr
.SecurityDescriptor
= NULL
;
177 attr
.SecurityQualityOfService
= NULL
;
178 RtlInitUnicodeString( &nameW
, name
);
179 RtlInitUnicodeString( &classW
, class );
181 return RtlNtStatusToDosError( NtCreateKey( retkey
, access
, &attr
, 0,
182 &classW
, options
, dispos
) );
186 /******************************************************************************
187 * RegCreateKeyExA [ADVAPI32.@]
189 * FIXME MAXIMUM_ALLOWED in access mask not supported by server
191 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
192 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
193 PHKEY retkey
, LPDWORD dispos
)
195 OBJECT_ATTRIBUTES attr
;
196 UNICODE_STRING classW
;
197 ANSI_STRING nameA
, classA
;
200 if (reserved
) return ERROR_INVALID_PARAMETER
;
201 if (!is_version_nt()) access
= KEY_ALL_ACCESS
; /* Win95 ignores the access mask */
202 else if (!(access
& KEY_ACCESS_MASK
) || (access
& ~KEY_ACCESS_MASK
)) return ERROR_ACCESS_DENIED
;
203 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
205 attr
.Length
= sizeof(attr
);
206 attr
.RootDirectory
= hkey
;
207 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
209 attr
.SecurityDescriptor
= NULL
;
210 attr
.SecurityQualityOfService
= NULL
;
211 RtlInitAnsiString( &nameA
, name
);
212 RtlInitAnsiString( &classA
, class );
214 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
217 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
219 status
= NtCreateKey( retkey
, access
, &attr
, 0, &classW
, options
, dispos
);
220 RtlFreeUnicodeString( &classW
);
223 return RtlNtStatusToDosError( status
);
227 /******************************************************************************
228 * RegCreateKeyW [ADVAPI32.@]
230 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR name
, PHKEY retkey
)
232 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
233 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
234 return RegCreateKeyExW( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
235 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
239 /******************************************************************************
240 * RegCreateKeyA [ADVAPI32.@]
242 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR name
, PHKEY retkey
)
244 return RegCreateKeyExA( hkey
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
245 KEY_ALL_ACCESS
, NULL
, retkey
, NULL
);
250 /******************************************************************************
251 * RegOpenKeyExW [ADVAPI32.@]
253 * Opens the specified key
255 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
258 * hkey [I] Handle of open key
259 * name [I] Name of subkey to open
260 * reserved [I] Reserved - must be zero
261 * access [I] Security access mask
262 * retkey [O] Handle to open key
265 * Success: ERROR_SUCCESS
266 * Failure: Error code
269 * in case of failing is retkey = 0
271 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, REGSAM access
, PHKEY retkey
)
273 OBJECT_ATTRIBUTES attr
;
274 UNICODE_STRING nameW
;
276 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
278 attr
.Length
= sizeof(attr
);
279 attr
.RootDirectory
= hkey
;
280 attr
.ObjectName
= &nameW
;
282 attr
.SecurityDescriptor
= NULL
;
283 attr
.SecurityQualityOfService
= NULL
;
284 RtlInitUnicodeString( &nameW
, name
);
285 return RtlNtStatusToDosError( NtOpenKey( retkey
, access
, &attr
) );
289 /******************************************************************************
290 * RegOpenKeyExA [ADVAPI32.@]
292 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, REGSAM access
, PHKEY retkey
)
294 OBJECT_ATTRIBUTES attr
;
298 if (!is_version_nt()) access
= KEY_ALL_ACCESS
; /* Win95 ignores the access mask */
300 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
302 attr
.Length
= sizeof(attr
);
303 attr
.RootDirectory
= hkey
;
304 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
306 attr
.SecurityDescriptor
= NULL
;
307 attr
.SecurityQualityOfService
= NULL
;
309 RtlInitAnsiString( &nameA
, name
);
310 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
313 status
= NtOpenKey( retkey
, access
, &attr
);
315 return RtlNtStatusToDosError( status
);
319 /******************************************************************************
320 * RegOpenKeyW [ADVAPI32.@]
323 * hkey [I] Handle of open key
324 * name [I] Address of name of subkey to open
325 * retkey [O] Handle to open key
328 * Success: ERROR_SUCCESS
329 * Failure: Error code
332 * in case of failing is retkey = 0
334 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, PHKEY retkey
)
336 return RegOpenKeyExW( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
340 /******************************************************************************
341 * RegOpenKeyA [ADVAPI32.@]
343 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, PHKEY retkey
)
345 return RegOpenKeyExA( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
349 /******************************************************************************
350 * RegOpenCurrentUser [ADVAPI32.@]
351 * FIXME: This function is supposed to retrieve a handle to the
352 * HKEY_CURRENT_USER for the user the current thread is impersonating.
353 * Since Wine does not currently allow threads to impersonate other users,
354 * this stub should work fine.
356 DWORD WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
358 return RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
363 /******************************************************************************
364 * RegEnumKeyExW [ADVAPI32.@]
367 * hkey [I] Handle to key to enumerate
368 * index [I] Index of subkey to enumerate
369 * name [O] Buffer for subkey name
370 * name_len [O] Size of subkey buffer
371 * reserved [I] Reserved
372 * class [O] Buffer for class string
373 * class_len [O] Size of class buffer
374 * ft [O] Time key last written to
376 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
377 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
380 char buffer
[256], *buf_ptr
= buffer
;
381 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
384 TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
385 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
387 if (reserved
) return ERROR_INVALID_PARAMETER
;
388 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
390 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
391 buffer
, sizeof(buffer
), &total_size
);
393 while (status
== STATUS_BUFFER_OVERFLOW
)
395 /* retry with a dynamically allocated buffer */
396 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
397 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
398 return ERROR_NOT_ENOUGH_MEMORY
;
399 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
400 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
401 buf_ptr
, total_size
, &total_size
);
406 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
407 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
409 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
411 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
412 status
= STATUS_BUFFER_OVERFLOW
;
416 memcpy( name
, info
->Name
, info
->NameLength
);
420 *class_len
= cls_len
;
423 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
430 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
431 return RtlNtStatusToDosError( status
);
435 /******************************************************************************
436 * RegEnumKeyExA [ADVAPI32.@]
438 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
439 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
442 char buffer
[256], *buf_ptr
= buffer
;
443 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
446 TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
447 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
449 if (reserved
) return ERROR_INVALID_PARAMETER
;
450 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
452 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
453 buffer
, sizeof(buffer
), &total_size
);
455 while (status
== STATUS_BUFFER_OVERFLOW
)
457 /* retry with a dynamically allocated buffer */
458 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
459 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
460 return ERROR_NOT_ENOUGH_MEMORY
;
461 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
462 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
463 buf_ptr
, total_size
, &total_size
);
470 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
471 RtlUnicodeToMultiByteSize( &cls_len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
473 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
475 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
476 status
= STATUS_BUFFER_OVERFLOW
;
480 RtlUnicodeToMultiByteN( name
, len
, NULL
, info
->Name
, info
->NameLength
);
484 *class_len
= cls_len
;
487 RtlUnicodeToMultiByteN( class, cls_len
, NULL
,
488 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
496 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
497 return RtlNtStatusToDosError( status
);
501 /******************************************************************************
502 * RegEnumKeyW [ADVAPI32.@]
504 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
506 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
510 /******************************************************************************
511 * RegEnumKeyA [ADVAPI32.@]
513 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
515 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
519 /******************************************************************************
520 * RegQueryInfoKeyW [ADVAPI32.@]
523 * hkey [I] Handle to key to query
524 * class [O] Buffer for class string
525 * class_len [O] Size of class string buffer
526 * reserved [I] Reserved
527 * subkeys [O] Buffer for number of subkeys
528 * max_subkey [O] Buffer for longest subkey name length
529 * max_class [O] Buffer for longest class string length
530 * values [O] Buffer for number of value entries
531 * max_value [O] Buffer for longest value name length
532 * max_data [O] Buffer for longest value data length
533 * security [O] Buffer for security descriptor length
534 * modif [O] Modification time
536 * - win95 allows class to be valid and class_len to be NULL
537 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
538 * - both allow class to be NULL and class_len to be NULL
539 * (it's hard to test validity, so test !NULL instead)
541 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
542 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
543 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
544 LPDWORD security
, FILETIME
*modif
)
547 char buffer
[256], *buf_ptr
= buffer
;
548 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
551 TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
552 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
554 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
555 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
557 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
558 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
562 /* retry with a dynamically allocated buffer */
563 while (status
== STATUS_BUFFER_OVERFLOW
)
565 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
566 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
567 return ERROR_NOT_ENOUGH_MEMORY
;
568 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
569 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
572 if (status
) goto done
;
574 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
576 status
= STATUS_BUFFER_OVERFLOW
;
580 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
581 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
584 else status
= STATUS_SUCCESS
;
586 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
587 if (subkeys
) *subkeys
= info
->SubKeys
;
588 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
589 if (max_class
) *max_class
= info
->MaxClassLen
;
590 if (values
) *values
= info
->Values
;
591 if (max_value
) *max_value
= info
->MaxValueNameLen
;
592 if (max_data
) *max_data
= info
->MaxValueDataLen
;
593 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
596 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
597 return RtlNtStatusToDosError( status
);
601 /******************************************************************************
602 * RegQueryMultipleValuesA [ADVAPI32.@]
604 DWORD WINAPI
RegQueryMultipleValuesA(HKEY hkey
, PVALENTA val_list
, DWORD num_vals
,
605 LPSTR lpValueBuf
, LPDWORD ldwTotsize
)
608 DWORD maxBytes
= *ldwTotsize
;
610 LPSTR bufptr
= lpValueBuf
;
613 TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
615 for(i
=0; i
< num_vals
; ++i
)
618 val_list
[i
].ve_valuelen
=0;
619 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
620 if(status
!= ERROR_SUCCESS
)
625 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
627 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
628 bufptr
, &val_list
[i
].ve_valuelen
);
629 if(status
!= ERROR_SUCCESS
)
634 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
636 bufptr
+= val_list
[i
].ve_valuelen
;
639 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
641 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
645 /******************************************************************************
646 * RegQueryMultipleValuesW [ADVAPI32.@]
648 DWORD WINAPI
RegQueryMultipleValuesW(HKEY hkey
, PVALENTW val_list
, DWORD num_vals
,
649 LPWSTR lpValueBuf
, LPDWORD ldwTotsize
)
652 DWORD maxBytes
= *ldwTotsize
;
654 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
657 TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
659 for(i
=0; i
< num_vals
; ++i
)
661 val_list
[i
].ve_valuelen
=0;
662 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
663 if(status
!= ERROR_SUCCESS
)
668 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
670 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
671 bufptr
, &val_list
[i
].ve_valuelen
);
672 if(status
!= ERROR_SUCCESS
)
677 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
679 bufptr
+= val_list
[i
].ve_valuelen
;
682 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
684 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
687 /******************************************************************************
688 * RegQueryInfoKeyA [ADVAPI32.@]
690 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
691 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
692 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
693 LPDWORD security
, FILETIME
*modif
)
696 char buffer
[256], *buf_ptr
= buffer
;
697 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
698 DWORD total_size
, len
;
700 TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
701 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
703 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
704 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
706 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
707 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
709 if (class || class_len
)
711 /* retry with a dynamically allocated buffer */
712 while (status
== STATUS_BUFFER_OVERFLOW
)
714 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
715 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
716 return ERROR_NOT_ENOUGH_MEMORY
;
717 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
718 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
721 if (status
) goto done
;
723 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
), info
->ClassLength
);
726 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
729 if (class && !status
)
731 RtlUnicodeToMultiByteN( class, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
736 else status
= STATUS_SUCCESS
;
738 if (subkeys
) *subkeys
= info
->SubKeys
;
739 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
740 if (max_class
) *max_class
= info
->MaxClassLen
;
741 if (values
) *values
= info
->Values
;
742 if (max_value
) *max_value
= info
->MaxValueNameLen
;
743 if (max_data
) *max_data
= info
->MaxValueDataLen
;
744 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
747 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
748 return RtlNtStatusToDosError( status
);
752 /******************************************************************************
753 * RegCloseKey [ADVAPI32.@]
755 * Releases the handle of the specified key
758 * hkey [I] Handle of key to close
761 * Success: ERROR_SUCCESS
762 * Failure: Error code
764 DWORD WINAPI
RegCloseKey( HKEY hkey
)
766 if (!hkey
|| hkey
>= (HKEY
)0x80000000) return ERROR_SUCCESS
;
767 return RtlNtStatusToDosError( NtClose( hkey
) );
771 /******************************************************************************
772 * RegDeleteKeyW [ADVAPI32.@]
775 * hkey [I] Handle to open key
776 * name [I] Name of subkey to delete
779 * Success: ERROR_SUCCESS
780 * Failure: Error code
782 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
787 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
791 ret
= RtlNtStatusToDosError( NtDeleteKey( hkey
) );
793 else if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, KEY_ENUMERATE_SUB_KEYS
, &tmp
)))
795 if (!is_version_nt()) /* win95 does recursive key deletes */
797 WCHAR name
[MAX_PATH
];
799 while(!RegEnumKeyW(tmp
, 0, name
, sizeof name
))
801 if(RegDeleteKeyW(tmp
, name
)) /* recurse */
805 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
808 TRACE("%s ret=%08lx\n", debugstr_w(name
), ret
);
813 /******************************************************************************
814 * RegDeleteKeyA [ADVAPI32.@]
816 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
821 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
825 ret
= RtlNtStatusToDosError( NtDeleteKey( hkey
) );
827 else if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, KEY_ENUMERATE_SUB_KEYS
, &tmp
)))
829 if (!is_version_nt()) /* win95 does recursive key deletes */
833 while(!RegEnumKeyA(tmp
, 0, name
, sizeof name
))
835 if(RegDeleteKeyA(tmp
, name
)) /* recurse */
839 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
842 TRACE("%s ret=%08lx\n", debugstr_a(name
), ret
);
848 /******************************************************************************
849 * RegSetValueExW [ADVAPI32.@]
851 * Sets the data and type of a value under a register key
854 * hkey [I] Handle of key to set value for
855 * name [I] Name of value to set
856 * reserved [I] Reserved - must be zero
857 * type [I] Flag for value type
858 * data [I] Address of value data
859 * count [I] Size of value data
862 * Success: ERROR_SUCCESS
863 * Failure: Error code
866 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
867 * NT does definitely care (aj)
869 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
870 DWORD type
, CONST BYTE
*data
, DWORD count
)
872 UNICODE_STRING nameW
;
874 if (!is_version_nt()) /* win95 */
876 if (type
== REG_SZ
) count
= (strlenW( (WCHAR
*)data
) + 1) * sizeof(WCHAR
);
878 else if (count
&& is_string(type
))
880 LPCWSTR str
= (LPCWSTR
)data
;
881 /* if user forgot to count terminating null, add it (yes NT does this) */
882 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
883 count
+= sizeof(WCHAR
);
885 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
887 RtlInitUnicodeString( &nameW
, name
);
888 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
892 /******************************************************************************
893 * RegSetValueExA [ADVAPI32.@]
895 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
896 CONST BYTE
*data
, DWORD count
)
902 if (!is_version_nt()) /* win95 */
904 if (type
== REG_SZ
) count
= strlen(data
) + 1;
906 else if (count
&& is_string(type
))
908 /* if user forgot to count terminating null, add it (yes NT does this) */
909 if (data
[count
-1] && !data
[count
]) count
++;
912 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
914 if (is_string( type
)) /* need to convert to Unicode */
917 RtlMultiByteToUnicodeSize( &lenW
, data
, count
);
918 if (!(dataW
= HeapAlloc( GetProcessHeap(), 0, lenW
))) return ERROR_OUTOFMEMORY
;
919 RtlMultiByteToUnicodeN( dataW
, lenW
, NULL
, data
, count
);
921 data
= (BYTE
*)dataW
;
924 RtlInitAnsiString( &nameA
, name
);
925 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
928 status
= NtSetValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
, 0, type
, data
, count
);
930 if (dataW
) HeapFree( GetProcessHeap(), 0, dataW
);
931 return RtlNtStatusToDosError( status
);
935 /******************************************************************************
936 * RegSetValueW [ADVAPI32.@]
938 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR name
, DWORD type
, LPCWSTR data
, DWORD count
)
943 TRACE("(%p,%s,%ld,%s,%ld)\n", hkey
, debugstr_w(name
), type
, debugstr_w(data
), count
);
945 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
947 if (name
&& name
[0]) /* need to create the subkey */
949 if ((ret
= RegCreateKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
952 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
,
953 (strlenW( data
) + 1) * sizeof(WCHAR
) );
954 if (subkey
!= hkey
) RegCloseKey( subkey
);
959 /******************************************************************************
960 * RegSetValueA [ADVAPI32.@]
962 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
967 TRACE("(%p,%s,%ld,%s,%ld)\n", hkey
, debugstr_a(name
), type
, debugstr_a(data
), count
);
969 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
971 if (name
&& name
[0]) /* need to create the subkey */
973 if ((ret
= RegCreateKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
975 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (LPBYTE
)data
, strlen(data
)+1 );
976 if (subkey
!= hkey
) RegCloseKey( subkey
);
982 /******************************************************************************
983 * RegQueryValueExW [ADVAPI32.@]
985 * Retrieves type and data for a specified name associated with an open key
988 * hkey [I] Handle of key to query
989 * name [I] Name of value to query
990 * reserved [I] Reserved - must be NULL
991 * type [O] Address of buffer for value type. If NULL, the type
993 * data [O] Address of data buffer. If NULL, the actual data is
995 * count [I/O] Address of data buffer size
998 * ERROR_SUCCESS: Success
999 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
1000 * buffer is left untouched. The MS-documentation is wrong (js) !!!
1002 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
1003 LPBYTE data
, LPDWORD count
)
1006 UNICODE_STRING name_str
;
1008 char buffer
[256], *buf_ptr
= buffer
;
1009 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1010 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1012 TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1013 hkey
, debugstr_w(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
1015 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1016 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1018 RtlInitUnicodeString( &name_str
, name
);
1020 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
1021 else total_size
= info_size
;
1023 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1024 buffer
, total_size
, &total_size
);
1025 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1029 /* retry with a dynamically allocated buffer */
1030 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
1032 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1033 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1034 return ERROR_NOT_ENOUGH_MEMORY
;
1035 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1036 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1037 buf_ptr
, total_size
, &total_size
);
1042 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1043 /* if the type is REG_SZ and data is not 0-terminated
1044 * and there is enough space in the buffer NT appends a \0 */
1045 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1047 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
1048 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1051 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1053 else status
= STATUS_SUCCESS
;
1055 if (type
) *type
= info
->Type
;
1056 if (count
) *count
= total_size
- info_size
;
1059 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1060 return RtlNtStatusToDosError(status
);
1064 /******************************************************************************
1065 * RegQueryValueExA [ADVAPI32.@]
1068 * the documentation is wrong: if the buffer is too small it remains untouched
1070 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1071 LPBYTE data
, LPDWORD count
)
1076 char buffer
[256], *buf_ptr
= buffer
;
1077 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1078 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1080 TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1081 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
1083 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1084 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1086 RtlInitAnsiString( &nameA
, name
);
1087 if ((status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
1089 return RtlNtStatusToDosError(status
);
1091 status
= NtQueryValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
,
1092 KeyValuePartialInformation
, buffer
, sizeof(buffer
), &total_size
);
1093 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1095 /* we need to fetch the contents for a string type even if not requested,
1096 * because we need to compute the length of the ASCII string. */
1097 if (data
|| is_string(info
->Type
))
1099 /* retry with a dynamically allocated buffer */
1100 while (status
== STATUS_BUFFER_OVERFLOW
)
1102 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1103 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1105 status
= STATUS_NO_MEMORY
;
1108 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1109 status
= NtQueryValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
,
1110 KeyValuePartialInformation
, buf_ptr
, total_size
, &total_size
);
1113 if (status
) goto done
;
1115 if (is_string(info
->Type
))
1119 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
1120 total_size
- info_size
);
1123 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1126 RtlUnicodeToMultiByteN( data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
1127 total_size
- info_size
);
1128 /* if the type is REG_SZ and data is not 0-terminated
1129 * and there is enough space in the buffer NT appends a \0 */
1130 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1133 total_size
= len
+ info_size
;
1137 if (total_size
- info_size
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1138 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1141 else status
= STATUS_SUCCESS
;
1143 if (type
) *type
= info
->Type
;
1144 if (count
) *count
= total_size
- info_size
;
1147 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1148 return RtlNtStatusToDosError(status
);
1152 /******************************************************************************
1153 * RegQueryValueW [ADVAPI32.@]
1155 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
1160 TRACE("(%p,%s,%p,%ld)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
1162 if (name
&& name
[0])
1164 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1166 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
1167 if (subkey
!= hkey
) RegCloseKey( subkey
);
1168 if (ret
== ERROR_FILE_NOT_FOUND
)
1170 /* return empty string if default value not found */
1171 if (data
) *data
= 0;
1172 if (count
) *count
= 1;
1173 ret
= ERROR_SUCCESS
;
1179 /******************************************************************************
1180 * RegQueryValueA [ADVAPI32.@]
1182 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
1187 TRACE("(%p,%s,%p,%ld)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
1189 if (name
&& name
[0])
1191 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1193 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, count
);
1194 if (subkey
!= hkey
) RegCloseKey( subkey
);
1195 if (ret
== ERROR_FILE_NOT_FOUND
)
1197 /* return empty string if default value not found */
1198 if (data
) *data
= 0;
1199 if (count
) *count
= 1;
1200 ret
= ERROR_SUCCESS
;
1206 /******************************************************************************
1207 * RegEnumValueW [ADVAPI32.@]
1210 * hkey [I] Handle to key to query
1211 * index [I] Index of value to query
1212 * value [O] Value string
1213 * val_count [I/O] Size of value buffer (in wchars)
1214 * reserved [I] Reserved
1215 * type [O] Type code
1216 * data [O] Value data
1217 * count [I/O] Size of data buffer (in bytes)
1220 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
1221 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1225 char buffer
[256], *buf_ptr
= buffer
;
1226 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1227 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1229 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1230 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1232 /* NT only checks count, not val_count */
1233 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1234 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1236 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1237 if (data
) total_size
+= *count
;
1238 total_size
= min( sizeof(buffer
), total_size
);
1240 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1241 buffer
, total_size
, &total_size
);
1242 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1246 /* retry with a dynamically allocated buffer */
1247 while (status
== STATUS_BUFFER_OVERFLOW
)
1249 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1250 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1251 return ERROR_NOT_ENOUGH_MEMORY
;
1252 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1253 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1254 buf_ptr
, total_size
, &total_size
);
1257 if (status
) goto done
;
1261 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
1263 status
= STATUS_BUFFER_OVERFLOW
;
1266 memcpy( value
, info
->Name
, info
->NameLength
);
1267 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
1268 value
[*val_count
] = 0;
1273 if (total_size
- info
->DataOffset
> *count
)
1275 status
= STATUS_BUFFER_OVERFLOW
;
1278 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1279 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1281 /* if the type is REG_SZ and data is not 0-terminated
1282 * and there is enough space in the buffer NT appends a \0 */
1283 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
1284 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1288 else status
= STATUS_SUCCESS
;
1291 if (type
) *type
= info
->Type
;
1292 if (count
) *count
= info
->DataLength
;
1295 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1296 return RtlNtStatusToDosError(status
);
1300 /******************************************************************************
1301 * RegEnumValueA [ADVAPI32.@]
1303 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1304 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1308 char buffer
[256], *buf_ptr
= buffer
;
1309 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1310 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1312 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1313 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1315 /* NT only checks count, not val_count */
1316 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1317 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1319 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1320 if (data
) total_size
+= *count
;
1321 total_size
= min( sizeof(buffer
), total_size
);
1323 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1324 buffer
, total_size
, &total_size
);
1325 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1327 /* we need to fetch the contents for a string type even if not requested,
1328 * because we need to compute the length of the ASCII string. */
1329 if (value
|| data
|| is_string(info
->Type
))
1331 /* retry with a dynamically allocated buffer */
1332 while (status
== STATUS_BUFFER_OVERFLOW
)
1334 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1335 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1336 return ERROR_NOT_ENOUGH_MEMORY
;
1337 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1338 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1339 buf_ptr
, total_size
, &total_size
);
1342 if (status
) goto done
;
1344 if (is_string(info
->Type
))
1347 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1348 total_size
- info
->DataOffset
);
1351 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1354 RtlUnicodeToMultiByteN( data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1355 total_size
- info
->DataOffset
);
1356 /* if the type is REG_SZ and data is not 0-terminated
1357 * and there is enough space in the buffer NT appends a \0 */
1358 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1361 info
->DataLength
= len
;
1365 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1366 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1369 if (value
&& !status
)
1373 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
1374 if (len
>= *val_count
)
1376 status
= STATUS_BUFFER_OVERFLOW
;
1379 len
= *val_count
- 1;
1380 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1386 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1392 else status
= STATUS_SUCCESS
;
1394 if (type
) *type
= info
->Type
;
1395 if (count
) *count
= info
->DataLength
;
1398 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1399 return RtlNtStatusToDosError(status
);
1404 /******************************************************************************
1405 * RegDeleteValueW [ADVAPI32.@]
1408 * hkey [I] handle to key
1409 * name [I] name of value to delete
1414 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
1416 UNICODE_STRING nameW
;
1418 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1420 RtlInitUnicodeString( &nameW
, name
);
1421 return RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
1425 /******************************************************************************
1426 * RegDeleteValueA [ADVAPI32.@]
1428 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
1433 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1435 RtlInitAnsiString( &nameA
, name
);
1436 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
1438 status
= NtDeleteValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
);
1439 return RtlNtStatusToDosError( status
);
1443 /******************************************************************************
1444 * RegLoadKeyW [ADVAPI32.@]
1447 * hkey [I] Handle of open key
1448 * subkey [I] Address of name of subkey
1449 * filename [I] Address of filename for registry information
1451 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
1454 DWORD ret
, len
, err
= GetLastError();
1457 TRACE( "(%p,%s,%s)\n", hkey
, debugstr_w(subkey
), debugstr_w(filename
) );
1459 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1460 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1461 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1463 len
= strlenW( subkey
) * sizeof(WCHAR
);
1464 if (len
> MAX_PATH
*sizeof(WCHAR
)) return ERROR_INVALID_PARAMETER
;
1466 if ((file
= CreateFileW( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1467 FILE_ATTRIBUTE_NORMAL
, 0 )) == INVALID_HANDLE_VALUE
)
1469 ret
= GetLastError();
1473 RegCreateKeyW(hkey
,subkey
,&shkey
);
1475 SERVER_START_REQ( load_registry
)
1479 wine_server_add_data( req
, subkey
, len
);
1480 ret
= RtlNtStatusToDosError( wine_server_call(req
) );
1483 CloseHandle( file
);
1487 SetLastError( err
); /* restore the last error code */
1492 /******************************************************************************
1493 * RegLoadKeyA [ADVAPI32.@]
1495 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
1497 WCHAR buffer
[MAX_PATH
];
1499 DWORD ret
, len
, err
= GetLastError();
1502 TRACE( "(%p,%s,%s)\n", hkey
, debugstr_a(subkey
), debugstr_a(filename
) );
1504 if (!filename
|| !*filename
) return ERROR_INVALID_PARAMETER
;
1505 if (!subkey
|| !*subkey
) return ERROR_INVALID_PARAMETER
;
1506 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1508 if (!(len
= MultiByteToWideChar( CP_ACP
, 0, subkey
, strlen(subkey
), buffer
, MAX_PATH
)))
1509 return ERROR_INVALID_PARAMETER
;
1511 if ((file
= CreateFileA( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1512 FILE_ATTRIBUTE_NORMAL
, 0 )) == INVALID_HANDLE_VALUE
)
1514 ret
= GetLastError();
1518 RegCreateKeyA(hkey
,subkey
,&shkey
);
1520 SERVER_START_REQ( load_registry
)
1524 wine_server_add_data( req
, buffer
, len
* sizeof(WCHAR
) );
1525 ret
= RtlNtStatusToDosError( wine_server_call(req
) );
1528 CloseHandle( file
);
1532 SetLastError( err
); /* restore the last error code */
1537 /******************************************************************************
1538 * RegSaveKeyA [ADVAPI32.@]
1541 * hkey [I] Handle of key where save begins
1542 * lpFile [I] Address of filename to save to
1543 * sa [I] Address of security structure
1545 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
1553 TRACE( "(%p,%s,%p)\n", hkey
, debugstr_a(file
), sa
);
1555 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
1556 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1558 err
= GetLastError();
1559 GetFullPathNameA( file
, sizeof(buffer
), buffer
, &name
);
1562 sprintf( name
, "reg%04x.tmp", count
++ );
1563 handle
= CreateFileA( buffer
, GENERIC_WRITE
, 0, NULL
,
1564 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
1565 if (handle
!= INVALID_HANDLE_VALUE
) break;
1566 if ((ret
= GetLastError()) != ERROR_ALREADY_EXISTS
) goto done
;
1568 /* Something gone haywire ? Please report if this happens abnormally */
1570 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
);
1573 SERVER_START_REQ( save_registry
)
1577 ret
= RtlNtStatusToDosError( wine_server_call( req
) );
1581 CloseHandle( handle
);
1584 if (!MoveFileExA( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
1586 ERR( "Failed to move %s to %s\n", buffer
, file
);
1587 ret
= GetLastError();
1590 if (ret
) DeleteFileA( buffer
);
1593 SetLastError( err
); /* restore last error code */
1598 /******************************************************************************
1599 * RegSaveKeyW [ADVAPI32.@]
1601 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
1603 LPSTR fileA
= HEAP_strdupWtoA( GetProcessHeap(), 0, file
);
1604 DWORD ret
= RegSaveKeyA( hkey
, fileA
, sa
);
1605 if (fileA
) HeapFree( GetProcessHeap(), 0, fileA
);
1610 /******************************************************************************
1611 * RegRestoreKeyW [ADVAPI32.@]
1614 * hkey [I] Handle of key where restore begins
1615 * lpFile [I] Address of filename containing saved tree
1616 * dwFlags [I] Optional flags
1618 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1620 TRACE("(%p,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1622 /* It seems to do this check before the hkey check */
1623 if (!lpFile
|| !*lpFile
)
1624 return ERROR_INVALID_PARAMETER
;
1626 FIXME("(%p,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1628 /* Check for file existence */
1630 return ERROR_SUCCESS
;
1634 /******************************************************************************
1635 * RegRestoreKeyA [ADVAPI32.@]
1637 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1639 LPWSTR lpFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile
);
1640 LONG ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1641 HeapFree( GetProcessHeap(), 0, lpFileW
);
1646 /******************************************************************************
1647 * RegUnLoadKeyW [ADVAPI32.@]
1650 * hkey [I] Handle of open key
1651 * lpSubKey [I] Address of name of subkey to unload
1653 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1655 FIXME("(%p,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1656 return ERROR_SUCCESS
;
1660 /******************************************************************************
1661 * RegUnLoadKeyA [ADVAPI32.@]
1663 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1665 LPWSTR lpSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey
);
1666 LONG ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
1667 if(lpSubKeyW
) HeapFree( GetProcessHeap(), 0, lpSubKeyW
);
1672 /******************************************************************************
1673 * RegReplaceKeyW [ADVAPI32.@]
1676 * hkey [I] Handle of open key
1677 * lpSubKey [I] Address of name of subkey
1678 * lpNewFile [I] Address of filename for file with new data
1679 * lpOldFile [I] Address of filename for backup file
1681 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1684 FIXME("(%p,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1685 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1686 return ERROR_SUCCESS
;
1690 /******************************************************************************
1691 * RegReplaceKeyA [ADVAPI32.@]
1693 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1696 LPWSTR lpSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey
);
1697 LPWSTR lpNewFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile
);
1698 LPWSTR lpOldFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile
);
1699 LONG ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
1700 HeapFree( GetProcessHeap(), 0, lpOldFileW
);
1701 HeapFree( GetProcessHeap(), 0, lpNewFileW
);
1702 HeapFree( GetProcessHeap(), 0, lpSubKeyW
);
1707 /******************************************************************************
1708 * RegSetKeySecurity [ADVAPI32.@]
1711 * hkey [I] Open handle of key to set
1712 * SecurityInfo [I] Descriptor contents
1713 * pSecurityDesc [I] Address of descriptor for key
1715 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1716 PSECURITY_DESCRIPTOR pSecurityDesc
)
1718 TRACE("(%p,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1720 /* It seems to perform this check before the hkey check */
1721 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1722 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1723 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1724 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1727 return ERROR_INVALID_PARAMETER
;
1730 return ERROR_INVALID_PARAMETER
;
1732 FIXME(":(%p,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1734 return ERROR_SUCCESS
;
1738 /******************************************************************************
1739 * RegGetKeySecurity [ADVAPI32.@]
1740 * Retrieves a copy of security descriptor protecting the registry key
1743 * hkey [I] Open handle of key to set
1744 * SecurityInformation [I] Descriptor contents
1745 * pSecurityDescriptor [O] Address of descriptor for key
1746 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1749 * Success: ERROR_SUCCESS
1750 * Failure: Error code
1752 LONG WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
1753 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1754 LPDWORD lpcbSecurityDescriptor
)
1756 TRACE("(%p,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1757 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1759 /* FIXME: Check for valid SecurityInformation values */
1761 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1762 return ERROR_INSUFFICIENT_BUFFER
;
1764 FIXME("(%p,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1765 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1767 /* Do not leave security descriptor filled with garbage */
1768 RtlCreateSecurityDescriptor(pSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
1770 return ERROR_SUCCESS
;
1774 /******************************************************************************
1775 * RegFlushKey [ADVAPI32.@]
1776 * Immediately writes key to registry.
1777 * Only returns after data has been written to disk.
1779 * FIXME: does it really wait until data is written ?
1782 * hkey [I] Handle of key to write
1785 * Success: ERROR_SUCCESS
1786 * Failure: Error code
1788 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1790 FIXME( "(%p): stub\n", hkey
);
1791 return ERROR_SUCCESS
;
1795 /******************************************************************************
1796 * RegConnectRegistryW [ADVAPI32.@]
1799 * lpMachineName [I] Address of name of remote computer
1800 * hHey [I] Predefined registry handle
1801 * phkResult [I] Address of buffer for remote registry handle
1803 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1806 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1808 if (!lpMachineName
|| !*lpMachineName
) {
1809 /* Use the local machine name */
1810 return RegOpenKeyA( hKey
, "", phkResult
);
1813 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1814 return ERROR_BAD_NETPATH
;
1818 /******************************************************************************
1819 * RegConnectRegistryA [ADVAPI32.@]
1821 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, PHKEY reskey
)
1823 LPWSTR machineW
= HEAP_strdupAtoW( GetProcessHeap(), 0, machine
);
1824 DWORD ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
1825 HeapFree( GetProcessHeap(), 0, machineW
);
1830 /******************************************************************************
1831 * RegNotifyChangeKeyValue [ADVAPI32.@]
1834 * hkey [I] Handle of key to watch
1835 * fWatchSubTree [I] Flag for subkey notification
1836 * fdwNotifyFilter [I] Changes to be reported
1837 * hEvent [I] Handle of signaled event
1838 * fAsync [I] Flag for asynchronous reporting
1840 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1841 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1844 FIXME("(%p,%i,%ld,%p,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1846 return ERROR_SUCCESS
;