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
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
45 /* allowed bits for access mask */
46 #define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
48 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
49 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
50 #define NB_SPECIAL_ROOT_KEYS ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
52 static HKEY special_root_keys
[NB_SPECIAL_ROOT_KEYS
];
54 static const WCHAR name_CLASSES_ROOT
[] =
55 {'M','a','c','h','i','n','e','\\',
56 'S','o','f','t','w','a','r','e','\\',
57 'C','l','a','s','s','e','s',0};
58 static const WCHAR name_LOCAL_MACHINE
[] =
59 {'M','a','c','h','i','n','e',0};
60 static const WCHAR name_USERS
[] =
62 static const WCHAR name_PERFORMANCE_DATA
[] =
63 {'P','e','r','f','D','a','t','a',0};
64 static const WCHAR name_CURRENT_CONFIG
[] =
65 {'M','a','c','h','i','n','e','\\',
66 'S','y','s','t','e','m','\\',
67 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
68 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
69 'C','u','r','r','e','n','t',0};
70 static const WCHAR name_DYN_DATA
[] =
71 {'D','y','n','D','a','t','a',0};
73 #define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
74 static UNICODE_STRING root_key_names
[NB_SPECIAL_ROOT_KEYS
] =
76 DECL_STR(CLASSES_ROOT
),
77 { 0, 0, NULL
}, /* HKEY_CURRENT_USER is determined dynamically */
78 DECL_STR(LOCAL_MACHINE
),
80 DECL_STR(PERFORMANCE_DATA
),
81 DECL_STR(CURRENT_CONFIG
),
87 /* check if value type needs string conversion (Ansi<->Unicode) */
88 inline static int is_string( DWORD type
)
90 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
93 /* check if current version is NT or Win95 */
94 inline static int is_version_nt(void)
96 return !(GetVersion() & 0x80000000);
99 /* create one of the HKEY_* special root keys */
100 static HKEY
create_special_root_hkey( HANDLE hkey
, DWORD access
)
103 int idx
= (UINT_PTR
)hkey
- (UINT_PTR
)HKEY_SPECIAL_ROOT_FIRST
;
105 if (hkey
== HKEY_CURRENT_USER
)
107 if (RtlOpenCurrentUser( access
, &hkey
)) return 0;
108 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey
);
112 OBJECT_ATTRIBUTES attr
;
114 attr
.Length
= sizeof(attr
);
115 attr
.RootDirectory
= 0;
116 attr
.ObjectName
= &root_key_names
[idx
];
118 attr
.SecurityDescriptor
= NULL
;
119 attr
.SecurityQualityOfService
= NULL
;
120 if (NtCreateKey( &hkey
, access
, &attr
, 0, NULL
, 0, NULL
)) return 0;
121 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
124 if (!(ret
= InterlockedCompareExchangePointer( (void **)&special_root_keys
[idx
], hkey
, 0 )))
127 NtClose( hkey
); /* somebody beat us to it */
131 /* map the hkey from special root to normal key if necessary */
132 inline static HKEY
get_special_root_hkey( HKEY hkey
)
136 if ((hkey
>= HKEY_SPECIAL_ROOT_FIRST
) && (hkey
<= HKEY_SPECIAL_ROOT_LAST
))
138 if (!(ret
= special_root_keys
[(UINT_PTR
)hkey
- (UINT_PTR
)HKEY_SPECIAL_ROOT_FIRST
]))
139 ret
= create_special_root_hkey( hkey
, KEY_ALL_ACCESS
);
145 /******************************************************************************
146 * RegCreateKeyExW [ADVAPI32.@]
148 * See RegCreateKeyExA.
150 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
151 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
152 PHKEY retkey
, LPDWORD dispos
)
154 OBJECT_ATTRIBUTES attr
;
155 UNICODE_STRING nameW
, classW
;
157 if (reserved
) return ERROR_INVALID_PARAMETER
;
158 if (!(access
& KEY_ACCESS_MASK
) || (access
& ~KEY_ACCESS_MASK
)) return ERROR_ACCESS_DENIED
;
159 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
161 attr
.Length
= sizeof(attr
);
162 attr
.RootDirectory
= hkey
;
163 attr
.ObjectName
= &nameW
;
165 attr
.SecurityDescriptor
= NULL
;
166 attr
.SecurityQualityOfService
= NULL
;
167 RtlInitUnicodeString( &nameW
, name
);
168 RtlInitUnicodeString( &classW
, class );
170 return RtlNtStatusToDosError( NtCreateKey( (PHANDLE
)retkey
, access
, &attr
, 0,
171 &classW
, options
, dispos
) );
175 /******************************************************************************
176 * RegCreateKeyExA [ADVAPI32.@]
178 * Open a registry key, creating it if it doesn't exist.
181 * hkey [I] Handle of the parent registry key
182 * name [I] Name of the new key to open or create
183 * reserved [I] Reserved, pass 0
184 * class [I] The object type of the new key
185 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
186 * access [I] Access level desired
187 * sa [I] Security attributes for the key
188 * retkey [O] Destination for the resulting handle
189 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
192 * Success: ERROR_SUCCESS.
193 * Failure: A standard Win32 error code. retkey remains untouched.
196 * MAXIMUM_ALLOWED in access mask not supported by server
198 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
199 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
200 PHKEY retkey
, LPDWORD dispos
)
202 OBJECT_ATTRIBUTES attr
;
203 UNICODE_STRING classW
;
204 ANSI_STRING nameA
, classA
;
207 if (reserved
) return ERROR_INVALID_PARAMETER
;
208 if (!is_version_nt()) access
= KEY_ALL_ACCESS
; /* Win95 ignores the access mask */
209 else if (!(access
& KEY_ACCESS_MASK
) || (access
& ~KEY_ACCESS_MASK
)) return ERROR_ACCESS_DENIED
;
210 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
212 attr
.Length
= sizeof(attr
);
213 attr
.RootDirectory
= hkey
;
214 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
216 attr
.SecurityDescriptor
= NULL
;
217 attr
.SecurityQualityOfService
= NULL
;
218 RtlInitAnsiString( &nameA
, name
);
219 RtlInitAnsiString( &classA
, class );
221 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
224 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
226 status
= NtCreateKey( (PHANDLE
)retkey
, access
, &attr
, 0, &classW
, options
, dispos
);
227 RtlFreeUnicodeString( &classW
);
230 return RtlNtStatusToDosError( status
);
234 /******************************************************************************
235 * RegCreateKeyW [ADVAPI32.@]
237 * Creates the specified reg key.
240 * hKey [I] Handle to an open key.
241 * lpSubKey [I] Name of a key that will be opened or created.
242 * phkResult [O] Receives a handle to the opened or created key.
245 * Success: ERROR_SUCCESS
246 * Failure: nonzero error code defined in Winerror.h
248 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpSubKey
, PHKEY phkResult
)
250 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
251 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
252 return RegCreateKeyExW( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
253 KEY_ALL_ACCESS
, NULL
, phkResult
, NULL
);
257 /******************************************************************************
258 * RegCreateKeyA [ADVAPI32.@]
262 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpSubKey
, PHKEY phkResult
)
264 return RegCreateKeyExA( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
265 KEY_ALL_ACCESS
, NULL
, phkResult
, NULL
);
270 /******************************************************************************
271 * RegOpenKeyExW [ADVAPI32.@]
275 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, REGSAM access
, PHKEY retkey
)
277 OBJECT_ATTRIBUTES attr
;
278 UNICODE_STRING nameW
;
280 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
282 attr
.Length
= sizeof(attr
);
283 attr
.RootDirectory
= hkey
;
284 attr
.ObjectName
= &nameW
;
286 attr
.SecurityDescriptor
= NULL
;
287 attr
.SecurityQualityOfService
= NULL
;
288 RtlInitUnicodeString( &nameW
, name
);
289 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE
)retkey
, access
, &attr
) );
293 /******************************************************************************
294 * RegOpenKeyExA [ADVAPI32.@]
296 * Open a registry key.
299 * hkey [I] Handle of open key
300 * name [I] Name of subkey to open
301 * reserved [I] Reserved - must be zero
302 * access [I] Security access mask
303 * retkey [O] Handle to open key
306 * Success: ERROR_SUCCESS
307 * Failure: A standard Win32 error code. retkey is set to 0.
310 * Unlike RegCreateKeyExA(), this function will not create the key if it
313 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, REGSAM access
, PHKEY retkey
)
315 OBJECT_ATTRIBUTES attr
;
319 if (!is_version_nt()) access
= KEY_ALL_ACCESS
; /* Win95 ignores the access mask */
321 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
323 attr
.Length
= sizeof(attr
);
324 attr
.RootDirectory
= hkey
;
325 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
327 attr
.SecurityDescriptor
= NULL
;
328 attr
.SecurityQualityOfService
= NULL
;
330 RtlInitAnsiString( &nameA
, name
);
331 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
334 status
= NtOpenKey( (PHANDLE
)retkey
, access
, &attr
);
336 return RtlNtStatusToDosError( status
);
340 /******************************************************************************
341 * RegOpenKeyW [ADVAPI32.@]
345 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, PHKEY retkey
)
350 return ERROR_SUCCESS
;
352 return RegOpenKeyExW( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
356 /******************************************************************************
357 * RegOpenKeyA [ADVAPI32.@]
359 * Open a registry key.
362 * hkey [I] Handle of parent key to open the new key under
363 * name [I] Name of the key under hkey to open
364 * retkey [O] Destination for the resulting Handle
367 * Success: ERROR_SUCCESS
368 * Failure: A standard Win32 error code. retkey is set to 0.
370 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, PHKEY retkey
)
375 return ERROR_SUCCESS
;
377 return RegOpenKeyExA( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
381 /******************************************************************************
382 * RegOpenCurrentUser [ADVAPI32.@]
384 * FIXME: This function is supposed to retrieve a handle to the
385 * HKEY_CURRENT_USER for the user the current thread is impersonating.
386 * Since Wine does not currently allow threads to impersonate other users,
387 * this stub should work fine.
389 DWORD WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
391 return RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
396 /******************************************************************************
397 * RegEnumKeyExW [ADVAPI32.@]
400 * hkey [I] Handle to key to enumerate
401 * index [I] Index of subkey to enumerate
402 * name [O] Buffer for subkey name
403 * name_len [O] Size of subkey buffer
404 * reserved [I] Reserved
405 * class [O] Buffer for class string
406 * class_len [O] Size of class buffer
407 * ft [O] Time key last written to
410 * Success: ERROR_SUCCESS
411 * Failure: System error code. If there are no more subkeys available, the
412 * function returns ERROR_NO_MORE_ITEMS.
414 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
415 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
418 char buffer
[256], *buf_ptr
= buffer
;
419 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
422 TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
423 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
425 if (reserved
) return ERROR_INVALID_PARAMETER
;
426 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
428 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
429 buffer
, sizeof(buffer
), &total_size
);
431 while (status
== STATUS_BUFFER_OVERFLOW
)
433 /* retry with a dynamically allocated buffer */
434 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
435 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
436 return ERROR_NOT_ENOUGH_MEMORY
;
437 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
438 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
439 buf_ptr
, total_size
, &total_size
);
444 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
445 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
447 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
449 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
450 status
= STATUS_BUFFER_OVERFLOW
;
454 memcpy( name
, info
->Name
, info
->NameLength
);
458 *class_len
= cls_len
;
461 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
468 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
469 return RtlNtStatusToDosError( status
);
473 /******************************************************************************
474 * RegEnumKeyExA [ADVAPI32.@]
478 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
479 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
482 char buffer
[256], *buf_ptr
= buffer
;
483 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
486 TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
487 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
489 if (reserved
) return ERROR_INVALID_PARAMETER
;
490 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
492 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
493 buffer
, sizeof(buffer
), &total_size
);
495 while (status
== STATUS_BUFFER_OVERFLOW
)
497 /* retry with a dynamically allocated buffer */
498 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
499 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
500 return ERROR_NOT_ENOUGH_MEMORY
;
501 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
502 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
503 buf_ptr
, total_size
, &total_size
);
510 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
511 RtlUnicodeToMultiByteSize( &cls_len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
513 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
515 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
516 status
= STATUS_BUFFER_OVERFLOW
;
520 RtlUnicodeToMultiByteN( name
, len
, NULL
, info
->Name
, info
->NameLength
);
524 *class_len
= cls_len
;
527 RtlUnicodeToMultiByteN( class, cls_len
, NULL
,
528 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
536 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
537 return RtlNtStatusToDosError( status
);
541 /******************************************************************************
542 * RegEnumKeyW [ADVAPI32.@]
544 * Enumerates subkyes of the specified open reg key.
547 * hKey [I] Handle to an open key.
548 * dwIndex [I] Index of the subkey of hKey to retrieve.
549 * lpName [O] Name of the subkey.
550 * cchName [I] Size of lpName in TCHARS.
553 * Success: ERROR_SUCCESS
554 * Failure: system error code. If there are no more subkeys available, the
555 * function returns ERROR_NO_MORE_ITEMS.
557 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
559 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
563 /******************************************************************************
564 * RegEnumKeyA [ADVAPI32.@]
568 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
570 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
574 /******************************************************************************
575 * RegQueryInfoKeyW [ADVAPI32.@]
578 * hkey [I] Handle to key to query
579 * class [O] Buffer for class string
580 * class_len [O] Size of class string buffer
581 * reserved [I] Reserved
582 * subkeys [O] Buffer for number of subkeys
583 * max_subkey [O] Buffer for longest subkey name length
584 * max_class [O] Buffer for longest class string length
585 * values [O] Buffer for number of value entries
586 * max_value [O] Buffer for longest value name length
587 * max_data [O] Buffer for longest value data length
588 * security [O] Buffer for security descriptor length
589 * modif [O] Modification time
591 * - win95 allows class to be valid and class_len to be NULL
592 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
593 * - both allow class to be NULL and class_len to be NULL
594 * (it's hard to test validity, so test !NULL instead)
596 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
597 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
598 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
599 LPDWORD security
, FILETIME
*modif
)
602 char buffer
[256], *buf_ptr
= buffer
;
603 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
606 TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
607 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
609 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
610 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
612 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
613 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
617 /* retry with a dynamically allocated buffer */
618 while (status
== STATUS_BUFFER_OVERFLOW
)
620 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
621 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
622 return ERROR_NOT_ENOUGH_MEMORY
;
623 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
624 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
627 if (status
) goto done
;
629 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
631 status
= STATUS_BUFFER_OVERFLOW
;
635 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
636 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
639 else status
= STATUS_SUCCESS
;
641 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
642 if (subkeys
) *subkeys
= info
->SubKeys
;
643 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
644 if (max_class
) *max_class
= info
->MaxClassLen
;
645 if (values
) *values
= info
->Values
;
646 if (max_value
) *max_value
= info
->MaxValueNameLen
;
647 if (max_data
) *max_data
= info
->MaxValueDataLen
;
648 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
651 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
652 return RtlNtStatusToDosError( status
);
656 /******************************************************************************
657 * RegQueryMultipleValuesA [ADVAPI32.@]
659 * Retrieves the type and data for a list of value names associated with a key.
662 * hKey [I] Handle to an open key.
663 * val_list [O] Array of VALENT structures that describes the entries.
664 * num_vals [I] Number of elements in val_list.
665 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
666 * ldwTotsize [I/O] Size of lpValueBuf.
669 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
670 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
673 DWORD WINAPI
RegQueryMultipleValuesA(HKEY hkey
, PVALENTA val_list
, DWORD num_vals
,
674 LPSTR lpValueBuf
, LPDWORD ldwTotsize
)
677 DWORD maxBytes
= *ldwTotsize
;
679 LPSTR bufptr
= lpValueBuf
;
682 TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
684 for(i
=0; i
< num_vals
; ++i
)
687 val_list
[i
].ve_valuelen
=0;
688 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
689 if(status
!= ERROR_SUCCESS
)
694 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
696 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
697 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
698 if(status
!= ERROR_SUCCESS
)
703 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
705 bufptr
+= val_list
[i
].ve_valuelen
;
708 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
710 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
714 /******************************************************************************
715 * RegQueryMultipleValuesW [ADVAPI32.@]
717 * see RegQueryMultipleValuesA
719 DWORD WINAPI
RegQueryMultipleValuesW(HKEY hkey
, PVALENTW val_list
, DWORD num_vals
,
720 LPWSTR lpValueBuf
, LPDWORD ldwTotsize
)
723 DWORD maxBytes
= *ldwTotsize
;
725 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
728 TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
730 for(i
=0; i
< num_vals
; ++i
)
732 val_list
[i
].ve_valuelen
=0;
733 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
734 if(status
!= ERROR_SUCCESS
)
739 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
741 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
742 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
743 if(status
!= ERROR_SUCCESS
)
748 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
750 bufptr
+= val_list
[i
].ve_valuelen
;
753 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
755 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
758 /******************************************************************************
759 * RegQueryInfoKeyA [ADVAPI32.@]
761 * Retrieves information about a registry key.
764 * hKey [I] Handle to an open key.
765 * lpClass [O] Class string of the key.
766 * lpcClass [I/O] size of lpClass.
767 * lpReserved [I] Reserved; must be NULL.
768 * lpcSubKeys [O] Number of subkeys contained by the key.
769 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
770 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
772 * lpcValues [O] Number of values associated with the key.
773 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
774 * lpcMaxValueLen [O] Longest data component among the key's values
775 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
776 * lpftLastWriteTime [O] FILETIME strucutre that is the last write time.
779 * Success: ERROR_SUCCESS
780 * Failure: nonzero error code from Winerror.h
782 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
783 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
784 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
785 LPDWORD security
, FILETIME
*modif
)
788 char buffer
[256], *buf_ptr
= buffer
;
789 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
790 DWORD total_size
, len
;
792 TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
793 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
795 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
796 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
798 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
799 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
801 if (class || class_len
)
803 /* retry with a dynamically allocated buffer */
804 while (status
== STATUS_BUFFER_OVERFLOW
)
806 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
807 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
808 return ERROR_NOT_ENOUGH_MEMORY
;
809 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
810 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
813 if (status
) goto done
;
815 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
), info
->ClassLength
);
818 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
821 if (class && !status
)
823 RtlUnicodeToMultiByteN( class, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
828 else status
= STATUS_SUCCESS
;
830 if (subkeys
) *subkeys
= info
->SubKeys
;
831 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
832 if (max_class
) *max_class
= info
->MaxClassLen
;
833 if (values
) *values
= info
->Values
;
834 if (max_value
) *max_value
= info
->MaxValueNameLen
;
835 if (max_data
) *max_data
= info
->MaxValueDataLen
;
836 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
839 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
840 return RtlNtStatusToDosError( status
);
844 /******************************************************************************
845 * RegCloseKey [ADVAPI32.@]
847 * Close an open registry key.
850 * hkey [I] Handle of key to close
853 * Success: ERROR_SUCCESS
854 * Failure: Error code
856 DWORD WINAPI
RegCloseKey( HKEY hkey
)
858 if (!hkey
) return ERROR_INVALID_HANDLE
;
859 if (hkey
>= (HKEY
)0x80000000) return ERROR_SUCCESS
;
860 return RtlNtStatusToDosError( NtClose( hkey
) );
864 /******************************************************************************
865 * RegDeleteKeyW [ADVAPI32.@]
869 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
874 if (!name
) return ERROR_INVALID_PARAMETER
;
876 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
878 if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, DELETE
, &tmp
)))
880 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
883 TRACE("%s ret=%08lx\n", debugstr_w(name
), ret
);
888 /******************************************************************************
889 * RegDeleteKeyA [ADVAPI32.@]
891 * Delete a registry key.
894 * hkey [I] Handle to parent key containing the key to delete
895 * name [I] Name of the key user hkey to delete
899 * MSDN is wrong when it says that hkey must be opened with the DELETE access
900 * right. In reality, it opens a new handle with DELETE access.
903 * Success: ERROR_SUCCESS
904 * Failure: Error code
906 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
911 if (!name
) return ERROR_INVALID_PARAMETER
;
913 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
915 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, DELETE
, &tmp
)))
917 if (!is_version_nt()) /* win95 does recursive key deletes */
921 while(!RegEnumKeyA(tmp
, 0, name
, sizeof(name
)))
923 if(RegDeleteKeyA(tmp
, name
)) /* recurse */
927 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
930 TRACE("%s ret=%08lx\n", debugstr_a(name
), ret
);
936 /******************************************************************************
937 * RegSetValueExW [ADVAPI32.@]
939 * Set the data and contents of a registry value.
942 * hkey [I] Handle of key to set value for
943 * name [I] Name of value to set
944 * reserved [I] Reserved, must be zero
945 * type [I] Type of the value being set
946 * data [I] The new contents of the value to set
947 * count [I] Size of data
950 * Success: ERROR_SUCCESS
951 * Failure: Error code
953 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
954 DWORD type
, CONST BYTE
*data
, DWORD count
)
956 UNICODE_STRING nameW
;
958 /* no need for version check, not implemented on win9x anyway */
959 if (count
&& is_string(type
))
961 LPCWSTR str
= (LPCWSTR
)data
;
962 /* if user forgot to count terminating null, add it (yes NT does this) */
963 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
964 count
+= sizeof(WCHAR
);
966 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
968 RtlInitUnicodeString( &nameW
, name
);
969 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
973 /******************************************************************************
974 * RegSetValueExA [ADVAPI32.@]
979 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
980 * NT does definitely care (aj)
982 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
983 CONST BYTE
*data
, DWORD count
)
989 if (!is_version_nt()) /* win95 */
993 if (!data
) return ERROR_INVALID_PARAMETER
;
994 count
= strlen((const char *)data
) + 1;
997 else if (count
&& is_string(type
))
999 /* if user forgot to count terminating null, add it (yes NT does this) */
1000 if (data
[count
-1] && !data
[count
]) count
++;
1003 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1005 if (is_string( type
)) /* need to convert to Unicode */
1008 RtlMultiByteToUnicodeSize( &lenW
, (const char *)data
, count
);
1009 if (!(dataW
= HeapAlloc( GetProcessHeap(), 0, lenW
))) return ERROR_OUTOFMEMORY
;
1010 RtlMultiByteToUnicodeN( dataW
, lenW
, NULL
, (const char *)data
, count
);
1012 data
= (BYTE
*)dataW
;
1015 RtlInitAnsiString( &nameA
, name
);
1016 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
1019 status
= NtSetValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
, 0, type
, data
, count
);
1021 HeapFree( GetProcessHeap(), 0, dataW
);
1022 return RtlNtStatusToDosError( status
);
1026 /******************************************************************************
1027 * RegSetValueW [ADVAPI32.@]
1029 * Sets the data for the default or unnamed value of a reg key.
1032 * hKey [I] Handle to an open key.
1033 * lpSubKey [I] Name of a subkey of hKey.
1034 * dwType [I] Type of information to store.
1035 * lpData [I] String that contains the data to set for the default value.
1036 * cbData [I] Size of lpData.
1039 * Success: ERROR_SUCCESS
1040 * Failure: nonzero error code from Winerror.h
1042 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR name
, DWORD type
, LPCWSTR data
, DWORD count
)
1047 TRACE("(%p,%s,%ld,%s,%ld)\n", hkey
, debugstr_w(name
), type
, debugstr_w(data
), count
);
1049 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
1051 if (name
&& name
[0]) /* need to create the subkey */
1053 if ((ret
= RegCreateKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1056 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)data
,
1057 (strlenW( data
) + 1) * sizeof(WCHAR
) );
1058 if (subkey
!= hkey
) RegCloseKey( subkey
);
1063 /******************************************************************************
1064 * RegSetValueA [ADVAPI32.@]
1068 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1073 TRACE("(%p,%s,%ld,%s,%ld)\n", hkey
, debugstr_a(name
), type
, debugstr_a(data
), count
);
1075 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
1077 if (name
&& name
[0]) /* need to create the subkey */
1079 if ((ret
= RegCreateKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1081 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)data
, strlen(data
)+1 );
1082 if (subkey
!= hkey
) RegCloseKey( subkey
);
1088 /******************************************************************************
1089 * RegQueryValueExW [ADVAPI32.@]
1091 * See RegQueryValueExA.
1093 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
1094 LPBYTE data
, LPDWORD count
)
1097 UNICODE_STRING name_str
;
1099 char buffer
[256], *buf_ptr
= buffer
;
1100 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1101 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1103 TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1104 hkey
, debugstr_w(name
), reserved
, type
, data
, count
,
1105 (count
&& data
) ? *count
: 0 );
1107 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1108 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1110 RtlInitUnicodeString( &name_str
, name
);
1112 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
1113 else total_size
= info_size
;
1115 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1116 buffer
, total_size
, &total_size
);
1117 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1121 /* retry with a dynamically allocated buffer */
1122 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
1124 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1125 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1126 return ERROR_NOT_ENOUGH_MEMORY
;
1127 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1128 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1129 buf_ptr
, total_size
, &total_size
);
1134 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1135 /* if the type is REG_SZ and data is not 0-terminated
1136 * and there is enough space in the buffer NT appends a \0 */
1137 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1139 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
1140 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1143 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1145 else status
= STATUS_SUCCESS
;
1147 if (type
) *type
= info
->Type
;
1148 if (count
) *count
= total_size
- info_size
;
1151 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1152 return RtlNtStatusToDosError(status
);
1156 /******************************************************************************
1157 * RegQueryValueExA [ADVAPI32.@]
1159 * Get the type and contents of a specified value under with a key.
1162 * hkey [I] Handle of the key to query
1163 * name [I] Name of value under hkey to query
1164 * reserved [I] Reserved - must be NULL
1165 * type [O] Destination for the value type, or NULL if not required
1166 * data [O] Destination for the values contents, or NULL if not required
1167 * count [I/O] Size of data, updated with the number of bytes returned
1170 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1171 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1172 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1173 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1176 * MSDN states that if data is too small it is partially filled. In reality
1177 * it remains untouched.
1179 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1180 LPBYTE data
, LPDWORD count
)
1185 char buffer
[256], *buf_ptr
= buffer
;
1186 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1187 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1189 TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1190 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
1192 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1193 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1195 RtlInitAnsiString( &nameA
, name
);
1196 if ((status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
1198 return RtlNtStatusToDosError(status
);
1200 status
= NtQueryValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
,
1201 KeyValuePartialInformation
, buffer
, sizeof(buffer
), &total_size
);
1202 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1204 /* we need to fetch the contents for a string type even if not requested,
1205 * because we need to compute the length of the ASCII string. */
1206 if (data
|| is_string(info
->Type
))
1208 /* retry with a dynamically allocated buffer */
1209 while (status
== STATUS_BUFFER_OVERFLOW
)
1211 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1212 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1214 status
= STATUS_NO_MEMORY
;
1217 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1218 status
= NtQueryValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
,
1219 KeyValuePartialInformation
, buf_ptr
, total_size
, &total_size
);
1222 if (status
) goto done
;
1224 if (is_string(info
->Type
))
1228 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
1229 total_size
- info_size
);
1232 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1235 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
1236 total_size
- info_size
);
1237 /* if the type is REG_SZ and data is not 0-terminated
1238 * and there is enough space in the buffer NT appends a \0 */
1239 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1242 total_size
= len
+ info_size
;
1246 if (total_size
- info_size
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1247 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1250 else status
= STATUS_SUCCESS
;
1252 if (type
) *type
= info
->Type
;
1253 if (count
) *count
= total_size
- info_size
;
1256 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1257 return RtlNtStatusToDosError(status
);
1261 /******************************************************************************
1262 * RegQueryValueW [ADVAPI32.@]
1264 * Retrieves the data associated with the default or unnamed value of a key.
1267 * hkey [I] Handle to an open key.
1268 * name [I] Name of the subkey of hKey.
1269 * data [O] Receives the string associated with the default value
1271 * count [I/O] Size of lpValue in bytes.
1274 * Success: ERROR_SUCCESS
1275 * Failure: nonzero error code from Winerror.h
1277 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
1282 TRACE("(%p,%s,%p,%ld)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
1284 if (name
&& name
[0])
1286 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1288 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1289 if (subkey
!= hkey
) RegCloseKey( subkey
);
1290 if (ret
== ERROR_FILE_NOT_FOUND
)
1292 /* return empty string if default value not found */
1293 if (data
) *data
= 0;
1294 if (count
) *count
= sizeof(WCHAR
);
1295 ret
= ERROR_SUCCESS
;
1301 /******************************************************************************
1302 * RegQueryValueA [ADVAPI32.@]
1304 * see RegQueryValueW
1306 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
1311 TRACE("(%p,%s,%p,%ld)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
1313 if (name
&& name
[0])
1315 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1317 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1318 if (subkey
!= hkey
) RegCloseKey( subkey
);
1319 if (ret
== ERROR_FILE_NOT_FOUND
)
1321 /* return empty string if default value not found */
1322 if (data
) *data
= 0;
1323 if (count
) *count
= 1;
1324 ret
= ERROR_SUCCESS
;
1330 /******************************************************************************
1331 * ADVAPI_ApplyRestrictions [internal]
1333 * Helper function for RegGetValueA/W.
1335 VOID
ADVAPI_ApplyRestrictions( DWORD dwFlags
, DWORD dwType
, DWORD cbData
,
1338 /* Check if the type is restricted by the passed flags */
1339 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1345 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1346 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1347 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1348 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1349 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1350 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1351 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1354 if (dwFlags
& dwMask
)
1356 /* Type is not restricted, check for size mismatch */
1357 if (dwType
== REG_BINARY
)
1361 if ((dwFlags
& RRF_RT_DWORD
) == RRF_RT_DWORD
)
1363 else if ((dwFlags
& RRF_RT_DWORD
) == RRF_RT_QWORD
)
1366 if (cbExpect
&& cbData
!= cbExpect
)
1367 *ret
= ERROR_DATATYPE_MISMATCH
;
1370 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1375 /******************************************************************************
1376 * RegGetValueW [ADVAPI32.@]
1378 * Retrieves the type and data for a value name associated with a key
1379 * optionally expanding it's content and restricting it's type.
1382 * hKey [I] Handle to an open key.
1383 * pszSubKey [I] Name of the subkey of hKey.
1384 * pszValue [I] Name of value under hKey/szSubKey to query.
1385 * dwFlags [I] Flags restricting the value type to retrieve.
1386 * pdwType [O] Destination for the values type, may be NULL.
1387 * pvData [O] Destination for the values content, may be NULL.
1388 * pcbData [I/O] Size of pvData, updated with the size required to
1389 * retrieve the whole content.
1392 * Success: ERROR_SUCCESS
1393 * Failure: nonzero error code from Winerror.h
1396 * - Unless RRF_NOEXPAND is specified REG_EXPAND_SZ is automatically expanded
1397 * and REG_SZ is retrieved instead.
1398 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1399 * without RRF_NOEXPAND is thus not allowed.
1401 LONG WINAPI
RegGetValueW( HKEY hKey
, LPCWSTR pszSubKey
, LPCWSTR pszValue
,
1402 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1405 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1409 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1410 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1411 pvData
, pcbData
, cbData
);
1413 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
))
1414 return ERROR_INVALID_PARAMETER
;
1416 if (pszSubKey
&& pszSubKey
[0])
1418 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1419 if (ret
!= ERROR_SUCCESS
) return ret
;
1422 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1424 /* If we are going to expand we need to read in the whole the value even
1425 * if the passed buffer was too small as the expanded string might be
1426 * smaller than the unexpanded one and could fit into cbData bytes. */
1427 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1428 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
1431 if (pvBuf
) HeapFree(GetProcessHeap(), 0, pvBuf
);
1433 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1436 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1440 if (ret
== ERROR_MORE_DATA
)
1441 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
1442 &dwType
, pvBuf
, &cbData
);
1445 /* Even if cbData was large enough we have to copy the
1446 * string since ExpandEnvironmentStrings can't handle
1447 * overlapping buffers. */
1448 CopyMemory(pvBuf
, pvData
, cbData
);
1451 /* Both the type or the value itself could have been modified in
1452 * between so we have to keep retrying until the buffer is large
1453 * enough or we no longer have to expand the value. */
1454 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1456 if (ret
== ERROR_SUCCESS
)
1458 if (dwType
== REG_EXPAND_SZ
)
1460 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
1461 pcbData
? *pcbData
: 0);
1463 if(pcbData
&& cbData
> *pcbData
)
1464 ret
= ERROR_MORE_DATA
;
1467 CopyMemory(pvData
, pvBuf
, *pcbData
);
1470 if (pvBuf
) HeapFree(GetProcessHeap(), 0, pvBuf
);
1473 if (pszSubKey
&& pszSubKey
[0])
1476 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1478 if (pcbData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1479 ZeroMemory(pvData
, *pcbData
);
1481 if (pdwType
) *pdwType
= dwType
;
1482 if (pcbData
) *pcbData
= cbData
;
1488 /******************************************************************************
1489 * RegGetValueA [ADVAPI32.@]
1493 LONG WINAPI
RegGetValueA( HKEY hKey
, LPCSTR pszSubKey
, LPCSTR pszValue
,
1494 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1497 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1501 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1502 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
1505 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
))
1506 return ERROR_INVALID_PARAMETER
;
1508 if (pszSubKey
&& pszSubKey
[0])
1510 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1511 if (ret
!= ERROR_SUCCESS
) return ret
;
1514 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1516 /* If we are going to expand we need to read in the whole the value even
1517 * if the passed buffer was too small as the expanded string might be
1518 * smaller than the unexpanded one and could fit into cbData bytes. */
1519 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1520 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
1523 if (pvBuf
) HeapFree(GetProcessHeap(), 0, pvBuf
);
1525 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1528 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1532 if (ret
== ERROR_MORE_DATA
)
1533 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
1534 &dwType
, pvBuf
, &cbData
);
1537 /* Even if cbData was large enough we have to copy the
1538 * string since ExpandEnvironmentStrings can't handle
1539 * overlapping buffers. */
1540 CopyMemory(pvBuf
, pvData
, cbData
);
1543 /* Both the type or the value itself could have been modified in
1544 * between so we have to keep retrying until the buffer is large
1545 * enough or we no longer have to expand the value. */
1546 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1548 if (ret
== ERROR_SUCCESS
)
1550 if (dwType
== REG_EXPAND_SZ
)
1552 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
1553 pcbData
? *pcbData
: 0);
1555 if(pcbData
&& cbData
> *pcbData
)
1556 ret
= ERROR_MORE_DATA
;
1559 CopyMemory(pvData
, pvBuf
, *pcbData
);
1562 if (pvBuf
) HeapFree(GetProcessHeap(), 0, pvBuf
);
1565 if (pszSubKey
&& pszSubKey
[0])
1568 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1570 if (pcbData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1571 ZeroMemory(pvData
, *pcbData
);
1573 if (pdwType
) *pdwType
= dwType
;
1574 if (pcbData
) *pcbData
= cbData
;
1580 /******************************************************************************
1581 * RegEnumValueW [ADVAPI32.@]
1584 * hkey [I] Handle to key to query
1585 * index [I] Index of value to query
1586 * value [O] Value string
1587 * val_count [I/O] Size of value buffer (in wchars)
1588 * reserved [I] Reserved
1589 * type [O] Type code
1590 * data [O] Value data
1591 * count [I/O] Size of data buffer (in bytes)
1594 * Success: ERROR_SUCCESS
1595 * Failure: nonzero error code from Winerror.h
1598 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
1599 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1603 char buffer
[256], *buf_ptr
= buffer
;
1604 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1605 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1607 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1608 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1610 /* NT only checks count, not val_count */
1611 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1612 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1614 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1615 if (data
) total_size
+= *count
;
1616 total_size
= min( sizeof(buffer
), total_size
);
1618 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1619 buffer
, total_size
, &total_size
);
1620 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1624 /* retry with a dynamically allocated buffer */
1625 while (status
== STATUS_BUFFER_OVERFLOW
)
1627 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1628 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1629 return ERROR_NOT_ENOUGH_MEMORY
;
1630 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1631 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1632 buf_ptr
, total_size
, &total_size
);
1635 if (status
) goto done
;
1639 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
1641 status
= STATUS_BUFFER_OVERFLOW
;
1644 memcpy( value
, info
->Name
, info
->NameLength
);
1645 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
1646 value
[*val_count
] = 0;
1651 if (total_size
- info
->DataOffset
> *count
)
1653 status
= STATUS_BUFFER_OVERFLOW
;
1656 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1657 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1659 /* if the type is REG_SZ and data is not 0-terminated
1660 * and there is enough space in the buffer NT appends a \0 */
1661 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
1662 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1666 else status
= STATUS_SUCCESS
;
1669 if (type
) *type
= info
->Type
;
1670 if (count
) *count
= info
->DataLength
;
1673 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1674 return RtlNtStatusToDosError(status
);
1678 /******************************************************************************
1679 * RegEnumValueA [ADVAPI32.@]
1683 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1684 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1688 char buffer
[256], *buf_ptr
= buffer
;
1689 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1690 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1692 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1693 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1695 /* NT only checks count, not val_count */
1696 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1697 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1699 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1700 if (data
) total_size
+= *count
;
1701 total_size
= min( sizeof(buffer
), total_size
);
1703 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1704 buffer
, total_size
, &total_size
);
1705 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1707 /* we need to fetch the contents for a string type even if not requested,
1708 * because we need to compute the length of the ASCII string. */
1709 if (value
|| data
|| is_string(info
->Type
))
1711 /* retry with a dynamically allocated buffer */
1712 while (status
== STATUS_BUFFER_OVERFLOW
)
1714 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1715 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1716 return ERROR_NOT_ENOUGH_MEMORY
;
1717 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1718 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1719 buf_ptr
, total_size
, &total_size
);
1722 if (status
) goto done
;
1724 if (is_string(info
->Type
))
1727 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1728 total_size
- info
->DataOffset
);
1731 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1734 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1735 total_size
- info
->DataOffset
);
1736 /* if the type is REG_SZ and data is not 0-terminated
1737 * and there is enough space in the buffer NT appends a \0 */
1738 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1741 info
->DataLength
= len
;
1745 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1746 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1749 if (value
&& !status
)
1753 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
1754 if (len
>= *val_count
)
1756 status
= STATUS_BUFFER_OVERFLOW
;
1759 len
= *val_count
- 1;
1760 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1766 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1772 else status
= STATUS_SUCCESS
;
1774 if (type
) *type
= info
->Type
;
1775 if (count
) *count
= info
->DataLength
;
1778 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1779 return RtlNtStatusToDosError(status
);
1784 /******************************************************************************
1785 * RegDeleteValueW [ADVAPI32.@]
1787 * See RegDeleteValueA.
1789 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
1791 UNICODE_STRING nameW
;
1793 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1795 RtlInitUnicodeString( &nameW
, name
);
1796 return RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
1800 /******************************************************************************
1801 * RegDeleteValueA [ADVAPI32.@]
1803 * Delete a value from the registry.
1806 * hkey [I] Registry handle of the key holding the value
1807 * name [I] Name of the value under hkey to delete
1810 * Success: ERROR_SUCCESS
1811 * Failure: nonzero error code from Winerror.h
1813 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
1818 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1820 RtlInitAnsiString( &nameA
, name
);
1821 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
1823 status
= NtDeleteValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
);
1824 return RtlNtStatusToDosError( status
);
1828 /******************************************************************************
1829 * RegLoadKeyW [ADVAPI32.@]
1832 * hkey [I] Handle of open key
1833 * subkey [I] Address of name of subkey
1834 * filename [I] Address of filename for registry information
1837 * Success: ERROR_SUCCES
1838 * Failure: nonzero error code from Winerror.h
1840 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
1842 OBJECT_ATTRIBUTES destkey
, file
;
1843 UNICODE_STRING subkeyW
, filenameW
;
1845 if (!(hkey
= get_special_root_hkey(hkey
))) return ERROR_INVALID_HANDLE
;
1847 destkey
.Length
= sizeof(destkey
);
1848 destkey
.RootDirectory
= hkey
; /* root key: HKLM or HKU */
1849 destkey
.ObjectName
= &subkeyW
; /* name of the key */
1850 destkey
.Attributes
= 0;
1851 destkey
.SecurityDescriptor
= NULL
;
1852 destkey
.SecurityQualityOfService
= NULL
;
1853 RtlInitUnicodeString(&subkeyW
, subkey
);
1855 file
.Length
= sizeof(file
);
1856 file
.RootDirectory
= NULL
;
1857 file
.ObjectName
= &filenameW
; /* file containing the hive */
1858 file
.Attributes
= OBJ_CASE_INSENSITIVE
;
1859 file
.SecurityDescriptor
= NULL
;
1860 file
.SecurityQualityOfService
= NULL
;
1861 RtlDosPathNameToNtPathName_U(filename
, &filenameW
, NULL
, NULL
);
1863 return RtlNtStatusToDosError( NtLoadKey(&destkey
, &file
) );
1867 /******************************************************************************
1868 * RegLoadKeyA [ADVAPI32.@]
1872 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
1874 UNICODE_STRING subkeyW
, filenameW
;
1875 STRING subkeyA
, filenameA
;
1878 RtlInitAnsiString(&subkeyA
, subkey
);
1879 RtlInitAnsiString(&filenameA
, filename
);
1881 if ((status
= RtlAnsiStringToUnicodeString(&subkeyW
, &subkeyA
, TRUE
)))
1882 return RtlNtStatusToDosError(status
);
1884 if ((status
= RtlAnsiStringToUnicodeString(&filenameW
, &filenameA
, TRUE
)))
1885 return RtlNtStatusToDosError(status
);
1887 return RegLoadKeyW(hkey
, subkeyW
.Buffer
, filenameW
.Buffer
);
1891 /******************************************************************************
1892 * RegSaveKeyW [ADVAPI32.@]
1895 * hkey [I] Handle of key where save begins
1896 * lpFile [I] Address of filename to save to
1897 * sa [I] Address of security structure
1900 * Success: ERROR_SUCCESS
1901 * Failure: nonzero error code from Winerror.h
1903 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
1905 static const WCHAR format
[] =
1906 {'r','e','g','%','0','4','x','.','t','m','p',0};
1907 WCHAR buffer
[MAX_PATH
];
1913 TRACE( "(%p,%s,%p)\n", hkey
, debugstr_w(file
), sa
);
1915 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
1916 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1918 err
= GetLastError();
1919 GetFullPathNameW( file
, sizeof(buffer
)/sizeof(WCHAR
), buffer
, &nameW
);
1923 snprintfW( nameW
, 16, format
, count
++ );
1924 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
1925 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
1926 if (handle
!= INVALID_HANDLE_VALUE
) break;
1927 if ((ret
= GetLastError()) != ERROR_ALREADY_EXISTS
) goto done
;
1929 /* Something gone haywire ? Please report if this happens abnormally */
1931 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
);
1934 ret
= RtlNtStatusToDosError(NtSaveKey(hkey
, handle
));
1936 CloseHandle( handle
);
1939 if (!MoveFileExW( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
1941 ERR( "Failed to move %s to %s\n", debugstr_w(buffer
),
1943 ret
= GetLastError();
1946 if (ret
) DeleteFileW( buffer
);
1949 SetLastError( err
); /* restore last error code */
1954 /******************************************************************************
1955 * RegSaveKeyA [ADVAPI32.@]
1959 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
1961 UNICODE_STRING
*fileW
= &NtCurrentTeb()->StaticUnicodeString
;
1965 RtlInitAnsiString(&fileA
, file
);
1966 if ((status
= RtlAnsiStringToUnicodeString(fileW
, &fileA
, FALSE
)))
1967 return RtlNtStatusToDosError( status
);
1968 return RegSaveKeyW(hkey
, fileW
->Buffer
, sa
);
1972 /******************************************************************************
1973 * RegRestoreKeyW [ADVAPI32.@]
1976 * hkey [I] Handle of key where restore begins
1977 * lpFile [I] Address of filename containing saved tree
1978 * dwFlags [I] Optional flags
1981 * Success: ERROR_SUCCESS
1982 * Failure: nonzero error code from Winerror.h
1984 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1986 TRACE("(%p,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1988 /* It seems to do this check before the hkey check */
1989 if (!lpFile
|| !*lpFile
)
1990 return ERROR_INVALID_PARAMETER
;
1992 FIXME("(%p,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1994 /* Check for file existence */
1996 return ERROR_SUCCESS
;
2000 /******************************************************************************
2001 * RegRestoreKeyA [ADVAPI32.@]
2003 * see RegRestoreKeyW
2005 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
2007 UNICODE_STRING lpFileW
;
2010 RtlCreateUnicodeStringFromAsciiz( &lpFileW
, lpFile
);
2011 ret
= RegRestoreKeyW( hkey
, lpFileW
.Buffer
, dwFlags
);
2012 RtlFreeUnicodeString( &lpFileW
);
2017 /******************************************************************************
2018 * RegUnLoadKeyW [ADVAPI32.@]
2021 * hkey [I] Handle of open key
2022 * lpSubKey [I] Address of name of subkey to unload
2025 * Success: ERROR_SUCCESS
2026 * Failure: nonzero error code from Winerror.h
2028 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
2033 TRACE("(%p,%s)\n",hkey
, debugstr_w(lpSubKey
));
2035 ret
= RegOpenKeyW(hkey
,lpSubKey
,&shkey
);
2037 return ERROR_INVALID_PARAMETER
;
2039 ret
= RtlNtStatusToDosError(NtUnloadKey(shkey
));
2047 /******************************************************************************
2048 * RegUnLoadKeyA [ADVAPI32.@]
2052 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
2054 UNICODE_STRING lpSubKeyW
;
2057 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2058 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
.Buffer
);
2059 RtlFreeUnicodeString( &lpSubKeyW
);
2064 /******************************************************************************
2065 * RegReplaceKeyW [ADVAPI32.@]
2068 * hkey [I] Handle of open key
2069 * lpSubKey [I] Address of name of subkey
2070 * lpNewFile [I] Address of filename for file with new data
2071 * lpOldFile [I] Address of filename for backup file
2074 * Success: ERROR_SUCCESS
2075 * Failure: nonzero error code from Winerror.h
2077 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
2080 FIXME("(%p,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
2081 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
2082 return ERROR_SUCCESS
;
2086 /******************************************************************************
2087 * RegReplaceKeyA [ADVAPI32.@]
2089 * see RegReplaceKeyW
2091 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
2094 UNICODE_STRING lpSubKeyW
;
2095 UNICODE_STRING lpNewFileW
;
2096 UNICODE_STRING lpOldFileW
;
2099 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2100 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW
, lpOldFile
);
2101 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW
, lpNewFile
);
2102 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
.Buffer
, lpNewFileW
.Buffer
, lpOldFileW
.Buffer
);
2103 RtlFreeUnicodeString( &lpOldFileW
);
2104 RtlFreeUnicodeString( &lpNewFileW
);
2105 RtlFreeUnicodeString( &lpSubKeyW
);
2110 /******************************************************************************
2111 * RegSetKeySecurity [ADVAPI32.@]
2114 * hkey [I] Open handle of key to set
2115 * SecurityInfo [I] Descriptor contents
2116 * pSecurityDesc [I] Address of descriptor for key
2119 * Success: ERROR_SUCCESS
2120 * Failure: nonzero error code from Winerror.h
2122 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
2123 PSECURITY_DESCRIPTOR pSecurityDesc
)
2125 TRACE("(%p,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
2127 /* It seems to perform this check before the hkey check */
2128 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
2129 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
2130 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
2131 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
2134 return ERROR_INVALID_PARAMETER
;
2137 return ERROR_INVALID_PARAMETER
;
2139 FIXME(":(%p,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
2141 return ERROR_SUCCESS
;
2145 /******************************************************************************
2146 * RegGetKeySecurity [ADVAPI32.@]
2148 * Get a copy of the security descriptor for a given registry key.
2151 * hkey [I] Open handle of key to set
2152 * SecurityInformation [I] Descriptor contents
2153 * pSecurityDescriptor [O] Address of descriptor for key
2154 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2157 * Success: ERROR_SUCCESS
2158 * Failure: Error code
2160 LONG WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
2161 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2162 LPDWORD lpcbSecurityDescriptor
)
2164 TRACE("(%p,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
2165 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
2167 /* FIXME: Check for valid SecurityInformation values */
2169 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
2170 return ERROR_INSUFFICIENT_BUFFER
;
2172 FIXME("(%p,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
2173 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
2175 /* Do not leave security descriptor filled with garbage */
2176 RtlCreateSecurityDescriptor(pSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
2178 return ERROR_SUCCESS
;
2182 /******************************************************************************
2183 * RegFlushKey [ADVAPI32.@]
2185 * Immediately write a registry key to registry.
2188 * hkey [I] Handle of key to write
2191 * Success: ERROR_SUCCESS
2192 * Failure: Error code
2194 DWORD WINAPI
RegFlushKey( HKEY hkey
)
2196 hkey
= get_special_root_hkey( hkey
);
2197 if (!hkey
) return ERROR_INVALID_HANDLE
;
2199 return RtlNtStatusToDosError( NtFlushKey( hkey
) );
2203 /******************************************************************************
2204 * RegConnectRegistryW [ADVAPI32.@]
2207 * lpMachineName [I] Address of name of remote computer
2208 * hHey [I] Predefined registry handle
2209 * phkResult [I] Address of buffer for remote registry handle
2212 * Success: ERROR_SUCCESS
2213 * Failure: nonzero error code from Winerror.h
2215 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
2220 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
2222 if (!lpMachineName
|| !*lpMachineName
) {
2223 /* Use the local machine name */
2224 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
2227 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
2228 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
2230 /* MSDN says lpMachineName must start with \\ : not so */
2231 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
2233 if (GetComputerNameW(compName
, &len
))
2235 if (!strcmpiW(lpMachineName
, compName
))
2236 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
2239 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
2240 ret
= ERROR_BAD_NETPATH
;
2244 ret
= GetLastError();
2250 /******************************************************************************
2251 * RegConnectRegistryA [ADVAPI32.@]
2253 * see RegConnectRegistryW
2255 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, PHKEY reskey
)
2257 UNICODE_STRING machineW
;
2260 RtlCreateUnicodeStringFromAsciiz( &machineW
, machine
);
2261 ret
= RegConnectRegistryW( machineW
.Buffer
, hkey
, reskey
);
2262 RtlFreeUnicodeString( &machineW
);
2267 /******************************************************************************
2268 * RegNotifyChangeKeyValue [ADVAPI32.@]
2271 * hkey [I] Handle of key to watch
2272 * fWatchSubTree [I] Flag for subkey notification
2273 * fdwNotifyFilter [I] Changes to be reported
2274 * hEvent [I] Handle of signaled event
2275 * fAsync [I] Flag for asynchronous reporting
2278 * Success: ERROR_SUCCESS
2279 * Failure: nonzero error code from Winerror.h
2281 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
2282 DWORD fdwNotifyFilter
, HANDLE hEvent
,
2286 IO_STATUS_BLOCK iosb
;
2288 hkey
= get_special_root_hkey( hkey
);
2289 if (!hkey
) return ERROR_INVALID_HANDLE
;
2291 TRACE("(%p,%i,%ld,%p,%i)\n", hkey
, fWatchSubTree
, fdwNotifyFilter
,
2294 status
= NtNotifyChangeKey( hkey
, hEvent
, NULL
, NULL
, &iosb
,
2295 fdwNotifyFilter
, fWatchSubTree
, NULL
, 0,
2298 if (status
&& status
!= STATUS_TIMEOUT
)
2299 return RtlNtStatusToDosError( status
);
2301 return ERROR_SUCCESS
;
2304 /******************************************************************************
2305 * RegOpenUserClassesRoot [ADVAPI32.@]
2307 * Open the HKEY_CLASSES_ROOT key for a user.
2310 * hToken [I] Handle of token representing the user
2311 * dwOptions [I] Reserved, nust be 0
2312 * samDesired [I] Desired access rights
2313 * phkResult [O] Destination for the resulting key handle
2316 * Success: ERROR_SUCCESS
2317 * Failure: nonzero error code from Winerror.h
2320 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2321 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2322 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2324 LONG WINAPI
RegOpenUserClassesRoot(
2331 FIXME("(%p, 0x%lx, 0x%lx, %p) semi-stub\n", hToken
, dwOptions
, samDesired
, phkResult
);
2333 *phkResult
= HKEY_CLASSES_ROOT
;
2334 return ERROR_SUCCESS
;