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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #define WIN32_NO_STATUS
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
47 /* allowed bits for access mask */
48 #define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
50 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
51 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
52 #define NB_SPECIAL_ROOT_KEYS ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
54 static HKEY special_root_keys
[NB_SPECIAL_ROOT_KEYS
];
56 static const WCHAR name_CLASSES_ROOT
[] =
57 {'M','a','c','h','i','n','e','\\',
58 'S','o','f','t','w','a','r','e','\\',
59 'C','l','a','s','s','e','s',0};
60 static const WCHAR name_LOCAL_MACHINE
[] =
61 {'M','a','c','h','i','n','e',0};
62 static const WCHAR name_USERS
[] =
64 static const WCHAR name_PERFORMANCE_DATA
[] =
65 {'P','e','r','f','D','a','t','a',0};
66 static const WCHAR name_CURRENT_CONFIG
[] =
67 {'M','a','c','h','i','n','e','\\',
68 'S','y','s','t','e','m','\\',
69 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
70 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
71 'C','u','r','r','e','n','t',0};
72 static const WCHAR name_DYN_DATA
[] =
73 {'D','y','n','D','a','t','a',0};
75 #define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
76 static UNICODE_STRING root_key_names
[NB_SPECIAL_ROOT_KEYS
] =
78 DECL_STR(CLASSES_ROOT
),
79 { 0, 0, NULL
}, /* HKEY_CURRENT_USER is determined dynamically */
80 DECL_STR(LOCAL_MACHINE
),
82 DECL_STR(PERFORMANCE_DATA
),
83 DECL_STR(CURRENT_CONFIG
),
89 /* check if value type needs string conversion (Ansi<->Unicode) */
90 inline static int is_string( DWORD type
)
92 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
95 /* check if current version is NT or Win95 */
96 inline static int is_version_nt(void)
98 return !(GetVersion() & 0x80000000);
101 /* create one of the HKEY_* special root keys */
102 static HKEY
create_special_root_hkey( HANDLE hkey
, DWORD access
)
105 int idx
= (UINT_PTR
)hkey
- (UINT_PTR
)HKEY_SPECIAL_ROOT_FIRST
;
107 if (hkey
== HKEY_CURRENT_USER
)
109 if (RtlOpenCurrentUser( access
, &hkey
)) return 0;
110 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey
);
114 OBJECT_ATTRIBUTES attr
;
116 attr
.Length
= sizeof(attr
);
117 attr
.RootDirectory
= 0;
118 attr
.ObjectName
= &root_key_names
[idx
];
120 attr
.SecurityDescriptor
= NULL
;
121 attr
.SecurityQualityOfService
= NULL
;
122 if (NtCreateKey( &hkey
, access
, &attr
, 0, NULL
, 0, NULL
)) return 0;
123 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
126 if (!(ret
= InterlockedCompareExchangePointer( (void **)&special_root_keys
[idx
], hkey
, 0 )))
129 NtClose( hkey
); /* somebody beat us to it */
133 /* map the hkey from special root to normal key if necessary */
134 inline static HKEY
get_special_root_hkey( HKEY hkey
)
138 if ((hkey
>= HKEY_SPECIAL_ROOT_FIRST
) && (hkey
<= HKEY_SPECIAL_ROOT_LAST
))
140 if (!(ret
= special_root_keys
[(UINT_PTR
)hkey
- (UINT_PTR
)HKEY_SPECIAL_ROOT_FIRST
]))
141 ret
= create_special_root_hkey( hkey
, KEY_ALL_ACCESS
);
147 /******************************************************************************
148 * RegCreateKeyExW [ADVAPI32.@]
150 * See RegCreateKeyExA.
152 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
153 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
154 PHKEY retkey
, LPDWORD dispos
)
156 OBJECT_ATTRIBUTES attr
;
157 UNICODE_STRING nameW
, classW
;
159 if (reserved
) return ERROR_INVALID_PARAMETER
;
160 if (!(access
& KEY_ACCESS_MASK
) || (access
& ~KEY_ACCESS_MASK
)) return ERROR_ACCESS_DENIED
;
161 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
163 attr
.Length
= sizeof(attr
);
164 attr
.RootDirectory
= hkey
;
165 attr
.ObjectName
= &nameW
;
167 attr
.SecurityDescriptor
= NULL
;
168 attr
.SecurityQualityOfService
= NULL
;
169 RtlInitUnicodeString( &nameW
, name
);
170 RtlInitUnicodeString( &classW
, class );
172 return RtlNtStatusToDosError( NtCreateKey( (PHANDLE
)retkey
, access
, &attr
, 0,
173 &classW
, options
, dispos
) );
177 /******************************************************************************
178 * RegCreateKeyExA [ADVAPI32.@]
180 * Open a registry key, creating it if it doesn't exist.
183 * hkey [I] Handle of the parent registry key
184 * name [I] Name of the new key to open or create
185 * reserved [I] Reserved, pass 0
186 * class [I] The object type of the new key
187 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
188 * access [I] Access level desired
189 * sa [I] Security attributes for the key
190 * retkey [O] Destination for the resulting handle
191 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
194 * Success: ERROR_SUCCESS.
195 * Failure: A standard Win32 error code. retkey remains untouched.
198 * MAXIMUM_ALLOWED in access mask not supported by server
200 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
201 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
202 PHKEY retkey
, LPDWORD dispos
)
204 OBJECT_ATTRIBUTES attr
;
205 UNICODE_STRING classW
;
206 ANSI_STRING nameA
, classA
;
209 if (reserved
) return ERROR_INVALID_PARAMETER
;
210 if (!is_version_nt())
212 access
= KEY_ALL_ACCESS
; /* Win95 ignores the access mask */
213 if (name
&& *name
== '\\') name
++; /* win9x,ME ignores one (and only one) beginning backslash */
215 else if (!(access
& KEY_ACCESS_MASK
) || (access
& ~KEY_ACCESS_MASK
)) return ERROR_ACCESS_DENIED
;
216 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
218 attr
.Length
= sizeof(attr
);
219 attr
.RootDirectory
= hkey
;
220 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
222 attr
.SecurityDescriptor
= NULL
;
223 attr
.SecurityQualityOfService
= NULL
;
224 RtlInitAnsiString( &nameA
, name
);
225 RtlInitAnsiString( &classA
, class );
227 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
230 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
232 status
= NtCreateKey( (PHANDLE
)retkey
, access
, &attr
, 0, &classW
, options
, dispos
);
233 RtlFreeUnicodeString( &classW
);
236 return RtlNtStatusToDosError( status
);
240 /******************************************************************************
241 * RegCreateKeyW [ADVAPI32.@]
243 * Creates the specified reg key.
246 * hKey [I] Handle to an open key.
247 * lpSubKey [I] Name of a key that will be opened or created.
248 * phkResult [O] Receives a handle to the opened or created key.
251 * Success: ERROR_SUCCESS
252 * Failure: nonzero error code defined in Winerror.h
254 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpSubKey
, PHKEY phkResult
)
256 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
257 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
258 return RegCreateKeyExW( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
259 KEY_ALL_ACCESS
, NULL
, phkResult
, NULL
);
263 /******************************************************************************
264 * RegCreateKeyA [ADVAPI32.@]
268 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpSubKey
, PHKEY phkResult
)
270 return RegCreateKeyExA( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
271 KEY_ALL_ACCESS
, NULL
, phkResult
, NULL
);
276 /******************************************************************************
277 * RegOpenKeyExW [ADVAPI32.@]
281 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, REGSAM access
, PHKEY retkey
)
283 OBJECT_ATTRIBUTES attr
;
284 UNICODE_STRING nameW
;
286 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
288 attr
.Length
= sizeof(attr
);
289 attr
.RootDirectory
= hkey
;
290 attr
.ObjectName
= &nameW
;
292 attr
.SecurityDescriptor
= NULL
;
293 attr
.SecurityQualityOfService
= NULL
;
294 RtlInitUnicodeString( &nameW
, name
);
295 return RtlNtStatusToDosError( NtOpenKey( (PHANDLE
)retkey
, access
, &attr
) );
299 /******************************************************************************
300 * RegOpenKeyExA [ADVAPI32.@]
302 * Open a registry key.
305 * hkey [I] Handle of open key
306 * name [I] Name of subkey to open
307 * reserved [I] Reserved - must be zero
308 * access [I] Security access mask
309 * retkey [O] Handle to open key
312 * Success: ERROR_SUCCESS
313 * Failure: A standard Win32 error code. retkey is set to 0.
316 * Unlike RegCreateKeyExA(), this function will not create the key if it
319 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, REGSAM access
, PHKEY retkey
)
321 OBJECT_ATTRIBUTES attr
;
325 if (!is_version_nt()) access
= KEY_ALL_ACCESS
; /* Win95 ignores the access mask */
327 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
329 attr
.Length
= sizeof(attr
);
330 attr
.RootDirectory
= hkey
;
331 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
333 attr
.SecurityDescriptor
= NULL
;
334 attr
.SecurityQualityOfService
= NULL
;
336 RtlInitAnsiString( &nameA
, name
);
337 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
340 status
= NtOpenKey( (PHANDLE
)retkey
, access
, &attr
);
342 return RtlNtStatusToDosError( status
);
346 /******************************************************************************
347 * RegOpenKeyW [ADVAPI32.@]
351 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, PHKEY retkey
)
356 return ERROR_SUCCESS
;
358 return RegOpenKeyExW( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
362 /******************************************************************************
363 * RegOpenKeyA [ADVAPI32.@]
365 * Open a registry key.
368 * hkey [I] Handle of parent key to open the new key under
369 * name [I] Name of the key under hkey to open
370 * retkey [O] Destination for the resulting Handle
373 * Success: ERROR_SUCCESS
374 * Failure: A standard Win32 error code. retkey is set to 0.
376 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, PHKEY retkey
)
381 return ERROR_SUCCESS
;
383 return RegOpenKeyExA( hkey
, name
, 0, KEY_ALL_ACCESS
, retkey
);
387 /******************************************************************************
388 * RegOpenCurrentUser [ADVAPI32.@]
390 * Get a handle to the HKEY_CURRENT_USER key for the user
391 * the current thread is impersonating.
394 * access [I] Desired access rights to the key
395 * retkey [O] Handle to the opened key
398 * Success: ERROR_SUCCESS
399 * Failure: nonzero error code from Winerror.h
402 * This function is supposed to retrieve a handle to the
403 * HKEY_CURRENT_USER for the user the current thread is impersonating.
404 * Since Wine does not currently allow threads to impersonate other users,
405 * this stub should work fine.
407 DWORD WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
409 return RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
414 /******************************************************************************
415 * RegEnumKeyExW [ADVAPI32.@]
417 * Enumerate subkeys of the specified open registry key.
420 * hkey [I] Handle to key to enumerate
421 * index [I] Index of subkey to enumerate
422 * name [O] Buffer for subkey name
423 * name_len [O] Size of subkey buffer
424 * reserved [I] Reserved
425 * class [O] Buffer for class string
426 * class_len [O] Size of class buffer
427 * ft [O] Time key last written to
430 * Success: ERROR_SUCCESS
431 * Failure: System error code. If there are no more subkeys available, the
432 * function returns ERROR_NO_MORE_ITEMS.
434 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
435 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
438 char buffer
[256], *buf_ptr
= buffer
;
439 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
442 TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
443 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
445 if (reserved
) return ERROR_INVALID_PARAMETER
;
446 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
448 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
449 buffer
, sizeof(buffer
), &total_size
);
451 while (status
== STATUS_BUFFER_OVERFLOW
)
453 /* retry with a dynamically allocated buffer */
454 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
455 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
456 return ERROR_NOT_ENOUGH_MEMORY
;
457 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
458 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
459 buf_ptr
, total_size
, &total_size
);
464 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
465 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
467 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
469 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
470 status
= STATUS_BUFFER_OVERFLOW
;
474 memcpy( name
, info
->Name
, info
->NameLength
);
478 *class_len
= cls_len
;
481 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
488 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
489 return RtlNtStatusToDosError( status
);
493 /******************************************************************************
494 * RegEnumKeyExA [ADVAPI32.@]
498 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
499 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
502 char buffer
[256], *buf_ptr
= buffer
;
503 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
506 TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
507 name_len
? *name_len
: -1, reserved
, class, class_len
, ft
);
509 if (reserved
) return ERROR_INVALID_PARAMETER
;
510 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
512 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
513 buffer
, sizeof(buffer
), &total_size
);
515 while (status
== STATUS_BUFFER_OVERFLOW
)
517 /* retry with a dynamically allocated buffer */
518 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
519 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
520 return ERROR_NOT_ENOUGH_MEMORY
;
521 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
522 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
523 buf_ptr
, total_size
, &total_size
);
530 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
531 RtlUnicodeToMultiByteSize( &cls_len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
533 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
535 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
536 status
= STATUS_BUFFER_OVERFLOW
;
540 RtlUnicodeToMultiByteN( name
, len
, NULL
, info
->Name
, info
->NameLength
);
544 *class_len
= cls_len
;
547 RtlUnicodeToMultiByteN( class, cls_len
, NULL
,
548 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
556 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
557 return RtlNtStatusToDosError( status
);
561 /******************************************************************************
562 * RegEnumKeyW [ADVAPI32.@]
564 * Enumerates subkyes of the specified open reg key.
567 * hKey [I] Handle to an open key.
568 * dwIndex [I] Index of the subkey of hKey to retrieve.
569 * lpName [O] Name of the subkey.
570 * cchName [I] Size of lpName in TCHARS.
573 * Success: ERROR_SUCCESS
574 * Failure: system error code. If there are no more subkeys available, the
575 * function returns ERROR_NO_MORE_ITEMS.
577 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
579 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
583 /******************************************************************************
584 * RegEnumKeyA [ADVAPI32.@]
588 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
590 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
594 /******************************************************************************
595 * RegQueryInfoKeyW [ADVAPI32.@]
597 * Retrieves information about the specified registry key.
600 * hkey [I] Handle to key to query
601 * class [O] Buffer for class string
602 * class_len [O] Size of class string buffer
603 * reserved [I] Reserved
604 * subkeys [O] Buffer for number of subkeys
605 * max_subkey [O] Buffer for longest subkey name length
606 * max_class [O] Buffer for longest class string length
607 * values [O] Buffer for number of value entries
608 * max_value [O] Buffer for longest value name length
609 * max_data [O] Buffer for longest value data length
610 * security [O] Buffer for security descriptor length
611 * modif [O] Modification time
614 * Success: ERROR_SUCCESS
615 * Failure: system error code.
618 * - win95 allows class to be valid and class_len to be NULL
619 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
620 * - both allow class to be NULL and class_len to be NULL
621 * (it's hard to test validity, so test !NULL instead)
623 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
624 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
625 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
626 LPDWORD security
, FILETIME
*modif
)
629 char buffer
[256], *buf_ptr
= buffer
;
630 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
633 TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
634 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
636 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
637 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
639 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
640 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
644 /* retry with a dynamically allocated buffer */
645 while (status
== STATUS_BUFFER_OVERFLOW
)
647 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
648 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
649 return ERROR_NOT_ENOUGH_MEMORY
;
650 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
651 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
654 if (status
) goto done
;
656 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
658 status
= STATUS_BUFFER_OVERFLOW
;
662 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
663 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
666 else status
= STATUS_SUCCESS
;
668 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
669 if (subkeys
) *subkeys
= info
->SubKeys
;
670 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
671 if (max_class
) *max_class
= info
->MaxClassLen
;
672 if (values
) *values
= info
->Values
;
673 if (max_value
) *max_value
= info
->MaxValueNameLen
;
674 if (max_data
) *max_data
= info
->MaxValueDataLen
;
675 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
678 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
679 return RtlNtStatusToDosError( status
);
683 /******************************************************************************
684 * RegQueryMultipleValuesA [ADVAPI32.@]
686 * Retrieves the type and data for a list of value names associated with a key.
689 * hKey [I] Handle to an open key.
690 * val_list [O] Array of VALENT structures that describes the entries.
691 * num_vals [I] Number of elements in val_list.
692 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
693 * ldwTotsize [I/O] Size of lpValueBuf.
696 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
697 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
700 DWORD WINAPI
RegQueryMultipleValuesA(HKEY hkey
, PVALENTA val_list
, DWORD num_vals
,
701 LPSTR lpValueBuf
, LPDWORD ldwTotsize
)
704 DWORD maxBytes
= *ldwTotsize
;
706 LPSTR bufptr
= lpValueBuf
;
709 TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
711 for(i
=0; i
< num_vals
; ++i
)
714 val_list
[i
].ve_valuelen
=0;
715 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
716 if(status
!= ERROR_SUCCESS
)
721 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
723 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
724 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
725 if(status
!= ERROR_SUCCESS
)
730 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
732 bufptr
+= val_list
[i
].ve_valuelen
;
735 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
737 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
741 /******************************************************************************
742 * RegQueryMultipleValuesW [ADVAPI32.@]
744 * See RegQueryMultipleValuesA.
746 DWORD WINAPI
RegQueryMultipleValuesW(HKEY hkey
, PVALENTW val_list
, DWORD num_vals
,
747 LPWSTR lpValueBuf
, LPDWORD ldwTotsize
)
750 DWORD maxBytes
= *ldwTotsize
;
752 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
755 TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
757 for(i
=0; i
< num_vals
; ++i
)
759 val_list
[i
].ve_valuelen
=0;
760 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
761 if(status
!= ERROR_SUCCESS
)
766 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
768 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
769 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
770 if(status
!= ERROR_SUCCESS
)
775 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
777 bufptr
+= val_list
[i
].ve_valuelen
;
780 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
782 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
785 /******************************************************************************
786 * RegQueryInfoKeyA [ADVAPI32.@]
788 * Retrieves information about a registry key.
791 * hKey [I] Handle to an open key.
792 * lpClass [O] Class string of the key.
793 * lpcClass [I/O] size of lpClass.
794 * lpReserved [I] Reserved; must be NULL.
795 * lpcSubKeys [O] Number of subkeys contained by the key.
796 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
797 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
799 * lpcValues [O] Number of values associated with the key.
800 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
801 * lpcMaxValueLen [O] Longest data component among the key's values
802 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
803 * lpftLastWriteTime [O] FILETIME strucutre that is the last write time.
806 * Success: ERROR_SUCCESS
807 * Failure: nonzero error code from Winerror.h
809 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
810 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
811 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
812 LPDWORD security
, FILETIME
*modif
)
815 char buffer
[256], *buf_ptr
= buffer
;
816 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
817 DWORD total_size
, len
;
819 TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
820 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
822 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
823 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
825 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
826 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
828 if (class || class_len
)
830 /* retry with a dynamically allocated buffer */
831 while (status
== STATUS_BUFFER_OVERFLOW
)
833 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
834 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
835 return ERROR_NOT_ENOUGH_MEMORY
;
836 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
837 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
840 if (status
) goto done
;
842 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
), info
->ClassLength
);
845 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
848 if (class && !status
)
850 RtlUnicodeToMultiByteN( class, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
855 else status
= STATUS_SUCCESS
;
857 if (subkeys
) *subkeys
= info
->SubKeys
;
858 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
859 if (max_class
) *max_class
= info
->MaxClassLen
;
860 if (values
) *values
= info
->Values
;
861 if (max_value
) *max_value
= info
->MaxValueNameLen
;
862 if (max_data
) *max_data
= info
->MaxValueDataLen
;
863 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
866 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
867 return RtlNtStatusToDosError( status
);
871 /******************************************************************************
872 * RegCloseKey [ADVAPI32.@]
874 * Close an open registry key.
877 * hkey [I] Handle of key to close
880 * Success: ERROR_SUCCESS
881 * Failure: Error code
883 DWORD WINAPI
RegCloseKey( HKEY hkey
)
885 if (!hkey
) return ERROR_INVALID_HANDLE
;
886 if (hkey
>= (HKEY
)0x80000000) return ERROR_SUCCESS
;
887 return RtlNtStatusToDosError( NtClose( hkey
) );
891 /******************************************************************************
892 * RegDeleteKeyW [ADVAPI32.@]
896 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
901 if (!name
) return ERROR_INVALID_PARAMETER
;
903 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
905 if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, DELETE
, &tmp
)))
907 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
910 TRACE("%s ret=%08lx\n", debugstr_w(name
), ret
);
915 /******************************************************************************
916 * RegDeleteKeyA [ADVAPI32.@]
918 * Delete a registry key.
921 * hkey [I] Handle to parent key containing the key to delete
922 * name [I] Name of the key user hkey to delete
926 * MSDN is wrong when it says that hkey must be opened with the DELETE access
927 * right. In reality, it opens a new handle with DELETE access.
930 * Success: ERROR_SUCCESS
931 * Failure: Error code
933 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
938 if (!name
) return ERROR_INVALID_PARAMETER
;
940 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
942 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, DELETE
, &tmp
)))
944 if (!is_version_nt()) /* win95 does recursive key deletes */
948 while(!RegEnumKeyA(tmp
, 0, name
, sizeof(name
)))
950 if(RegDeleteKeyA(tmp
, name
)) /* recurse */
954 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
957 TRACE("%s ret=%08lx\n", debugstr_a(name
), ret
);
963 /******************************************************************************
964 * RegSetValueExW [ADVAPI32.@]
966 * Set the data and contents of a registry value.
969 * hkey [I] Handle of key to set value for
970 * name [I] Name of value to set
971 * reserved [I] Reserved, must be zero
972 * type [I] Type of the value being set
973 * data [I] The new contents of the value to set
974 * count [I] Size of data
977 * Success: ERROR_SUCCESS
978 * Failure: Error code
980 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
981 DWORD type
, CONST BYTE
*data
, DWORD count
)
983 UNICODE_STRING nameW
;
985 /* no need for version check, not implemented on win9x anyway */
986 if (count
&& is_string(type
))
988 LPCWSTR str
= (LPCWSTR
)data
;
989 /* if user forgot to count terminating null, add it (yes NT does this) */
990 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
991 count
+= sizeof(WCHAR
);
993 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
995 RtlInitUnicodeString( &nameW
, name
);
996 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
1000 /******************************************************************************
1001 * RegSetValueExA [ADVAPI32.@]
1003 * See RegSetValueExW.
1006 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1007 * NT does definitely care (aj)
1009 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1010 CONST BYTE
*data
, DWORD count
)
1013 WCHAR
*dataW
= NULL
;
1016 if (!is_version_nt()) /* win95 */
1020 if (!data
) return ERROR_INVALID_PARAMETER
;
1021 count
= strlen((const char *)data
) + 1;
1024 else if (count
&& is_string(type
))
1026 /* if user forgot to count terminating null, add it (yes NT does this) */
1027 if (data
[count
-1] && !data
[count
]) count
++;
1030 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1032 if (is_string( type
)) /* need to convert to Unicode */
1035 RtlMultiByteToUnicodeSize( &lenW
, (const char *)data
, count
);
1036 if (!(dataW
= HeapAlloc( GetProcessHeap(), 0, lenW
))) return ERROR_OUTOFMEMORY
;
1037 RtlMultiByteToUnicodeN( dataW
, lenW
, NULL
, (const char *)data
, count
);
1039 data
= (BYTE
*)dataW
;
1042 RtlInitAnsiString( &nameA
, name
);
1043 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
1046 status
= NtSetValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
, 0, type
, data
, count
);
1048 HeapFree( GetProcessHeap(), 0, dataW
);
1049 return RtlNtStatusToDosError( status
);
1053 /******************************************************************************
1054 * RegSetValueW [ADVAPI32.@]
1056 * Sets the data for the default or unnamed value of a reg key.
1059 * hKey [I] Handle to an open key.
1060 * lpSubKey [I] Name of a subkey of hKey.
1061 * dwType [I] Type of information to store.
1062 * lpData [I] String that contains the data to set for the default value.
1063 * cbData [I] Size of lpData.
1066 * Success: ERROR_SUCCESS
1067 * Failure: nonzero error code from Winerror.h
1069 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR name
, DWORD type
, LPCWSTR data
, DWORD count
)
1074 TRACE("(%p,%s,%ld,%s,%ld)\n", hkey
, debugstr_w(name
), type
, debugstr_w(data
), count
);
1076 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
1078 if (name
&& name
[0]) /* need to create the subkey */
1080 if ((ret
= RegCreateKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1083 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)data
,
1084 (strlenW( data
) + 1) * sizeof(WCHAR
) );
1085 if (subkey
!= hkey
) RegCloseKey( subkey
);
1090 /******************************************************************************
1091 * RegSetValueA [ADVAPI32.@]
1095 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1100 TRACE("(%p,%s,%ld,%s,%ld)\n", hkey
, debugstr_a(name
), type
, debugstr_a(data
), count
);
1102 if (type
!= REG_SZ
) return ERROR_INVALID_PARAMETER
;
1104 if (name
&& name
[0]) /* need to create the subkey */
1106 if ((ret
= RegCreateKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1108 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)data
, strlen(data
)+1 );
1109 if (subkey
!= hkey
) RegCloseKey( subkey
);
1115 /******************************************************************************
1116 * RegQueryValueExW [ADVAPI32.@]
1118 * See RegQueryValueExA.
1120 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
1121 LPBYTE data
, LPDWORD count
)
1124 UNICODE_STRING name_str
;
1126 char buffer
[256], *buf_ptr
= buffer
;
1127 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1128 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1130 TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1131 hkey
, debugstr_w(name
), reserved
, type
, data
, count
,
1132 (count
&& data
) ? *count
: 0 );
1134 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1135 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1137 RtlInitUnicodeString( &name_str
, name
);
1139 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
1140 else total_size
= info_size
;
1142 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1143 buffer
, total_size
, &total_size
);
1144 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1148 /* retry with a dynamically allocated buffer */
1149 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
1151 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1152 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1153 return ERROR_NOT_ENOUGH_MEMORY
;
1154 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1155 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1156 buf_ptr
, total_size
, &total_size
);
1161 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1162 /* if the type is REG_SZ and data is not 0-terminated
1163 * and there is enough space in the buffer NT appends a \0 */
1164 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1166 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
1167 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1170 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1172 else status
= STATUS_SUCCESS
;
1174 if (type
) *type
= info
->Type
;
1175 if (count
) *count
= total_size
- info_size
;
1178 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1179 return RtlNtStatusToDosError(status
);
1183 /******************************************************************************
1184 * RegQueryValueExA [ADVAPI32.@]
1186 * Get the type and contents of a specified value under with a key.
1189 * hkey [I] Handle of the key to query
1190 * name [I] Name of value under hkey to query
1191 * reserved [I] Reserved - must be NULL
1192 * type [O] Destination for the value type, or NULL if not required
1193 * data [O] Destination for the values contents, or NULL if not required
1194 * count [I/O] Size of data, updated with the number of bytes returned
1197 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1198 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1199 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1200 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1203 * MSDN states that if data is too small it is partially filled. In reality
1204 * it remains untouched.
1206 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1207 LPBYTE data
, LPDWORD count
)
1212 char buffer
[256], *buf_ptr
= buffer
;
1213 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1214 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1216 TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1217 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
1219 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1220 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1222 RtlInitAnsiString( &nameA
, name
);
1223 if ((status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
1225 return RtlNtStatusToDosError(status
);
1227 status
= NtQueryValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
,
1228 KeyValuePartialInformation
, buffer
, sizeof(buffer
), &total_size
);
1229 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1231 /* we need to fetch the contents for a string type even if not requested,
1232 * because we need to compute the length of the ASCII string. */
1233 if (data
|| is_string(info
->Type
))
1235 /* retry with a dynamically allocated buffer */
1236 while (status
== STATUS_BUFFER_OVERFLOW
)
1238 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1239 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1241 status
= STATUS_NO_MEMORY
;
1244 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1245 status
= NtQueryValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
,
1246 KeyValuePartialInformation
, buf_ptr
, total_size
, &total_size
);
1249 if (status
) goto done
;
1251 if (is_string(info
->Type
))
1255 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
1256 total_size
- info_size
);
1259 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1262 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
1263 total_size
- info_size
);
1264 /* if the type is REG_SZ and data is not 0-terminated
1265 * and there is enough space in the buffer NT appends a \0 */
1266 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1269 total_size
= len
+ info_size
;
1273 if (total_size
- info_size
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1274 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1277 else status
= STATUS_SUCCESS
;
1279 if (type
) *type
= info
->Type
;
1280 if (count
) *count
= total_size
- info_size
;
1283 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1284 return RtlNtStatusToDosError(status
);
1288 /******************************************************************************
1289 * RegQueryValueW [ADVAPI32.@]
1291 * Retrieves the data associated with the default or unnamed value of a key.
1294 * hkey [I] Handle to an open key.
1295 * name [I] Name of the subkey of hKey.
1296 * data [O] Receives the string associated with the default value
1298 * count [I/O] Size of lpValue in bytes.
1301 * Success: ERROR_SUCCESS
1302 * Failure: nonzero error code from Winerror.h
1304 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
1309 TRACE("(%p,%s,%p,%ld)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
1311 if (name
&& name
[0])
1313 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1315 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1316 if (subkey
!= hkey
) RegCloseKey( subkey
);
1317 if (ret
== ERROR_FILE_NOT_FOUND
)
1319 /* return empty string if default value not found */
1320 if (data
) *data
= 0;
1321 if (count
) *count
= sizeof(WCHAR
);
1322 ret
= ERROR_SUCCESS
;
1328 /******************************************************************************
1329 * RegQueryValueA [ADVAPI32.@]
1331 * See RegQueryValueW.
1333 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
1338 TRACE("(%p,%s,%p,%ld)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
1340 if (name
&& name
[0])
1342 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1344 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1345 if (subkey
!= hkey
) RegCloseKey( subkey
);
1346 if (ret
== ERROR_FILE_NOT_FOUND
)
1348 /* return empty string if default value not found */
1349 if (data
) *data
= 0;
1350 if (count
) *count
= 1;
1351 ret
= ERROR_SUCCESS
;
1357 /******************************************************************************
1358 * ADVAPI_ApplyRestrictions [internal]
1360 * Helper function for RegGetValueA/W.
1362 VOID
ADVAPI_ApplyRestrictions( DWORD dwFlags
, DWORD dwType
, DWORD cbData
,
1365 /* Check if the type is restricted by the passed flags */
1366 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1372 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1373 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1374 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1375 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1376 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1377 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1378 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1381 if (dwFlags
& dwMask
)
1383 /* Type is not restricted, check for size mismatch */
1384 if (dwType
== REG_BINARY
)
1388 if ((dwFlags
& RRF_RT_DWORD
) == RRF_RT_DWORD
)
1390 else if ((dwFlags
& RRF_RT_DWORD
) == RRF_RT_QWORD
)
1393 if (cbExpect
&& cbData
!= cbExpect
)
1394 *ret
= ERROR_DATATYPE_MISMATCH
;
1397 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1402 /******************************************************************************
1403 * RegGetValueW [ADVAPI32.@]
1405 * Retrieves the type and data for a value name associated with a key
1406 * optionally expanding it's content and restricting it's type.
1409 * hKey [I] Handle to an open key.
1410 * pszSubKey [I] Name of the subkey of hKey.
1411 * pszValue [I] Name of value under hKey/szSubKey to query.
1412 * dwFlags [I] Flags restricting the value type to retrieve.
1413 * pdwType [O] Destination for the values type, may be NULL.
1414 * pvData [O] Destination for the values content, may be NULL.
1415 * pcbData [I/O] Size of pvData, updated with the size required to
1416 * retrieve the whole content.
1419 * Success: ERROR_SUCCESS
1420 * Failure: nonzero error code from Winerror.h
1423 * - Unless RRF_NOEXPAND is specified REG_EXPAND_SZ is automatically expanded
1424 * and REG_SZ is retrieved instead.
1425 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1426 * without RRF_NOEXPAND is thus not allowed.
1428 LONG WINAPI
RegGetValueW( HKEY hKey
, LPCWSTR pszSubKey
, LPCWSTR pszValue
,
1429 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1432 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1436 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1437 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1438 pvData
, pcbData
, cbData
);
1440 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
))
1441 return ERROR_INVALID_PARAMETER
;
1443 if (pszSubKey
&& pszSubKey
[0])
1445 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1446 if (ret
!= ERROR_SUCCESS
) return ret
;
1449 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1451 /* If we are going to expand we need to read in the whole the value even
1452 * if the passed buffer was too small as the expanded string might be
1453 * smaller than the unexpanded one and could fit into cbData bytes. */
1454 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1455 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
1458 HeapFree(GetProcessHeap(), 0, pvBuf
);
1460 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1463 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1467 if (ret
== ERROR_MORE_DATA
)
1468 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
1469 &dwType
, pvBuf
, &cbData
);
1472 /* Even if cbData was large enough we have to copy the
1473 * string since ExpandEnvironmentStrings can't handle
1474 * overlapping buffers. */
1475 CopyMemory(pvBuf
, pvData
, cbData
);
1478 /* Both the type or the value itself could have been modified in
1479 * between so we have to keep retrying until the buffer is large
1480 * enough or we no longer have to expand the value. */
1481 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1483 if (ret
== ERROR_SUCCESS
)
1485 if (dwType
== REG_EXPAND_SZ
)
1487 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
1488 pcbData
? *pcbData
: 0);
1490 if(pcbData
&& cbData
> *pcbData
)
1491 ret
= ERROR_MORE_DATA
;
1494 CopyMemory(pvData
, pvBuf
, *pcbData
);
1497 HeapFree(GetProcessHeap(), 0, pvBuf
);
1500 if (pszSubKey
&& pszSubKey
[0])
1503 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1505 if (pcbData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1506 ZeroMemory(pvData
, *pcbData
);
1508 if (pdwType
) *pdwType
= dwType
;
1509 if (pcbData
) *pcbData
= cbData
;
1515 /******************************************************************************
1516 * RegGetValueA [ADVAPI32.@]
1520 LONG WINAPI
RegGetValueA( HKEY hKey
, LPCSTR pszSubKey
, LPCSTR pszValue
,
1521 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1524 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1528 TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
1529 hKey
, pszSubKey
, pszValue
, dwFlags
, pdwType
, pvData
, pcbData
,
1532 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
))
1533 return ERROR_INVALID_PARAMETER
;
1535 if (pszSubKey
&& pszSubKey
[0])
1537 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1538 if (ret
!= ERROR_SUCCESS
) return ret
;
1541 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1543 /* If we are going to expand we need to read in the whole the value even
1544 * if the passed buffer was too small as the expanded string might be
1545 * smaller than the unexpanded one and could fit into cbData bytes. */
1546 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1547 (dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
)))
1550 HeapFree(GetProcessHeap(), 0, pvBuf
);
1552 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1555 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1559 if (ret
== ERROR_MORE_DATA
)
1560 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
1561 &dwType
, pvBuf
, &cbData
);
1564 /* Even if cbData was large enough we have to copy the
1565 * string since ExpandEnvironmentStrings can't handle
1566 * overlapping buffers. */
1567 CopyMemory(pvBuf
, pvData
, cbData
);
1570 /* Both the type or the value itself could have been modified in
1571 * between so we have to keep retrying until the buffer is large
1572 * enough or we no longer have to expand the value. */
1573 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1575 if (ret
== ERROR_SUCCESS
)
1577 if (dwType
== REG_EXPAND_SZ
)
1579 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
1580 pcbData
? *pcbData
: 0);
1582 if(pcbData
&& cbData
> *pcbData
)
1583 ret
= ERROR_MORE_DATA
;
1586 CopyMemory(pvData
, pvBuf
, *pcbData
);
1589 HeapFree(GetProcessHeap(), 0, pvBuf
);
1592 if (pszSubKey
&& pszSubKey
[0])
1595 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1597 if (pcbData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1598 ZeroMemory(pvData
, *pcbData
);
1600 if (pdwType
) *pdwType
= dwType
;
1601 if (pcbData
) *pcbData
= cbData
;
1607 /******************************************************************************
1608 * RegEnumValueW [ADVAPI32.@]
1610 * Enumerates the values for the specified open registry key.
1613 * hkey [I] Handle to key to query
1614 * index [I] Index of value to query
1615 * value [O] Value string
1616 * val_count [I/O] Size of value buffer (in wchars)
1617 * reserved [I] Reserved
1618 * type [O] Type code
1619 * data [O] Value data
1620 * count [I/O] Size of data buffer (in bytes)
1623 * Success: ERROR_SUCCESS
1624 * Failure: nonzero error code from Winerror.h
1627 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
1628 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1632 char buffer
[256], *buf_ptr
= buffer
;
1633 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1634 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1636 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1637 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1639 /* NT only checks count, not val_count */
1640 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1641 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1643 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1644 if (data
) total_size
+= *count
;
1645 total_size
= min( sizeof(buffer
), total_size
);
1647 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1648 buffer
, total_size
, &total_size
);
1649 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1653 /* retry with a dynamically allocated buffer */
1654 while (status
== STATUS_BUFFER_OVERFLOW
)
1656 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1657 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1658 return ERROR_NOT_ENOUGH_MEMORY
;
1659 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1660 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1661 buf_ptr
, total_size
, &total_size
);
1664 if (status
) goto done
;
1668 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
1670 status
= STATUS_BUFFER_OVERFLOW
;
1673 memcpy( value
, info
->Name
, info
->NameLength
);
1674 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
1675 value
[*val_count
] = 0;
1680 if (total_size
- info
->DataOffset
> *count
)
1682 status
= STATUS_BUFFER_OVERFLOW
;
1685 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1686 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1688 /* if the type is REG_SZ and data is not 0-terminated
1689 * and there is enough space in the buffer NT appends a \0 */
1690 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
1691 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1695 else status
= STATUS_SUCCESS
;
1698 if (type
) *type
= info
->Type
;
1699 if (count
) *count
= info
->DataLength
;
1702 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1703 return RtlNtStatusToDosError(status
);
1707 /******************************************************************************
1708 * RegEnumValueA [ADVAPI32.@]
1710 * See RegEnumValueW.
1712 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1713 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1717 char buffer
[256], *buf_ptr
= buffer
;
1718 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1719 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1721 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1722 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1724 /* NT only checks count, not val_count */
1725 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1726 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1728 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1729 if (data
) total_size
+= *count
;
1730 total_size
= min( sizeof(buffer
), total_size
);
1732 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1733 buffer
, total_size
, &total_size
);
1734 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1736 /* we need to fetch the contents for a string type even if not requested,
1737 * because we need to compute the length of the ASCII string. */
1738 if (value
|| data
|| is_string(info
->Type
))
1740 /* retry with a dynamically allocated buffer */
1741 while (status
== STATUS_BUFFER_OVERFLOW
)
1743 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1744 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1745 return ERROR_NOT_ENOUGH_MEMORY
;
1746 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1747 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1748 buf_ptr
, total_size
, &total_size
);
1751 if (status
) goto done
;
1753 if (is_string(info
->Type
))
1756 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1757 total_size
- info
->DataOffset
);
1760 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1763 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1764 total_size
- info
->DataOffset
);
1765 /* if the type is REG_SZ and data is not 0-terminated
1766 * and there is enough space in the buffer NT appends a \0 */
1767 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1770 info
->DataLength
= len
;
1774 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1775 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1778 if (value
&& !status
)
1782 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
1783 if (len
>= *val_count
)
1785 status
= STATUS_BUFFER_OVERFLOW
;
1788 len
= *val_count
- 1;
1789 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1795 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
1801 else status
= STATUS_SUCCESS
;
1803 if (type
) *type
= info
->Type
;
1804 if (count
) *count
= info
->DataLength
;
1807 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1808 return RtlNtStatusToDosError(status
);
1813 /******************************************************************************
1814 * RegDeleteValueW [ADVAPI32.@]
1816 * See RegDeleteValueA.
1818 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
1820 UNICODE_STRING nameW
;
1822 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1824 RtlInitUnicodeString( &nameW
, name
);
1825 return RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
1829 /******************************************************************************
1830 * RegDeleteValueA [ADVAPI32.@]
1832 * Delete a value from the registry.
1835 * hkey [I] Registry handle of the key holding the value
1836 * name [I] Name of the value under hkey to delete
1839 * Success: ERROR_SUCCESS
1840 * Failure: nonzero error code from Winerror.h
1842 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
1847 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1849 RtlInitAnsiString( &nameA
, name
);
1850 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
1852 status
= NtDeleteValueKey( hkey
, &NtCurrentTeb()->StaticUnicodeString
);
1853 return RtlNtStatusToDosError( status
);
1857 /******************************************************************************
1858 * RegLoadKeyW [ADVAPI32.@]
1860 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1861 * registration information from a specified file into that subkey.
1864 * hkey [I] Handle of open key
1865 * subkey [I] Address of name of subkey
1866 * filename [I] Address of filename for registry information
1869 * Success: ERROR_SUCCES
1870 * Failure: nonzero error code from Winerror.h
1872 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
1874 OBJECT_ATTRIBUTES destkey
, file
;
1875 UNICODE_STRING subkeyW
, filenameW
;
1877 if (!(hkey
= get_special_root_hkey(hkey
))) return ERROR_INVALID_HANDLE
;
1879 destkey
.Length
= sizeof(destkey
);
1880 destkey
.RootDirectory
= hkey
; /* root key: HKLM or HKU */
1881 destkey
.ObjectName
= &subkeyW
; /* name of the key */
1882 destkey
.Attributes
= 0;
1883 destkey
.SecurityDescriptor
= NULL
;
1884 destkey
.SecurityQualityOfService
= NULL
;
1885 RtlInitUnicodeString(&subkeyW
, subkey
);
1887 file
.Length
= sizeof(file
);
1888 file
.RootDirectory
= NULL
;
1889 file
.ObjectName
= &filenameW
; /* file containing the hive */
1890 file
.Attributes
= OBJ_CASE_INSENSITIVE
;
1891 file
.SecurityDescriptor
= NULL
;
1892 file
.SecurityQualityOfService
= NULL
;
1893 RtlDosPathNameToNtPathName_U(filename
, &filenameW
, NULL
, NULL
);
1895 return RtlNtStatusToDosError( NtLoadKey(&destkey
, &file
) );
1899 /******************************************************************************
1900 * RegLoadKeyA [ADVAPI32.@]
1904 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
1906 UNICODE_STRING subkeyW
, filenameW
;
1907 STRING subkeyA
, filenameA
;
1910 RtlInitAnsiString(&subkeyA
, subkey
);
1911 RtlInitAnsiString(&filenameA
, filename
);
1913 if ((status
= RtlAnsiStringToUnicodeString(&subkeyW
, &subkeyA
, TRUE
)))
1914 return RtlNtStatusToDosError(status
);
1916 if ((status
= RtlAnsiStringToUnicodeString(&filenameW
, &filenameA
, TRUE
)))
1917 return RtlNtStatusToDosError(status
);
1919 return RegLoadKeyW(hkey
, subkeyW
.Buffer
, filenameW
.Buffer
);
1923 /******************************************************************************
1924 * RegSaveKeyW [ADVAPI32.@]
1926 * Save a key and all of its subkeys and values to a new file in the standard format.
1929 * hkey [I] Handle of key where save begins
1930 * lpFile [I] Address of filename to save to
1931 * sa [I] Address of security structure
1934 * Success: ERROR_SUCCESS
1935 * Failure: nonzero error code from Winerror.h
1937 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
1939 static const WCHAR format
[] =
1940 {'r','e','g','%','0','4','x','.','t','m','p',0};
1941 WCHAR buffer
[MAX_PATH
];
1947 TRACE( "(%p,%s,%p)\n", hkey
, debugstr_w(file
), sa
);
1949 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
1950 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1952 err
= GetLastError();
1953 GetFullPathNameW( file
, sizeof(buffer
)/sizeof(WCHAR
), buffer
, &nameW
);
1957 snprintfW( nameW
, 16, format
, count
++ );
1958 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
1959 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
1960 if (handle
!= INVALID_HANDLE_VALUE
) break;
1961 if ((ret
= GetLastError()) != ERROR_ALREADY_EXISTS
) goto done
;
1963 /* Something gone haywire ? Please report if this happens abnormally */
1965 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
);
1968 ret
= RtlNtStatusToDosError(NtSaveKey(hkey
, handle
));
1970 CloseHandle( handle
);
1973 if (!MoveFileExW( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
1975 ERR( "Failed to move %s to %s\n", debugstr_w(buffer
),
1977 ret
= GetLastError();
1980 if (ret
) DeleteFileW( buffer
);
1983 SetLastError( err
); /* restore last error code */
1988 /******************************************************************************
1989 * RegSaveKeyA [ADVAPI32.@]
1993 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
1995 UNICODE_STRING
*fileW
= &NtCurrentTeb()->StaticUnicodeString
;
1999 RtlInitAnsiString(&fileA
, file
);
2000 if ((status
= RtlAnsiStringToUnicodeString(fileW
, &fileA
, FALSE
)))
2001 return RtlNtStatusToDosError( status
);
2002 return RegSaveKeyW(hkey
, fileW
->Buffer
, sa
);
2006 /******************************************************************************
2007 * RegRestoreKeyW [ADVAPI32.@]
2009 * Read the registry information from a file and copy it over a key.
2012 * hkey [I] Handle of key where restore begins
2013 * lpFile [I] Address of filename containing saved tree
2014 * dwFlags [I] Optional flags
2017 * Success: ERROR_SUCCESS
2018 * Failure: nonzero error code from Winerror.h
2020 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
2022 TRACE("(%p,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2024 /* It seems to do this check before the hkey check */
2025 if (!lpFile
|| !*lpFile
)
2026 return ERROR_INVALID_PARAMETER
;
2028 FIXME("(%p,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2030 /* Check for file existence */
2032 return ERROR_SUCCESS
;
2036 /******************************************************************************
2037 * RegRestoreKeyA [ADVAPI32.@]
2039 * See RegRestoreKeyW.
2041 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
2043 UNICODE_STRING lpFileW
;
2046 RtlCreateUnicodeStringFromAsciiz( &lpFileW
, lpFile
);
2047 ret
= RegRestoreKeyW( hkey
, lpFileW
.Buffer
, dwFlags
);
2048 RtlFreeUnicodeString( &lpFileW
);
2053 /******************************************************************************
2054 * RegUnLoadKeyW [ADVAPI32.@]
2056 * Unload a registry key and its subkeys from the registry.
2059 * hkey [I] Handle of open key
2060 * lpSubKey [I] Address of name of subkey to unload
2063 * Success: ERROR_SUCCESS
2064 * Failure: nonzero error code from Winerror.h
2066 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
2071 TRACE("(%p,%s)\n",hkey
, debugstr_w(lpSubKey
));
2073 ret
= RegOpenKeyW(hkey
,lpSubKey
,&shkey
);
2075 return ERROR_INVALID_PARAMETER
;
2077 ret
= RtlNtStatusToDosError(NtUnloadKey(shkey
));
2085 /******************************************************************************
2086 * RegUnLoadKeyA [ADVAPI32.@]
2088 * See RegUnLoadKeyW.
2090 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
2092 UNICODE_STRING lpSubKeyW
;
2095 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2096 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
.Buffer
);
2097 RtlFreeUnicodeString( &lpSubKeyW
);
2102 /******************************************************************************
2103 * RegReplaceKeyW [ADVAPI32.@]
2105 * Replace the file backing a registry key and all its subkeys with another file.
2108 * hkey [I] Handle of open key
2109 * lpSubKey [I] Address of name of subkey
2110 * lpNewFile [I] Address of filename for file with new data
2111 * lpOldFile [I] Address of filename for backup file
2114 * Success: ERROR_SUCCESS
2115 * Failure: nonzero error code from Winerror.h
2117 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
2120 FIXME("(%p,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
2121 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
2122 return ERROR_SUCCESS
;
2126 /******************************************************************************
2127 * RegReplaceKeyA [ADVAPI32.@]
2129 * See RegReplaceKeyW.
2131 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
2134 UNICODE_STRING lpSubKeyW
;
2135 UNICODE_STRING lpNewFileW
;
2136 UNICODE_STRING lpOldFileW
;
2139 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2140 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW
, lpOldFile
);
2141 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW
, lpNewFile
);
2142 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
.Buffer
, lpNewFileW
.Buffer
, lpOldFileW
.Buffer
);
2143 RtlFreeUnicodeString( &lpOldFileW
);
2144 RtlFreeUnicodeString( &lpNewFileW
);
2145 RtlFreeUnicodeString( &lpSubKeyW
);
2150 /******************************************************************************
2151 * RegSetKeySecurity [ADVAPI32.@]
2153 * Set the security of an open registry key.
2156 * hkey [I] Open handle of key to set
2157 * SecurityInfo [I] Descriptor contents
2158 * pSecurityDesc [I] Address of descriptor for key
2161 * Success: ERROR_SUCCESS
2162 * Failure: nonzero error code from Winerror.h
2164 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
2165 PSECURITY_DESCRIPTOR pSecurityDesc
)
2167 TRACE("(%p,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
2169 /* It seems to perform this check before the hkey check */
2170 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
2171 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
2172 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
2173 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
2176 return ERROR_INVALID_PARAMETER
;
2179 return ERROR_INVALID_PARAMETER
;
2181 FIXME(":(%p,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
2183 return ERROR_SUCCESS
;
2187 /******************************************************************************
2188 * RegGetKeySecurity [ADVAPI32.@]
2190 * Get a copy of the security descriptor for a given registry key.
2193 * hkey [I] Open handle of key to set
2194 * SecurityInformation [I] Descriptor contents
2195 * pSecurityDescriptor [O] Address of descriptor for key
2196 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2199 * Success: ERROR_SUCCESS
2200 * Failure: Error code
2202 LONG WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
2203 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2204 LPDWORD lpcbSecurityDescriptor
)
2206 TRACE("(%p,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
2207 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
2209 /* FIXME: Check for valid SecurityInformation values */
2211 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
2212 return ERROR_INSUFFICIENT_BUFFER
;
2214 FIXME("(%p,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
2215 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
2217 /* Do not leave security descriptor filled with garbage */
2218 RtlCreateSecurityDescriptor(pSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
2220 return ERROR_SUCCESS
;
2224 /******************************************************************************
2225 * RegFlushKey [ADVAPI32.@]
2227 * Immediately write a registry key to registry.
2230 * hkey [I] Handle of key to write
2233 * Success: ERROR_SUCCESS
2234 * Failure: Error code
2236 DWORD WINAPI
RegFlushKey( HKEY hkey
)
2238 hkey
= get_special_root_hkey( hkey
);
2239 if (!hkey
) return ERROR_INVALID_HANDLE
;
2241 return RtlNtStatusToDosError( NtFlushKey( hkey
) );
2245 /******************************************************************************
2246 * RegConnectRegistryW [ADVAPI32.@]
2248 * Establishe a connection to a predefined registry key on another computer.
2251 * lpMachineName [I] Address of name of remote computer
2252 * hHey [I] Predefined registry handle
2253 * phkResult [I] Address of buffer for remote registry handle
2256 * Success: ERROR_SUCCESS
2257 * Failure: nonzero error code from Winerror.h
2259 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
2264 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
2266 if (!lpMachineName
|| !*lpMachineName
) {
2267 /* Use the local machine name */
2268 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
2271 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
2272 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
2274 /* MSDN says lpMachineName must start with \\ : not so */
2275 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
2277 if (GetComputerNameW(compName
, &len
))
2279 if (!strcmpiW(lpMachineName
, compName
))
2280 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
2283 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
2284 ret
= ERROR_BAD_NETPATH
;
2288 ret
= GetLastError();
2294 /******************************************************************************
2295 * RegConnectRegistryA [ADVAPI32.@]
2297 * See RegConnectRegistryW.
2299 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, PHKEY reskey
)
2301 UNICODE_STRING machineW
;
2304 RtlCreateUnicodeStringFromAsciiz( &machineW
, machine
);
2305 ret
= RegConnectRegistryW( machineW
.Buffer
, hkey
, reskey
);
2306 RtlFreeUnicodeString( &machineW
);
2311 /******************************************************************************
2312 * RegNotifyChangeKeyValue [ADVAPI32.@]
2314 * Notify the caller about changes to the attributes or contents of a registry key.
2317 * hkey [I] Handle of key to watch
2318 * fWatchSubTree [I] Flag for subkey notification
2319 * fdwNotifyFilter [I] Changes to be reported
2320 * hEvent [I] Handle of signaled event
2321 * fAsync [I] Flag for asynchronous reporting
2324 * Success: ERROR_SUCCESS
2325 * Failure: nonzero error code from Winerror.h
2327 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
2328 DWORD fdwNotifyFilter
, HANDLE hEvent
,
2332 IO_STATUS_BLOCK iosb
;
2334 hkey
= get_special_root_hkey( hkey
);
2335 if (!hkey
) return ERROR_INVALID_HANDLE
;
2337 TRACE("(%p,%i,%ld,%p,%i)\n", hkey
, fWatchSubTree
, fdwNotifyFilter
,
2340 status
= NtNotifyChangeKey( hkey
, hEvent
, NULL
, NULL
, &iosb
,
2341 fdwNotifyFilter
, fAsync
, NULL
, 0,
2344 if (status
&& status
!= STATUS_TIMEOUT
)
2345 return RtlNtStatusToDosError( status
);
2347 return ERROR_SUCCESS
;
2350 /******************************************************************************
2351 * RegOpenUserClassesRoot [ADVAPI32.@]
2353 * Open the HKEY_CLASSES_ROOT key for a user.
2356 * hToken [I] Handle of token representing the user
2357 * dwOptions [I] Reserved, nust be 0
2358 * samDesired [I] Desired access rights
2359 * phkResult [O] Destination for the resulting key handle
2362 * Success: ERROR_SUCCESS
2363 * Failure: nonzero error code from Winerror.h
2366 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2367 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2368 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2370 LONG WINAPI
RegOpenUserClassesRoot(
2377 FIXME("(%p, 0x%lx, 0x%lx, %p) semi-stub\n", hToken
, dwOptions
, samDesired
, phkResult
);
2379 *phkResult
= HKEY_CLASSES_ROOT
;
2380 return ERROR_SUCCESS
;
2383 /******************************************************************************
2384 * load_string [Internal]
2386 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2387 * avoid importing user32, which is higher level than advapi32. Helper for
2390 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
2397 /* Negative values have to be inverted. */
2398 if (HIWORD(resId
) == 0xffff)
2399 resId
= (UINT
)(-((INT
)resId
));
2401 /* Load the resource into memory and get a pointer to it. */
2402 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
2403 if (!hResource
) return 0;
2404 hMemory
= LoadResource(hModule
, hResource
);
2405 if (!hMemory
) return 0;
2406 pString
= LockResource(hMemory
);
2408 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2409 idxString
= resId
& 0xf;
2410 while (idxString
--) pString
+= *pString
+ 1;
2412 /* If no buffer is given, return length of the string. */
2413 if (!pwszBuffer
) return *pString
;
2415 /* Else copy over the string, respecting the buffer size. */
2416 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
2417 if (cMaxChars
>= 0) {
2418 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
2419 pwszBuffer
[cMaxChars
] = '\0';
2425 /******************************************************************************
2426 * RegLoadMUIStringW [ADVAPI32.@]
2428 * Load the localized version of a string resource from some PE, respective
2429 * id and path of which are given in the registry value in the format
2430 * @[path]\dllname,-resourceId
2433 * hKey [I] Key, of which to load the string value from.
2434 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2435 * pszBuffer [O] Buffer to store the localized string in.
2436 * cbBuffer [I] Size of the destination buffer in bytes.
2437 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2438 * dwFlags [I] None supported yet.
2439 * pszBaseDir [I] Not supported yet.
2442 * Success: ERROR_SUCCESS,
2443 * Failure: nonzero error code from winerror.h
2446 * This is an API of Windows Vista, which wasn't available at the time this code
2447 * was written. We have to check for the correct behaviour once it's available.
2449 LONG WINAPI
RegLoadMUIStringW(HKEY hKey
, LPCWSTR pwszValue
, LPWSTR pwszBuffer
, DWORD cbBuffer
,
2450 LPDWORD pcbData
, DWORD dwFlags
, LPCWSTR pwszBaseDir
)
2452 DWORD dwValueType
, cbData
;
2453 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
2456 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %ld, pcbData = %p, "
2457 "dwFlags = %ld, pwszBaseDir = %s) stub\n", hKey
, debugstr_w(pwszValue
), pwszBuffer
,
2458 cbBuffer
, pcbData
, dwFlags
, debugstr_w(pwszBaseDir
));
2460 /* Parameter sanity checks. */
2461 if (!hKey
|| !pwszBuffer
)
2462 return ERROR_INVALID_PARAMETER
;
2464 if (pwszBaseDir
&& *pwszBaseDir
) {
2465 FIXME("BaseDir parameter not yet supported!\n");
2466 return ERROR_INVALID_PARAMETER
;
2469 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2470 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
2471 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2472 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
) {
2473 result
= ERROR_FILE_NOT_FOUND
;
2476 pwszTempBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2477 if (!pwszTempBuffer
) {
2478 result
= ERROR_NOT_ENOUGH_MEMORY
;
2481 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
2482 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2484 /* Expand environment variables, if appropriate, or copy the original string over. */
2485 if (dwValueType
== REG_EXPAND_SZ
) {
2486 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
2487 if (!cbData
) goto cleanup
;
2488 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2489 if (!pwszExpandedBuffer
) {
2490 result
= ERROR_NOT_ENOUGH_MEMORY
;
2493 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
2495 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2496 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
2499 /* If the value references a resource based string, parse the value and load the string.
2500 * Else just copy over the original value. */
2501 result
= ERROR_SUCCESS
;
2502 if (*pwszExpandedBuffer
!= '@') { /* '@' is the prefix for resource based string entries. */
2503 lstrcpynW(pwszBuffer
, pwszExpandedBuffer
, cbBuffer
/ sizeof(WCHAR
));
2505 WCHAR
*pComma
= strrchrW(pwszExpandedBuffer
, ',');
2509 /* Format of the expanded value is 'path_to_dll,-resId' */
2510 if (!pComma
|| pComma
[1] != '-') {
2511 result
= ERROR_BADKEY
;
2515 uiStringId
= atoiW(pComma
+2);
2518 hModule
= LoadLibraryW(pwszExpandedBuffer
+ 1);
2519 if (!hModule
|| !load_string(hModule
, uiStringId
, pwszBuffer
, cbBuffer
/sizeof(WCHAR
)))
2520 result
= ERROR_BADKEY
;
2521 FreeLibrary(hModule
);
2525 HeapFree(GetProcessHeap(), 0, pwszTempBuffer
);
2526 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer
);
2530 /******************************************************************************
2531 * RegLoadMUIStringA [ADVAPI32.@]
2533 * See RegLoadMUIStringW
2535 LONG WINAPI
RegLoadMUIStringA(HKEY hKey
, LPCSTR pszValue
, LPSTR pszBuffer
, DWORD cbBuffer
,
2536 LPDWORD pcbData
, DWORD dwFlags
, LPCSTR pszBaseDir
)
2538 UNICODE_STRING valueW
, baseDirW
;
2540 DWORD cbData
= cbBuffer
* sizeof(WCHAR
);
2543 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
2544 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
2545 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszBaseDir
) ||
2546 !(pwszBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
)))
2548 result
= ERROR_NOT_ENOUGH_MEMORY
;
2552 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, dwFlags
,
2555 if (result
== ERROR_SUCCESS
) {
2556 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszBuffer
, cbBuffer
, NULL
, NULL
);
2562 HeapFree(GetProcessHeap(), 0, pwszBuffer
);
2563 RtlFreeUnicodeString(&baseDirW
);
2564 RtlFreeUnicodeString(&valueW
);