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 library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #define WIN32_NO_STATUS
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
44 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
45 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
47 static const WCHAR name_CLASSES_ROOT
[] =
48 {'M','a','c','h','i','n','e','\\',
49 'S','o','f','t','w','a','r','e','\\',
50 'C','l','a','s','s','e','s',0};
51 static const WCHAR name_LOCAL_MACHINE
[] =
52 {'M','a','c','h','i','n','e',0};
53 static const WCHAR name_USERS
[] =
55 static const WCHAR name_PERFORMANCE_DATA
[] =
56 {'P','e','r','f','D','a','t','a',0};
57 static const WCHAR name_CURRENT_CONFIG
[] =
58 {'M','a','c','h','i','n','e','\\',
59 'S','y','s','t','e','m','\\',
60 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
61 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
62 'C','u','r','r','e','n','t',0};
63 static const WCHAR name_DYN_DATA
[] =
64 {'D','y','n','D','a','t','a',0};
66 static const WCHAR
* const root_key_names
[] =
69 NULL
, /* HKEY_CURRENT_USER is determined dynamically */
72 name_PERFORMANCE_DATA
,
77 #define NB_SPECIAL_ROOT_KEYS (sizeof(root_key_names)/sizeof(root_key_names[0]))
79 static HKEY special_root_keys
[NB_SPECIAL_ROOT_KEYS
];
80 static BOOL hkcu_cache_disabled
;
82 static const int is_win64
= (sizeof(void *) > sizeof(int));
84 /* check if value type needs string conversion (Ansi<->Unicode) */
85 static inline int is_string( DWORD type
)
87 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
90 /* check if current version is NT or Win95 */
91 static inline int is_version_nt(void)
93 return !(GetVersion() & 0x80000000);
96 static BOOL
is_wow6432node( const UNICODE_STRING
*name
)
98 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e'};
100 return (name
->Length
== sizeof(wow6432nodeW
) &&
101 !memicmpW( name
->Buffer
, wow6432nodeW
, sizeof(wow6432nodeW
)/sizeof(WCHAR
) ));
104 /* open the Wow6432Node subkey of the specified key */
105 static HANDLE
open_wow6432node( HANDLE key
, const UNICODE_STRING
*name
)
107 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
108 OBJECT_ATTRIBUTES attr
;
109 UNICODE_STRING nameW
;
112 attr
.Length
= sizeof(attr
);
113 attr
.RootDirectory
= key
;
114 attr
.ObjectName
= &nameW
;
116 attr
.SecurityDescriptor
= NULL
;
117 attr
.SecurityQualityOfService
= NULL
;
118 RtlInitUnicodeString( &nameW
, wow6432nodeW
);
119 if (NtOpenKey( &ret
, MAXIMUM_ALLOWED
, &attr
)) ret
= 0;
123 /* wrapper for NtCreateKey that creates the key recursively if necessary */
124 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
125 const UNICODE_STRING
*class, ULONG options
, PULONG dispos
)
127 BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
128 NTSTATUS status
= STATUS_OBJECT_NAME_NOT_FOUND
;
130 if (!force_wow32
) status
= NtCreateKey( (HANDLE
*)retkey
, access
, attr
, 0, class, options
, dispos
);
132 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
134 HANDLE subkey
, root
= attr
->RootDirectory
;
135 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
136 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
139 while (i
< len
&& buffer
[i
] != '\\') i
++;
140 if (i
== len
&& !force_wow32
) return status
;
142 attrs
= attr
->Attributes
;
143 attr
->Attributes
&= ~OBJ_OPENLINK
;
144 attr
->ObjectName
= &str
;
148 str
.Buffer
= buffer
+ pos
;
149 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
150 if (force_wow32
&& pos
)
152 if (is_wow6432node( &str
)) force_wow32
= FALSE
;
153 else if ((subkey
= open_wow6432node( attr
->RootDirectory
, &str
)))
155 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
156 attr
->RootDirectory
= subkey
;
160 status
= NtCreateKey( &subkey
, access
, attr
, 0, class,
161 options
& ~REG_OPTION_CREATE_LINK
, dispos
);
162 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
163 if (status
) return status
;
164 attr
->RootDirectory
= subkey
;
165 while (i
< len
&& buffer
[i
] == '\\') i
++;
167 while (i
< len
&& buffer
[i
] != '\\') i
++;
169 str
.Buffer
= buffer
+ pos
;
170 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
171 attr
->Attributes
= attrs
;
172 status
= NtCreateKey( (PHANDLE
)retkey
, access
, attr
, 0, class, options
, dispos
);
173 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
178 /* wrapper for NtOpenKey to handle Wow6432 nodes */
179 static NTSTATUS
open_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
182 BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
183 HANDLE subkey
, root
= attr
->RootDirectory
;
184 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
185 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
188 if (!force_wow32
) return NtOpenKey( (HANDLE
*)retkey
, access
, attr
);
190 if (len
&& buffer
[0] == '\\') return STATUS_OBJECT_PATH_INVALID
;
191 while (i
< len
&& buffer
[i
] != '\\') i
++;
192 attrs
= attr
->Attributes
;
193 attr
->Attributes
&= ~OBJ_OPENLINK
;
194 attr
->ObjectName
= &str
;
198 str
.Buffer
= buffer
+ pos
;
199 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
200 if (force_wow32
&& pos
)
202 if (is_wow6432node( &str
)) force_wow32
= FALSE
;
203 else if ((subkey
= open_wow6432node( attr
->RootDirectory
, &str
)))
205 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
206 attr
->RootDirectory
= subkey
;
210 status
= NtOpenKey( &subkey
, access
, attr
);
211 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
212 if (status
) return status
;
213 attr
->RootDirectory
= subkey
;
214 while (i
< len
&& buffer
[i
] == '\\') i
++;
216 while (i
< len
&& buffer
[i
] != '\\') i
++;
218 str
.Buffer
= buffer
+ pos
;
219 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
220 attr
->Attributes
= attrs
;
221 status
= NtOpenKey( (PHANDLE
)retkey
, access
, attr
);
222 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
227 /* create one of the HKEY_* special root keys */
228 static HKEY
create_special_root_hkey( HKEY hkey
, DWORD access
)
231 int idx
= HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
233 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CURRENT_USER
))
235 if (RtlOpenCurrentUser( access
, (HANDLE
*)&hkey
)) return 0;
236 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey
);
238 /* don't cache the key in the table if caching is disabled */
239 if (hkcu_cache_disabled
)
244 OBJECT_ATTRIBUTES attr
;
247 attr
.Length
= sizeof(attr
);
248 attr
.RootDirectory
= 0;
249 attr
.ObjectName
= &name
;
251 attr
.SecurityDescriptor
= NULL
;
252 attr
.SecurityQualityOfService
= NULL
;
253 RtlInitUnicodeString( &name
, root_key_names
[idx
] );
254 if (create_key( &hkey
, access
, &attr
, NULL
, 0, NULL
)) return 0;
255 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
258 if (!(ret
= InterlockedCompareExchangePointer( (void **)&special_root_keys
[idx
], hkey
, 0 )))
261 NtClose( hkey
); /* somebody beat us to it */
265 /* map the hkey from special root to normal key if necessary */
266 static inline HKEY
get_special_root_hkey( HKEY hkey
)
270 if ((HandleToUlong(hkey
) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
))
271 && (HandleToUlong(hkey
) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
273 if (!(ret
= special_root_keys
[HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
)]))
274 ret
= create_special_root_hkey( hkey
, MAXIMUM_ALLOWED
);
280 /******************************************************************************
281 * RegOverridePredefKey [ADVAPI32.@]
283 LSTATUS WINAPI
RegOverridePredefKey( HKEY hkey
, HKEY override
)
288 TRACE("(%p %p)\n", hkey
, override
);
290 if ((HandleToUlong(hkey
) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
))
291 || (HandleToUlong(hkey
) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
292 return ERROR_INVALID_PARAMETER
;
293 idx
= HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
297 NTSTATUS status
= NtDuplicateObject( GetCurrentProcess(), override
,
298 GetCurrentProcess(), (HANDLE
*)&override
,
299 0, 0, DUPLICATE_SAME_ACCESS
);
300 if (status
) return RtlNtStatusToDosError( status
);
303 old_key
= InterlockedExchangePointer( (void **)&special_root_keys
[idx
], override
);
304 if (old_key
) NtClose( old_key
);
305 return ERROR_SUCCESS
;
309 /******************************************************************************
310 * RegCreateKeyExW [ADVAPI32.@]
312 * See RegCreateKeyExA.
314 LSTATUS WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
315 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
316 PHKEY retkey
, LPDWORD dispos
)
318 OBJECT_ATTRIBUTES attr
;
319 UNICODE_STRING nameW
, classW
;
321 if (reserved
) return ERROR_INVALID_PARAMETER
;
322 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
324 attr
.Length
= sizeof(attr
);
325 attr
.RootDirectory
= hkey
;
326 attr
.ObjectName
= &nameW
;
328 attr
.SecurityDescriptor
= NULL
;
329 attr
.SecurityQualityOfService
= NULL
;
330 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
331 RtlInitUnicodeString( &nameW
, name
);
332 RtlInitUnicodeString( &classW
, class );
334 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
, &classW
, options
, dispos
) );
338 /******************************************************************************
339 * RegCreateKeyExA [ADVAPI32.@]
341 * Open a registry key, creating it if it doesn't exist.
344 * hkey [I] Handle of the parent registry key
345 * name [I] Name of the new key to open or create
346 * reserved [I] Reserved, pass 0
347 * class [I] The object type of the new key
348 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
349 * access [I] Access level desired
350 * sa [I] Security attributes for the key
351 * retkey [O] Destination for the resulting handle
352 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
355 * Success: ERROR_SUCCESS.
356 * Failure: A standard Win32 error code. retkey remains untouched.
359 * MAXIMUM_ALLOWED in access mask not supported by server
361 LSTATUS WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
362 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
363 PHKEY retkey
, LPDWORD dispos
)
365 OBJECT_ATTRIBUTES attr
;
366 UNICODE_STRING classW
;
367 ANSI_STRING nameA
, classA
;
370 if (reserved
) return ERROR_INVALID_PARAMETER
;
371 if (!is_version_nt())
373 access
= MAXIMUM_ALLOWED
; /* Win95 ignores the access mask */
374 if (name
&& *name
== '\\') name
++; /* win9x,ME ignores one (and only one) beginning backslash */
376 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
378 attr
.Length
= sizeof(attr
);
379 attr
.RootDirectory
= hkey
;
380 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
382 attr
.SecurityDescriptor
= NULL
;
383 attr
.SecurityQualityOfService
= NULL
;
384 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
385 RtlInitAnsiString( &nameA
, name
);
386 RtlInitAnsiString( &classA
, class );
388 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
391 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
393 status
= create_key( retkey
, access
, &attr
, &classW
, options
, dispos
);
394 RtlFreeUnicodeString( &classW
);
397 return RtlNtStatusToDosError( status
);
401 /******************************************************************************
402 * RegCreateKeyW [ADVAPI32.@]
404 * Creates the specified reg key.
407 * hKey [I] Handle to an open key.
408 * lpSubKey [I] Name of a key that will be opened or created.
409 * phkResult [O] Receives a handle to the opened or created key.
412 * Success: ERROR_SUCCESS
413 * Failure: nonzero error code defined in Winerror.h
415 LSTATUS WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpSubKey
, PHKEY phkResult
)
417 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
418 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
419 return RegCreateKeyExW( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
420 MAXIMUM_ALLOWED
, NULL
, phkResult
, NULL
);
424 /******************************************************************************
425 * RegCreateKeyA [ADVAPI32.@]
429 LSTATUS WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpSubKey
, PHKEY phkResult
)
431 return RegCreateKeyExA( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
432 MAXIMUM_ALLOWED
, NULL
, phkResult
, NULL
);
437 /******************************************************************************
438 * RegOpenKeyExW [ADVAPI32.@]
442 LSTATUS WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD options
, REGSAM access
, PHKEY retkey
)
444 OBJECT_ATTRIBUTES attr
;
445 UNICODE_STRING nameW
;
447 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
448 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
) && name
&& *name
== '\\') name
++;
450 if (!retkey
) return ERROR_INVALID_PARAMETER
;
451 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
453 attr
.Length
= sizeof(attr
);
454 attr
.RootDirectory
= hkey
;
455 attr
.ObjectName
= &nameW
;
457 attr
.SecurityDescriptor
= NULL
;
458 attr
.SecurityQualityOfService
= NULL
;
459 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
460 RtlInitUnicodeString( &nameW
, name
);
461 return RtlNtStatusToDosError( open_key( retkey
, access
, &attr
) );
465 /******************************************************************************
466 * RegOpenKeyExA [ADVAPI32.@]
468 * Open a registry key.
471 * hkey [I] Handle of open key
472 * name [I] Name of subkey to open
473 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
474 * access [I] Security access mask
475 * retkey [O] Handle to open key
478 * Success: ERROR_SUCCESS
479 * Failure: A standard Win32 error code. retkey is set to 0.
482 * Unlike RegCreateKeyExA(), this function will not create the key if it
485 LSTATUS WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD options
, REGSAM access
, PHKEY retkey
)
487 OBJECT_ATTRIBUTES attr
;
491 if (!is_version_nt()) access
= MAXIMUM_ALLOWED
; /* Win95 ignores the access mask */
494 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
495 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
) && name
&& *name
== '\\') name
++;
498 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
500 attr
.Length
= sizeof(attr
);
501 attr
.RootDirectory
= hkey
;
502 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
504 attr
.SecurityDescriptor
= NULL
;
505 attr
.SecurityQualityOfService
= NULL
;
506 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
508 RtlInitAnsiString( &nameA
, name
);
509 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
512 status
= open_key( retkey
, access
, &attr
);
514 return RtlNtStatusToDosError( status
);
518 /******************************************************************************
519 * RegOpenKeyW [ADVAPI32.@]
523 LSTATUS WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, PHKEY retkey
)
526 return ERROR_INVALID_PARAMETER
;
531 return ERROR_SUCCESS
;
533 return RegOpenKeyExW( hkey
, name
, 0, MAXIMUM_ALLOWED
, retkey
);
537 /******************************************************************************
538 * RegOpenKeyA [ADVAPI32.@]
540 * Open a registry key.
543 * hkey [I] Handle of parent key to open the new key under
544 * name [I] Name of the key under hkey to open
545 * retkey [O] Destination for the resulting Handle
548 * Success: ERROR_SUCCESS
549 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
551 LSTATUS WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, PHKEY retkey
)
554 return ERROR_INVALID_PARAMETER
;
559 return ERROR_SUCCESS
;
561 return RegOpenKeyExA( hkey
, name
, 0, MAXIMUM_ALLOWED
, retkey
);
565 /******************************************************************************
566 * RegOpenCurrentUser [ADVAPI32.@]
568 * Get a handle to the HKEY_CURRENT_USER key for the user
569 * the current thread is impersonating.
572 * access [I] Desired access rights to the key
573 * retkey [O] Handle to the opened key
576 * Success: ERROR_SUCCESS
577 * Failure: nonzero error code from Winerror.h
580 * This function is supposed to retrieve a handle to the
581 * HKEY_CURRENT_USER for the user the current thread is impersonating.
582 * Since Wine does not currently allow threads to impersonate other users,
583 * this stub should work fine.
585 LSTATUS WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
587 return RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
592 /******************************************************************************
593 * RegEnumKeyExW [ADVAPI32.@]
595 * Enumerate subkeys of the specified open registry key.
598 * hkey [I] Handle to key to enumerate
599 * index [I] Index of subkey to enumerate
600 * name [O] Buffer for subkey name
601 * name_len [O] Size of subkey buffer
602 * reserved [I] Reserved
603 * class [O] Buffer for class string
604 * class_len [O] Size of class buffer
605 * ft [O] Time key last written to
608 * Success: ERROR_SUCCESS
609 * Failure: System error code. If there are no more subkeys available, the
610 * function returns ERROR_NO_MORE_ITEMS.
612 LSTATUS WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
613 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
616 char buffer
[256], *buf_ptr
= buffer
;
617 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
620 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
621 name_len
? *name_len
: 0, reserved
, class, class_len
, ft
);
623 if (reserved
) return ERROR_INVALID_PARAMETER
;
624 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
626 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
627 buffer
, sizeof(buffer
), &total_size
);
629 while (status
== STATUS_BUFFER_OVERFLOW
)
631 /* retry with a dynamically allocated buffer */
632 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
633 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
634 return ERROR_NOT_ENOUGH_MEMORY
;
635 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
636 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
637 buf_ptr
, total_size
, &total_size
);
642 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
643 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
645 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
647 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
648 status
= STATUS_BUFFER_OVERFLOW
;
652 memcpy( name
, info
->Name
, info
->NameLength
);
656 *class_len
= cls_len
;
659 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
666 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
667 return RtlNtStatusToDosError( status
);
671 /******************************************************************************
672 * RegEnumKeyExA [ADVAPI32.@]
676 LSTATUS WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
677 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
680 char buffer
[256], *buf_ptr
= buffer
;
681 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
684 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
685 name_len
? *name_len
: 0, reserved
, class, class_len
, ft
);
687 if (reserved
) return ERROR_INVALID_PARAMETER
;
688 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
690 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
691 buffer
, sizeof(buffer
), &total_size
);
693 while (status
== STATUS_BUFFER_OVERFLOW
)
695 /* retry with a dynamically allocated buffer */
696 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
697 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
698 return ERROR_NOT_ENOUGH_MEMORY
;
699 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
700 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
701 buf_ptr
, total_size
, &total_size
);
708 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
709 RtlUnicodeToMultiByteSize( &cls_len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
711 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
713 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
714 status
= STATUS_BUFFER_OVERFLOW
;
718 RtlUnicodeToMultiByteN( name
, len
, NULL
, info
->Name
, info
->NameLength
);
722 *class_len
= cls_len
;
725 RtlUnicodeToMultiByteN( class, cls_len
, NULL
,
726 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
734 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
735 return RtlNtStatusToDosError( status
);
739 /******************************************************************************
740 * RegEnumKeyW [ADVAPI32.@]
742 * Enumerates subkeys of the specified open reg key.
745 * hKey [I] Handle to an open key.
746 * dwIndex [I] Index of the subkey of hKey to retrieve.
747 * lpName [O] Name of the subkey.
748 * cchName [I] Size of lpName in TCHARS.
751 * Success: ERROR_SUCCESS
752 * Failure: system error code. If there are no more subkeys available, the
753 * function returns ERROR_NO_MORE_ITEMS.
755 LSTATUS WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
757 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
761 /******************************************************************************
762 * RegEnumKeyA [ADVAPI32.@]
766 LSTATUS WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
768 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
772 /******************************************************************************
773 * RegQueryInfoKeyW [ADVAPI32.@]
775 * Retrieves information about the specified registry key.
778 * hkey [I] Handle to key to query
779 * class [O] Buffer for class string
780 * class_len [O] Size of class string buffer
781 * reserved [I] Reserved
782 * subkeys [O] Buffer for number of subkeys
783 * max_subkey [O] Buffer for longest subkey name length
784 * max_class [O] Buffer for longest class string length
785 * values [O] Buffer for number of value entries
786 * max_value [O] Buffer for longest value name length
787 * max_data [O] Buffer for longest value data length
788 * security [O] Buffer for security descriptor length
789 * modif [O] Modification time
792 * Success: ERROR_SUCCESS
793 * Failure: system error code.
796 * - win95 allows class to be valid and class_len to be NULL
797 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
798 * - both allow class to be NULL and class_len to be NULL
799 * (it's hard to test validity, so test !NULL instead)
801 LSTATUS WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
802 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
803 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
804 LPDWORD security
, FILETIME
*modif
)
807 char buffer
[256], *buf_ptr
= buffer
;
808 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
811 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
812 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
814 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
815 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
817 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
818 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
822 /* retry with a dynamically allocated buffer */
823 while (status
== STATUS_BUFFER_OVERFLOW
)
825 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
826 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
827 return ERROR_NOT_ENOUGH_MEMORY
;
828 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
829 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
832 if (status
) goto done
;
834 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
836 status
= STATUS_BUFFER_OVERFLOW
;
840 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
841 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
844 else status
= STATUS_SUCCESS
;
846 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
847 if (subkeys
) *subkeys
= info
->SubKeys
;
848 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
849 if (max_class
) *max_class
= info
->MaxClassLen
;
850 if (values
) *values
= info
->Values
;
851 if (max_value
) *max_value
= info
->MaxValueNameLen
;
852 if (max_data
) *max_data
= info
->MaxValueDataLen
;
853 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
856 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
857 return RtlNtStatusToDosError( status
);
861 /******************************************************************************
862 * RegQueryMultipleValuesA [ADVAPI32.@]
864 * Retrieves the type and data for a list of value names associated with a key.
867 * hKey [I] Handle to an open key.
868 * val_list [O] Array of VALENT structures that describes the entries.
869 * num_vals [I] Number of elements in val_list.
870 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
871 * ldwTotsize [I/O] Size of lpValueBuf.
874 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
875 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
878 LSTATUS WINAPI
RegQueryMultipleValuesA( HKEY hkey
, PVALENTA val_list
, DWORD num_vals
,
879 LPSTR lpValueBuf
, LPDWORD ldwTotsize
)
882 DWORD maxBytes
= *ldwTotsize
;
884 LPSTR bufptr
= lpValueBuf
;
887 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
889 for(i
=0; i
< num_vals
; ++i
)
892 val_list
[i
].ve_valuelen
=0;
893 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
894 if(status
!= ERROR_SUCCESS
)
899 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
901 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
902 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
903 if(status
!= ERROR_SUCCESS
)
908 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
910 bufptr
+= val_list
[i
].ve_valuelen
;
913 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
915 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
919 /******************************************************************************
920 * RegQueryMultipleValuesW [ADVAPI32.@]
922 * See RegQueryMultipleValuesA.
924 LSTATUS WINAPI
RegQueryMultipleValuesW( HKEY hkey
, PVALENTW val_list
, DWORD num_vals
,
925 LPWSTR lpValueBuf
, LPDWORD ldwTotsize
)
928 DWORD maxBytes
= *ldwTotsize
;
930 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
933 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
935 for(i
=0; i
< num_vals
; ++i
)
937 val_list
[i
].ve_valuelen
=0;
938 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
939 if(status
!= ERROR_SUCCESS
)
944 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
946 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
947 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
948 if(status
!= ERROR_SUCCESS
)
953 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
955 bufptr
+= val_list
[i
].ve_valuelen
;
958 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
960 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
963 /******************************************************************************
964 * RegQueryInfoKeyA [ADVAPI32.@]
966 * Retrieves information about a registry key.
969 * hKey [I] Handle to an open key.
970 * lpClass [O] Class string of the key.
971 * lpcClass [I/O] size of lpClass.
972 * lpReserved [I] Reserved; must be NULL.
973 * lpcSubKeys [O] Number of subkeys contained by the key.
974 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
975 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
977 * lpcValues [O] Number of values associated with the key.
978 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
979 * lpcMaxValueLen [O] Longest data component among the key's values
980 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
981 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
984 * Success: ERROR_SUCCESS
985 * Failure: nonzero error code from Winerror.h
987 LSTATUS WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
988 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
989 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
990 LPDWORD security
, FILETIME
*modif
)
993 char buffer
[256], *buf_ptr
= buffer
;
994 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
995 DWORD total_size
, len
;
997 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
998 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
1000 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
1001 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1003 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
1004 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1006 if (class || class_len
)
1008 /* retry with a dynamically allocated buffer */
1009 while (status
== STATUS_BUFFER_OVERFLOW
)
1011 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1012 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1013 return ERROR_NOT_ENOUGH_MEMORY
;
1014 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
1015 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
1018 if (status
) goto done
;
1020 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
), info
->ClassLength
);
1023 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
1026 if (class && !status
)
1028 RtlUnicodeToMultiByteN( class, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
1029 info
->ClassLength
);
1033 else status
= STATUS_SUCCESS
;
1035 if (subkeys
) *subkeys
= info
->SubKeys
;
1036 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
1037 if (max_class
) *max_class
= info
->MaxClassLen
;
1038 if (values
) *values
= info
->Values
;
1039 if (max_value
) *max_value
= info
->MaxValueNameLen
;
1040 if (max_data
) *max_data
= info
->MaxValueDataLen
;
1041 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
1044 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1045 return RtlNtStatusToDosError( status
);
1049 /******************************************************************************
1050 * RegCloseKey [ADVAPI32.@]
1052 * Close an open registry key.
1055 * hkey [I] Handle of key to close
1058 * Success: ERROR_SUCCESS
1059 * Failure: Error code
1061 LSTATUS WINAPI
RegCloseKey( HKEY hkey
)
1063 if (!hkey
) return ERROR_INVALID_HANDLE
;
1064 if (hkey
>= (HKEY
)0x80000000) return ERROR_SUCCESS
;
1065 return RtlNtStatusToDosError( NtClose( hkey
) );
1069 /******************************************************************************
1070 * RegDeleteKeyExW [ADVAPI32.@]
1072 LSTATUS WINAPI
RegDeleteKeyExW( HKEY hkey
, LPCWSTR name
, REGSAM access
, DWORD reserved
)
1077 if (!name
) return ERROR_INVALID_PARAMETER
;
1079 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1081 access
&= KEY_WOW64_64KEY
| KEY_WOW64_32KEY
;
1082 if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, access
| DELETE
, &tmp
)))
1084 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
1087 TRACE("%s ret=%08x\n", debugstr_w(name
), ret
);
1092 /******************************************************************************
1093 * RegDeleteKeyW [ADVAPI32.@]
1095 * See RegDeleteKeyA.
1097 LSTATUS WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
1099 return RegDeleteKeyExW( hkey
, name
, 0, 0 );
1103 /******************************************************************************
1104 * RegDeleteKeyExA [ADVAPI32.@]
1106 LSTATUS WINAPI
RegDeleteKeyExA( HKEY hkey
, LPCSTR name
, REGSAM access
, DWORD reserved
)
1111 if (!name
) return ERROR_INVALID_PARAMETER
;
1113 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1115 access
&= KEY_WOW64_64KEY
| KEY_WOW64_32KEY
;
1116 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, access
| DELETE
, &tmp
)))
1118 if (!is_version_nt()) /* win95 does recursive key deletes */
1122 while(!RegEnumKeyA(tmp
, 0, sub
, sizeof(sub
)))
1124 if(RegDeleteKeyExA(tmp
, sub
, access
, reserved
)) /* recurse */
1128 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
1131 TRACE("%s ret=%08x\n", debugstr_a(name
), ret
);
1136 /******************************************************************************
1137 * RegDeleteKeyA [ADVAPI32.@]
1139 * Delete a registry key.
1142 * hkey [I] Handle to parent key containing the key to delete
1143 * name [I] Name of the key user hkey to delete
1147 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1148 * right. In reality, it opens a new handle with DELETE access.
1151 * Success: ERROR_SUCCESS
1152 * Failure: Error code
1154 LSTATUS WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
1156 return RegDeleteKeyExA( hkey
, name
, 0, 0 );
1161 /******************************************************************************
1162 * RegSetValueExW [ADVAPI32.@]
1164 * Set the data and contents of a registry value.
1167 * hkey [I] Handle of key to set value for
1168 * name [I] Name of value to set
1169 * reserved [I] Reserved, must be zero
1170 * type [I] Type of the value being set
1171 * data [I] The new contents of the value to set
1172 * count [I] Size of data
1175 * Success: ERROR_SUCCESS
1176 * Failure: Error code
1178 LSTATUS WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
1179 DWORD type
, CONST BYTE
*data
, DWORD count
)
1181 UNICODE_STRING nameW
;
1183 /* no need for version check, not implemented on win9x anyway */
1185 if (data
&& ((ULONG_PTR
)data
>> 16) == 0) return ERROR_NOACCESS
;
1187 if (count
&& is_string(type
))
1189 LPCWSTR str
= (LPCWSTR
)data
;
1190 /* if user forgot to count terminating null, add it (yes NT does this) */
1191 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
1192 count
+= sizeof(WCHAR
);
1194 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1196 RtlInitUnicodeString( &nameW
, name
);
1197 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
1201 /******************************************************************************
1202 * RegSetValueExA [ADVAPI32.@]
1204 * See RegSetValueExW.
1207 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1208 * NT does definitely care (aj)
1210 LSTATUS WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1211 CONST BYTE
*data
, DWORD count
)
1214 UNICODE_STRING nameW
;
1215 WCHAR
*dataW
= NULL
;
1218 if (!is_version_nt()) /* win95 */
1222 if (!data
) return ERROR_INVALID_PARAMETER
;
1223 count
= strlen((const char *)data
) + 1;
1226 else if (count
&& is_string(type
))
1228 /* if user forgot to count terminating null, add it (yes NT does this) */
1229 if (data
[count
-1] && !data
[count
]) count
++;
1232 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1234 if (is_string( type
)) /* need to convert to Unicode */
1237 RtlMultiByteToUnicodeSize( &lenW
, (const char *)data
, count
);
1238 if (!(dataW
= HeapAlloc( GetProcessHeap(), 0, lenW
))) return ERROR_OUTOFMEMORY
;
1239 RtlMultiByteToUnicodeN( dataW
, lenW
, NULL
, (const char *)data
, count
);
1241 data
= (BYTE
*)dataW
;
1244 RtlInitAnsiString( &nameA
, name
);
1245 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1247 status
= NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
);
1248 RtlFreeUnicodeString( &nameW
);
1250 HeapFree( GetProcessHeap(), 0, dataW
);
1251 return RtlNtStatusToDosError( status
);
1255 /******************************************************************************
1256 * RegSetValueW [ADVAPI32.@]
1258 * Sets the data for the default or unnamed value of a reg key.
1261 * hKey [I] Handle to an open key.
1262 * lpSubKey [I] Name of a subkey of hKey.
1263 * dwType [I] Type of information to store.
1264 * lpData [I] String that contains the data to set for the default value.
1265 * cbData [I] Ignored.
1268 * Success: ERROR_SUCCESS
1269 * Failure: nonzero error code from Winerror.h
1271 LSTATUS WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR name
, DWORD type
, LPCWSTR data
, DWORD count
)
1276 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_w(name
), type
, debugstr_w(data
), count
);
1278 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1280 if (name
&& name
[0]) /* need to create the subkey */
1282 if ((ret
= RegCreateKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1285 ret
= RegSetValueExW( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)data
,
1286 (strlenW( data
) + 1) * sizeof(WCHAR
) );
1287 if (subkey
!= hkey
) RegCloseKey( subkey
);
1292 /******************************************************************************
1293 * RegSetValueA [ADVAPI32.@]
1297 LSTATUS WINAPI
RegSetValueA( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1302 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_a(name
), type
, debugstr_a(data
), count
);
1304 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1306 if (name
&& name
[0]) /* need to create the subkey */
1308 if ((ret
= RegCreateKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1310 ret
= RegSetValueExA( subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)data
, strlen(data
)+1 );
1311 if (subkey
!= hkey
) RegCloseKey( subkey
);
1317 /******************************************************************************
1318 * RegQueryValueExW [ADVAPI32.@]
1320 * See RegQueryValueExA.
1322 LSTATUS WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
1323 LPBYTE data
, LPDWORD count
)
1326 UNICODE_STRING name_str
;
1328 char buffer
[256], *buf_ptr
= buffer
;
1329 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1330 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1332 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1333 hkey
, debugstr_w(name
), reserved
, type
, data
, count
,
1334 (count
&& data
) ? *count
: 0 );
1336 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1337 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1339 RtlInitUnicodeString( &name_str
, name
);
1341 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
1344 total_size
= info_size
;
1345 if (count
) *count
= 0;
1348 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1349 buffer
, total_size
, &total_size
);
1350 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1354 /* retry with a dynamically allocated buffer */
1355 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
1357 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1358 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1359 return ERROR_NOT_ENOUGH_MEMORY
;
1360 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1361 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1362 buf_ptr
, total_size
, &total_size
);
1367 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1368 /* if the type is REG_SZ and data is not 0-terminated
1369 * and there is enough space in the buffer NT appends a \0 */
1370 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1372 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
1373 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1376 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1378 else status
= STATUS_SUCCESS
;
1380 if (type
) *type
= info
->Type
;
1381 if (count
) *count
= total_size
- info_size
;
1384 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1385 return RtlNtStatusToDosError(status
);
1389 /******************************************************************************
1390 * RegQueryValueExA [ADVAPI32.@]
1392 * Get the type and contents of a specified value under with a key.
1395 * hkey [I] Handle of the key to query
1396 * name [I] Name of value under hkey to query
1397 * reserved [I] Reserved - must be NULL
1398 * type [O] Destination for the value type, or NULL if not required
1399 * data [O] Destination for the values contents, or NULL if not required
1400 * count [I/O] Size of data, updated with the number of bytes returned
1403 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1404 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1405 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1406 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1409 * MSDN states that if data is too small it is partially filled. In reality
1410 * it remains untouched.
1412 LSTATUS WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1413 LPBYTE data
, LPDWORD count
)
1417 UNICODE_STRING nameW
;
1418 DWORD total_size
, datalen
= 0;
1419 char buffer
[256], *buf_ptr
= buffer
;
1420 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1421 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1423 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1424 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
1426 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1427 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1429 if (count
) datalen
= *count
;
1430 if (!data
&& count
) *count
= 0;
1432 /* this matches Win9x behaviour - NT sets *type to a random value */
1433 if (type
) *type
= REG_NONE
;
1435 RtlInitAnsiString( &nameA
, name
);
1436 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1437 return RtlNtStatusToDosError(status
);
1439 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1440 buffer
, sizeof(buffer
), &total_size
);
1441 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1443 /* we need to fetch the contents for a string type even if not requested,
1444 * because we need to compute the length of the ASCII string. */
1445 if (data
|| is_string(info
->Type
))
1447 /* retry with a dynamically allocated buffer */
1448 while (status
== STATUS_BUFFER_OVERFLOW
)
1450 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1451 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1453 status
= STATUS_NO_MEMORY
;
1456 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1457 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1458 buf_ptr
, total_size
, &total_size
);
1461 if (status
) goto done
;
1463 if (is_string(info
->Type
))
1467 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
1468 total_size
- info_size
);
1471 if (len
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1474 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
1475 total_size
- info_size
);
1476 /* if the type is REG_SZ and data is not 0-terminated
1477 * and there is enough space in the buffer NT appends a \0 */
1478 if (len
< datalen
&& data
[len
-1]) data
[len
] = 0;
1481 total_size
= len
+ info_size
;
1485 if (total_size
- info_size
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1486 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1489 else status
= STATUS_SUCCESS
;
1491 if (type
) *type
= info
->Type
;
1492 if (count
) *count
= total_size
- info_size
;
1495 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1496 RtlFreeUnicodeString( &nameW
);
1497 return RtlNtStatusToDosError(status
);
1501 /******************************************************************************
1502 * RegQueryValueW [ADVAPI32.@]
1504 * Retrieves the data associated with the default or unnamed value of a key.
1507 * hkey [I] Handle to an open key.
1508 * name [I] Name of the subkey of hKey.
1509 * data [O] Receives the string associated with the default value
1511 * count [I/O] Size of lpValue in bytes.
1514 * Success: ERROR_SUCCESS
1515 * Failure: nonzero error code from Winerror.h
1517 LSTATUS WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
1522 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
1524 if (name
&& name
[0])
1526 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1528 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1529 if (subkey
!= hkey
) RegCloseKey( subkey
);
1530 if (ret
== ERROR_FILE_NOT_FOUND
)
1532 /* return empty string if default value not found */
1533 if (data
) *data
= 0;
1534 if (count
) *count
= sizeof(WCHAR
);
1535 ret
= ERROR_SUCCESS
;
1541 /******************************************************************************
1542 * RegQueryValueA [ADVAPI32.@]
1544 * See RegQueryValueW.
1546 LSTATUS WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
1551 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
1553 if (name
&& name
[0])
1555 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1557 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1558 if (subkey
!= hkey
) RegCloseKey( subkey
);
1559 if (ret
== ERROR_FILE_NOT_FOUND
)
1561 /* return empty string if default value not found */
1562 if (data
) *data
= 0;
1563 if (count
) *count
= 1;
1564 ret
= ERROR_SUCCESS
;
1570 /******************************************************************************
1571 * ADVAPI_ApplyRestrictions [internal]
1573 * Helper function for RegGetValueA/W.
1575 static VOID
ADVAPI_ApplyRestrictions( DWORD dwFlags
, DWORD dwType
,
1576 DWORD cbData
, PLONG ret
)
1578 /* Check if the type is restricted by the passed flags */
1579 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1585 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1586 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1587 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1588 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1589 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1590 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1591 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1594 if (dwFlags
& dwMask
)
1596 /* Type is not restricted, check for size mismatch */
1597 if (dwType
== REG_BINARY
)
1601 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
1603 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
1606 if (cbExpect
&& cbData
!= cbExpect
)
1607 *ret
= ERROR_DATATYPE_MISMATCH
;
1610 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1615 /******************************************************************************
1616 * RegGetValueW [ADVAPI32.@]
1618 * Retrieves the type and data for a value name associated with a key,
1619 * optionally expanding its content and restricting its type.
1622 * hKey [I] Handle to an open key.
1623 * pszSubKey [I] Name of the subkey of hKey.
1624 * pszValue [I] Name of value under hKey/szSubKey to query.
1625 * dwFlags [I] Flags restricting the value type to retrieve.
1626 * pdwType [O] Destination for the values type, may be NULL.
1627 * pvData [O] Destination for the values content, may be NULL.
1628 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1629 * retrieve the whole content, including the trailing '\0'
1633 * Success: ERROR_SUCCESS
1634 * Failure: nonzero error code from Winerror.h
1637 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1638 * expanded and pdwType is set to REG_SZ instead.
1639 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1640 * without RRF_NOEXPAND is thus not allowed.
1641 * An exception is the case where RRF_RT_ANY is specified, because then
1642 * RRF_NOEXPAND is allowed.
1644 LSTATUS WINAPI
RegGetValueW( HKEY hKey
, LPCWSTR pszSubKey
, LPCWSTR pszValue
,
1645 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1648 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1652 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1653 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1654 pvData
, pcbData
, cbData
);
1656 if (pvData
&& !pcbData
)
1657 return ERROR_INVALID_PARAMETER
;
1658 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1659 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1660 return ERROR_INVALID_PARAMETER
;
1662 if (pszSubKey
&& pszSubKey
[0])
1664 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1665 if (ret
!= ERROR_SUCCESS
) return ret
;
1668 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1670 /* If we are going to expand we need to read in the whole the value even
1671 * if the passed buffer was too small as the expanded string might be
1672 * smaller than the unexpanded one and could fit into cbData bytes. */
1673 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1674 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1677 HeapFree(GetProcessHeap(), 0, pvBuf
);
1679 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1682 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1686 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1687 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
1688 &dwType
, pvBuf
, &cbData
);
1691 /* Even if cbData was large enough we have to copy the
1692 * string since ExpandEnvironmentStrings can't handle
1693 * overlapping buffers. */
1694 CopyMemory(pvBuf
, pvData
, cbData
);
1697 /* Both the type or the value itself could have been modified in
1698 * between so we have to keep retrying until the buffer is large
1699 * enough or we no longer have to expand the value. */
1700 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1702 if (ret
== ERROR_SUCCESS
)
1704 /* Recheck dwType in case it changed since the first call */
1705 if (dwType
== REG_EXPAND_SZ
)
1707 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
1708 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
1710 if(pvData
&& pcbData
&& cbData
> *pcbData
)
1711 ret
= ERROR_MORE_DATA
;
1714 CopyMemory(pvData
, pvBuf
, *pcbData
);
1717 HeapFree(GetProcessHeap(), 0, pvBuf
);
1720 if (pszSubKey
&& pszSubKey
[0])
1723 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1725 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1726 ZeroMemory(pvData
, *pcbData
);
1728 if (pdwType
) *pdwType
= dwType
;
1729 if (pcbData
) *pcbData
= cbData
;
1735 /******************************************************************************
1736 * RegGetValueA [ADVAPI32.@]
1740 LSTATUS WINAPI
RegGetValueA( HKEY hKey
, LPCSTR pszSubKey
, LPCSTR pszValue
,
1741 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1744 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1748 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1749 hKey
, debugstr_a(pszSubKey
), debugstr_a(pszValue
), dwFlags
,
1750 pdwType
, pvData
, pcbData
, cbData
);
1752 if (pvData
&& !pcbData
)
1753 return ERROR_INVALID_PARAMETER
;
1754 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1755 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1756 return ERROR_INVALID_PARAMETER
;
1758 if (pszSubKey
&& pszSubKey
[0])
1760 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1761 if (ret
!= ERROR_SUCCESS
) return ret
;
1764 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1766 /* If we are going to expand we need to read in the whole the value even
1767 * if the passed buffer was too small as the expanded string might be
1768 * smaller than the unexpanded one and could fit into cbData bytes. */
1769 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1770 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1773 HeapFree(GetProcessHeap(), 0, pvBuf
);
1775 pvBuf
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1778 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1782 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1783 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
1784 &dwType
, pvBuf
, &cbData
);
1787 /* Even if cbData was large enough we have to copy the
1788 * string since ExpandEnvironmentStrings can't handle
1789 * overlapping buffers. */
1790 CopyMemory(pvBuf
, pvData
, cbData
);
1793 /* Both the type or the value itself could have been modified in
1794 * between so we have to keep retrying until the buffer is large
1795 * enough or we no longer have to expand the value. */
1796 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1798 if (ret
== ERROR_SUCCESS
)
1800 /* Recheck dwType in case it changed since the first call */
1801 if (dwType
== REG_EXPAND_SZ
)
1803 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
1804 pcbData
? *pcbData
: 0);
1806 if(pvData
&& pcbData
&& cbData
> *pcbData
)
1807 ret
= ERROR_MORE_DATA
;
1810 CopyMemory(pvData
, pvBuf
, *pcbData
);
1813 HeapFree(GetProcessHeap(), 0, pvBuf
);
1816 if (pszSubKey
&& pszSubKey
[0])
1819 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1821 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1822 ZeroMemory(pvData
, *pcbData
);
1824 if (pdwType
) *pdwType
= dwType
;
1825 if (pcbData
) *pcbData
= cbData
;
1831 /******************************************************************************
1832 * RegEnumValueW [ADVAPI32.@]
1834 * Enumerates the values for the specified open registry key.
1837 * hkey [I] Handle to key to query
1838 * index [I] Index of value to query
1839 * value [O] Value string
1840 * val_count [I/O] Size of value buffer (in wchars)
1841 * reserved [I] Reserved
1842 * type [O] Type code
1843 * data [O] Value data
1844 * count [I/O] Size of data buffer (in bytes)
1847 * Success: ERROR_SUCCESS
1848 * Failure: nonzero error code from Winerror.h
1851 LSTATUS WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
1852 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1856 char buffer
[256], *buf_ptr
= buffer
;
1857 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1858 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1860 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1861 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1863 /* NT only checks count, not val_count */
1864 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1865 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1867 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1868 if (data
) total_size
+= *count
;
1869 total_size
= min( sizeof(buffer
), total_size
);
1871 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1872 buffer
, total_size
, &total_size
);
1873 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1877 /* retry with a dynamically allocated buffer */
1878 while (status
== STATUS_BUFFER_OVERFLOW
)
1880 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1881 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1882 return ERROR_NOT_ENOUGH_MEMORY
;
1883 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1884 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1885 buf_ptr
, total_size
, &total_size
);
1888 if (status
) goto done
;
1892 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
1894 status
= STATUS_BUFFER_OVERFLOW
;
1897 memcpy( value
, info
->Name
, info
->NameLength
);
1898 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
1899 value
[*val_count
] = 0;
1904 if (total_size
- info
->DataOffset
> *count
)
1906 status
= STATUS_BUFFER_OVERFLOW
;
1909 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1910 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1912 /* if the type is REG_SZ and data is not 0-terminated
1913 * and there is enough space in the buffer NT appends a \0 */
1914 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
1915 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1919 else status
= STATUS_SUCCESS
;
1922 if (type
) *type
= info
->Type
;
1923 if (count
) *count
= info
->DataLength
;
1926 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1927 return RtlNtStatusToDosError(status
);
1931 /******************************************************************************
1932 * RegEnumValueA [ADVAPI32.@]
1934 * See RegEnumValueW.
1936 LSTATUS WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1937 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1941 char buffer
[256], *buf_ptr
= buffer
;
1942 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1943 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1945 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1946 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1948 /* NT only checks count, not val_count */
1949 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1950 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
1952 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1953 if (data
) total_size
+= *count
;
1954 total_size
= min( sizeof(buffer
), total_size
);
1956 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1957 buffer
, total_size
, &total_size
);
1958 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1960 /* we need to fetch the contents for a string type even if not requested,
1961 * because we need to compute the length of the ASCII string. */
1962 if (value
|| data
|| is_string(info
->Type
))
1964 /* retry with a dynamically allocated buffer */
1965 while (status
== STATUS_BUFFER_OVERFLOW
)
1967 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
1968 if (!(buf_ptr
= HeapAlloc( GetProcessHeap(), 0, total_size
)))
1969 return ERROR_NOT_ENOUGH_MEMORY
;
1970 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1971 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1972 buf_ptr
, total_size
, &total_size
);
1975 if (status
) goto done
;
1977 if (is_string(info
->Type
))
1980 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1981 total_size
- info
->DataOffset
);
1984 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1987 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
1988 total_size
- info
->DataOffset
);
1989 /* if the type is REG_SZ and data is not 0-terminated
1990 * and there is enough space in the buffer NT appends a \0 */
1991 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
1994 info
->DataLength
= len
;
1998 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
1999 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2002 if (value
&& !status
)
2006 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2007 if (len
>= *val_count
)
2009 status
= STATUS_BUFFER_OVERFLOW
;
2012 len
= *val_count
- 1;
2013 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2019 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2025 else status
= STATUS_SUCCESS
;
2027 if (type
) *type
= info
->Type
;
2028 if (count
) *count
= info
->DataLength
;
2031 if (buf_ptr
!= buffer
) HeapFree( GetProcessHeap(), 0, buf_ptr
);
2032 return RtlNtStatusToDosError(status
);
2037 /******************************************************************************
2038 * RegDeleteValueW [ADVAPI32.@]
2040 * See RegDeleteValueA.
2042 LSTATUS WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
2044 UNICODE_STRING nameW
;
2046 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
2048 RtlInitUnicodeString( &nameW
, name
);
2049 return RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
2053 /******************************************************************************
2054 * RegDeleteValueA [ADVAPI32.@]
2056 * Delete a value from the registry.
2059 * hkey [I] Registry handle of the key holding the value
2060 * name [I] Name of the value under hkey to delete
2063 * Success: ERROR_SUCCESS
2064 * Failure: nonzero error code from Winerror.h
2066 LSTATUS WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
2069 UNICODE_STRING nameW
;
2072 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
2074 RtlInitAnsiString( &nameA
, name
);
2075 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
2077 status
= NtDeleteValueKey( hkey
, &nameW
);
2078 RtlFreeUnicodeString( &nameW
);
2080 return RtlNtStatusToDosError( status
);
2084 /******************************************************************************
2085 * RegLoadKeyW [ADVAPI32.@]
2087 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2088 * registration information from a specified file into that subkey.
2091 * hkey [I] Handle of open key
2092 * subkey [I] Address of name of subkey
2093 * filename [I] Address of filename for registry information
2096 * Success: ERROR_SUCCESS
2097 * Failure: nonzero error code from Winerror.h
2099 LSTATUS WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
2101 OBJECT_ATTRIBUTES destkey
, file
;
2102 UNICODE_STRING subkeyW
, filenameW
;
2105 if (!(hkey
= get_special_root_hkey(hkey
))) return ERROR_INVALID_HANDLE
;
2107 destkey
.Length
= sizeof(destkey
);
2108 destkey
.RootDirectory
= hkey
; /* root key: HKLM or HKU */
2109 destkey
.ObjectName
= &subkeyW
; /* name of the key */
2110 destkey
.Attributes
= 0;
2111 destkey
.SecurityDescriptor
= NULL
;
2112 destkey
.SecurityQualityOfService
= NULL
;
2113 RtlInitUnicodeString(&subkeyW
, subkey
);
2115 file
.Length
= sizeof(file
);
2116 file
.RootDirectory
= NULL
;
2117 file
.ObjectName
= &filenameW
; /* file containing the hive */
2118 file
.Attributes
= OBJ_CASE_INSENSITIVE
;
2119 file
.SecurityDescriptor
= NULL
;
2120 file
.SecurityQualityOfService
= NULL
;
2121 RtlDosPathNameToNtPathName_U(filename
, &filenameW
, NULL
, NULL
);
2123 status
= NtLoadKey(&destkey
, &file
);
2124 RtlFreeUnicodeString(&filenameW
);
2125 return RtlNtStatusToDosError( status
);
2129 /******************************************************************************
2130 * RegLoadKeyA [ADVAPI32.@]
2134 LSTATUS WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
2136 UNICODE_STRING subkeyW
, filenameW
;
2137 STRING subkeyA
, filenameA
;
2141 RtlInitAnsiString(&subkeyA
, subkey
);
2142 RtlInitAnsiString(&filenameA
, filename
);
2144 RtlInitUnicodeString(&subkeyW
, NULL
);
2145 RtlInitUnicodeString(&filenameW
, NULL
);
2146 if (!(status
= RtlAnsiStringToUnicodeString(&subkeyW
, &subkeyA
, TRUE
)) &&
2147 !(status
= RtlAnsiStringToUnicodeString(&filenameW
, &filenameA
, TRUE
)))
2149 ret
= RegLoadKeyW(hkey
, subkeyW
.Buffer
, filenameW
.Buffer
);
2151 else ret
= RtlNtStatusToDosError(status
);
2152 RtlFreeUnicodeString(&subkeyW
);
2153 RtlFreeUnicodeString(&filenameW
);
2158 /******************************************************************************
2159 * RegSaveKeyW [ADVAPI32.@]
2161 * Save a key and all of its subkeys and values to a new file in the standard format.
2164 * hkey [I] Handle of key where save begins
2165 * lpFile [I] Address of filename to save to
2166 * sa [I] Address of security structure
2169 * Success: ERROR_SUCCESS
2170 * Failure: nonzero error code from Winerror.h
2172 LSTATUS WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
2174 static const WCHAR format
[] =
2175 {'r','e','g','%','0','4','x','.','t','m','p',0};
2176 WCHAR buffer
[MAX_PATH
];
2182 TRACE( "(%p,%s,%p)\n", hkey
, debugstr_w(file
), sa
);
2184 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
2185 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
2187 err
= GetLastError();
2188 GetFullPathNameW( file
, sizeof(buffer
)/sizeof(WCHAR
), buffer
, &nameW
);
2192 snprintfW( nameW
, 16, format
, count
++ );
2193 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
2194 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
2195 if (handle
!= INVALID_HANDLE_VALUE
) break;
2196 if ((ret
= GetLastError()) != ERROR_FILE_EXISTS
) goto done
;
2198 /* Something gone haywire ? Please report if this happens abnormally */
2200 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
);
2203 ret
= RtlNtStatusToDosError(NtSaveKey(hkey
, handle
));
2205 CloseHandle( handle
);
2208 if (!MoveFileExW( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
2210 ERR( "Failed to move %s to %s\n", debugstr_w(buffer
),
2212 ret
= GetLastError();
2215 if (ret
) DeleteFileW( buffer
);
2218 SetLastError( err
); /* restore last error code */
2223 /******************************************************************************
2224 * RegSaveKeyA [ADVAPI32.@]
2228 LSTATUS WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
2230 UNICODE_STRING
*fileW
= &NtCurrentTeb()->StaticUnicodeString
;
2234 RtlInitAnsiString(&fileA
, file
);
2235 if ((status
= RtlAnsiStringToUnicodeString(fileW
, &fileA
, FALSE
)))
2236 return RtlNtStatusToDosError( status
);
2237 return RegSaveKeyW(hkey
, fileW
->Buffer
, sa
);
2241 /******************************************************************************
2242 * RegRestoreKeyW [ADVAPI32.@]
2244 * Read the registry information from a file and copy it over a key.
2247 * hkey [I] Handle of key where restore begins
2248 * lpFile [I] Address of filename containing saved tree
2249 * dwFlags [I] Optional flags
2252 * Success: ERROR_SUCCESS
2253 * Failure: nonzero error code from Winerror.h
2255 LSTATUS WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
2257 TRACE("(%p,%s,%d)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2259 /* It seems to do this check before the hkey check */
2260 if (!lpFile
|| !*lpFile
)
2261 return ERROR_INVALID_PARAMETER
;
2263 FIXME("(%p,%s,%d): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2265 /* Check for file existence */
2267 return ERROR_SUCCESS
;
2271 /******************************************************************************
2272 * RegRestoreKeyA [ADVAPI32.@]
2274 * See RegRestoreKeyW.
2276 LSTATUS WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
2278 UNICODE_STRING lpFileW
;
2281 RtlCreateUnicodeStringFromAsciiz( &lpFileW
, lpFile
);
2282 ret
= RegRestoreKeyW( hkey
, lpFileW
.Buffer
, dwFlags
);
2283 RtlFreeUnicodeString( &lpFileW
);
2288 /******************************************************************************
2289 * RegUnLoadKeyW [ADVAPI32.@]
2291 * Unload a registry key and its subkeys from the registry.
2294 * hkey [I] Handle of open key
2295 * lpSubKey [I] Address of name of subkey to unload
2298 * Success: ERROR_SUCCESS
2299 * Failure: nonzero error code from Winerror.h
2301 LSTATUS WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
2305 OBJECT_ATTRIBUTES attr
;
2306 UNICODE_STRING subkey
;
2308 TRACE("(%p,%s)\n",hkey
, debugstr_w(lpSubKey
));
2310 ret
= RegOpenKeyW(hkey
,lpSubKey
,&shkey
);
2312 return ERROR_INVALID_PARAMETER
;
2314 RtlInitUnicodeString(&subkey
, lpSubKey
);
2315 InitializeObjectAttributes(&attr
, &subkey
, OBJ_CASE_INSENSITIVE
, shkey
, NULL
);
2316 ret
= RtlNtStatusToDosError(NtUnloadKey(&attr
));
2324 /******************************************************************************
2325 * RegUnLoadKeyA [ADVAPI32.@]
2327 * See RegUnLoadKeyW.
2329 LSTATUS WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
2331 UNICODE_STRING lpSubKeyW
;
2334 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2335 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
.Buffer
);
2336 RtlFreeUnicodeString( &lpSubKeyW
);
2341 /******************************************************************************
2342 * RegReplaceKeyW [ADVAPI32.@]
2344 * Replace the file backing a registry key and all its subkeys with another file.
2347 * hkey [I] Handle of open key
2348 * lpSubKey [I] Address of name of subkey
2349 * lpNewFile [I] Address of filename for file with new data
2350 * lpOldFile [I] Address of filename for backup file
2353 * Success: ERROR_SUCCESS
2354 * Failure: nonzero error code from Winerror.h
2356 LSTATUS WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
2359 FIXME("(%p,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
2360 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
2361 return ERROR_SUCCESS
;
2365 /******************************************************************************
2366 * RegReplaceKeyA [ADVAPI32.@]
2368 * See RegReplaceKeyW.
2370 LSTATUS WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
2373 UNICODE_STRING lpSubKeyW
;
2374 UNICODE_STRING lpNewFileW
;
2375 UNICODE_STRING lpOldFileW
;
2378 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2379 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW
, lpOldFile
);
2380 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW
, lpNewFile
);
2381 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
.Buffer
, lpNewFileW
.Buffer
, lpOldFileW
.Buffer
);
2382 RtlFreeUnicodeString( &lpOldFileW
);
2383 RtlFreeUnicodeString( &lpNewFileW
);
2384 RtlFreeUnicodeString( &lpSubKeyW
);
2389 /******************************************************************************
2390 * RegSetKeySecurity [ADVAPI32.@]
2392 * Set the security of an open registry key.
2395 * hkey [I] Open handle of key to set
2396 * SecurityInfo [I] Descriptor contents
2397 * pSecurityDesc [I] Address of descriptor for key
2400 * Success: ERROR_SUCCESS
2401 * Failure: nonzero error code from Winerror.h
2403 LSTATUS WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
2404 PSECURITY_DESCRIPTOR pSecurityDesc
)
2406 TRACE("(%p,%d,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
2408 /* It seems to perform this check before the hkey check */
2409 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
2410 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
2411 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
2412 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
2415 return ERROR_INVALID_PARAMETER
;
2418 return ERROR_INVALID_PARAMETER
;
2420 FIXME(":(%p,%d,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
2422 return ERROR_SUCCESS
;
2426 /******************************************************************************
2427 * RegGetKeySecurity [ADVAPI32.@]
2429 * Get a copy of the security descriptor for a given registry key.
2432 * hkey [I] Open handle of key to set
2433 * SecurityInformation [I] Descriptor contents
2434 * pSecurityDescriptor [O] Address of descriptor for key
2435 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2438 * Success: ERROR_SUCCESS
2439 * Failure: Error code
2441 LSTATUS WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
2442 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2443 LPDWORD lpcbSecurityDescriptor
)
2445 TRACE("(%p,%d,%p,%d)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
2446 *lpcbSecurityDescriptor
);
2448 if (!(hkey
= get_special_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
2450 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey
,
2451 SecurityInformation
, pSecurityDescriptor
,
2452 *lpcbSecurityDescriptor
, lpcbSecurityDescriptor
) );
2456 /******************************************************************************
2457 * RegFlushKey [ADVAPI32.@]
2459 * Immediately write a registry key to registry.
2462 * hkey [I] Handle of key to write
2465 * Success: ERROR_SUCCESS
2466 * Failure: Error code
2468 LSTATUS WINAPI
RegFlushKey( HKEY hkey
)
2470 hkey
= get_special_root_hkey( hkey
);
2471 if (!hkey
) return ERROR_INVALID_HANDLE
;
2473 return RtlNtStatusToDosError( NtFlushKey( hkey
) );
2477 /******************************************************************************
2478 * RegConnectRegistryW [ADVAPI32.@]
2480 * Establish a connection to a predefined registry key on another computer.
2483 * lpMachineName [I] Address of name of remote computer
2484 * hHey [I] Predefined registry handle
2485 * phkResult [I] Address of buffer for remote registry handle
2488 * Success: ERROR_SUCCESS
2489 * Failure: nonzero error code from Winerror.h
2491 LSTATUS WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
2496 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName
), hKey
, phkResult
);
2498 if (!lpMachineName
|| !*lpMachineName
) {
2499 /* Use the local machine name */
2500 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
2503 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
2504 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
2506 /* MSDN says lpMachineName must start with \\ : not so */
2507 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
2509 if (GetComputerNameW(compName
, &len
))
2511 if (!strcmpiW(lpMachineName
, compName
))
2512 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
2515 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
2516 ret
= ERROR_BAD_NETPATH
;
2520 ret
= GetLastError();
2526 /******************************************************************************
2527 * RegConnectRegistryA [ADVAPI32.@]
2529 * See RegConnectRegistryW.
2531 LSTATUS WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, PHKEY reskey
)
2533 UNICODE_STRING machineW
;
2536 RtlCreateUnicodeStringFromAsciiz( &machineW
, machine
);
2537 ret
= RegConnectRegistryW( machineW
.Buffer
, hkey
, reskey
);
2538 RtlFreeUnicodeString( &machineW
);
2543 /******************************************************************************
2544 * RegNotifyChangeKeyValue [ADVAPI32.@]
2546 * Notify the caller about changes to the attributes or contents of a registry key.
2549 * hkey [I] Handle of key to watch
2550 * fWatchSubTree [I] Flag for subkey notification
2551 * fdwNotifyFilter [I] Changes to be reported
2552 * hEvent [I] Handle of signaled event
2553 * fAsync [I] Flag for asynchronous reporting
2556 * Success: ERROR_SUCCESS
2557 * Failure: nonzero error code from Winerror.h
2559 LSTATUS WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
2560 DWORD fdwNotifyFilter
, HANDLE hEvent
,
2564 IO_STATUS_BLOCK iosb
;
2566 hkey
= get_special_root_hkey( hkey
);
2567 if (!hkey
) return ERROR_INVALID_HANDLE
;
2569 TRACE("(%p,%i,%d,%p,%i)\n", hkey
, fWatchSubTree
, fdwNotifyFilter
,
2572 status
= NtNotifyChangeKey( hkey
, hEvent
, NULL
, NULL
, &iosb
,
2573 fdwNotifyFilter
, fAsync
, NULL
, 0,
2576 if (status
&& status
!= STATUS_TIMEOUT
)
2577 return RtlNtStatusToDosError( status
);
2579 return ERROR_SUCCESS
;
2582 /******************************************************************************
2583 * RegOpenUserClassesRoot [ADVAPI32.@]
2585 * Open the HKEY_CLASSES_ROOT key for a user.
2588 * hToken [I] Handle of token representing the user
2589 * dwOptions [I] Reserved, must be 0
2590 * samDesired [I] Desired access rights
2591 * phkResult [O] Destination for the resulting key handle
2594 * Success: ERROR_SUCCESS
2595 * Failure: nonzero error code from Winerror.h
2598 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2599 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2600 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2602 LSTATUS WINAPI
RegOpenUserClassesRoot(
2609 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken
, dwOptions
, samDesired
, phkResult
);
2611 *phkResult
= HKEY_CLASSES_ROOT
;
2612 return ERROR_SUCCESS
;
2615 /******************************************************************************
2616 * load_string [Internal]
2618 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2619 * avoid importing user32, which is higher level than advapi32. Helper for
2622 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
2629 /* Negative values have to be inverted. */
2630 if (HIWORD(resId
) == 0xffff)
2631 resId
= (UINT
)(-((INT
)resId
));
2633 /* Load the resource into memory and get a pointer to it. */
2634 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
2635 if (!hResource
) return 0;
2636 hMemory
= LoadResource(hModule
, hResource
);
2637 if (!hMemory
) return 0;
2638 pString
= LockResource(hMemory
);
2640 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2641 idxString
= resId
& 0xf;
2642 while (idxString
--) pString
+= *pString
+ 1;
2644 /* If no buffer is given, return length of the string. */
2645 if (!pwszBuffer
) return *pString
;
2647 /* Else copy over the string, respecting the buffer size. */
2648 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
2649 if (cMaxChars
>= 0) {
2650 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
2651 pwszBuffer
[cMaxChars
] = '\0';
2657 /******************************************************************************
2658 * RegLoadMUIStringW [ADVAPI32.@]
2660 * Load the localized version of a string resource from some PE, respective
2661 * id and path of which are given in the registry value in the format
2662 * @[path]\dllname,-resourceId
2665 * hKey [I] Key, of which to load the string value from.
2666 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2667 * pszBuffer [O] Buffer to store the localized string in.
2668 * cbBuffer [I] Size of the destination buffer in bytes.
2669 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2670 * dwFlags [I] None supported yet.
2671 * pszBaseDir [I] Not supported yet.
2674 * Success: ERROR_SUCCESS,
2675 * Failure: nonzero error code from winerror.h
2678 * This is an API of Windows Vista, which wasn't available at the time this code
2679 * was written. We have to check for the correct behaviour once it's available.
2681 LSTATUS WINAPI
RegLoadMUIStringW(HKEY hKey
, LPCWSTR pwszValue
, LPWSTR pwszBuffer
, DWORD cbBuffer
,
2682 LPDWORD pcbData
, DWORD dwFlags
, LPCWSTR pwszBaseDir
)
2684 DWORD dwValueType
, cbData
;
2685 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
2688 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2689 "dwFlags = %d, pwszBaseDir = %s)\n", hKey
, debugstr_w(pwszValue
), pwszBuffer
,
2690 cbBuffer
, pcbData
, dwFlags
, debugstr_w(pwszBaseDir
));
2692 /* Parameter sanity checks. */
2693 if (!hKey
|| !pwszBuffer
)
2694 return ERROR_INVALID_PARAMETER
;
2696 if (pwszBaseDir
&& *pwszBaseDir
) {
2697 FIXME("BaseDir parameter not yet supported!\n");
2698 return ERROR_INVALID_PARAMETER
;
2701 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2702 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
2703 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2704 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
) {
2705 result
= ERROR_FILE_NOT_FOUND
;
2708 pwszTempBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2709 if (!pwszTempBuffer
) {
2710 result
= ERROR_NOT_ENOUGH_MEMORY
;
2713 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
2714 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2716 /* Expand environment variables, if appropriate, or copy the original string over. */
2717 if (dwValueType
== REG_EXPAND_SZ
) {
2718 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
2719 if (!cbData
) goto cleanup
;
2720 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2721 if (!pwszExpandedBuffer
) {
2722 result
= ERROR_NOT_ENOUGH_MEMORY
;
2725 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
2727 pwszExpandedBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2728 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
2731 /* If the value references a resource based string, parse the value and load the string.
2732 * Else just copy over the original value. */
2733 result
= ERROR_SUCCESS
;
2734 if (*pwszExpandedBuffer
!= '@') { /* '@' is the prefix for resource based string entries. */
2735 lstrcpynW(pwszBuffer
, pwszExpandedBuffer
, cbBuffer
/ sizeof(WCHAR
));
2737 WCHAR
*pComma
= strrchrW(pwszExpandedBuffer
, ',');
2741 /* Format of the expanded value is 'path_to_dll,-resId' */
2742 if (!pComma
|| pComma
[1] != '-') {
2743 result
= ERROR_BADKEY
;
2747 uiStringId
= atoiW(pComma
+2);
2750 hModule
= LoadLibraryW(pwszExpandedBuffer
+ 1);
2751 if (!hModule
|| !load_string(hModule
, uiStringId
, pwszBuffer
, cbBuffer
/sizeof(WCHAR
)))
2752 result
= ERROR_BADKEY
;
2753 FreeLibrary(hModule
);
2757 HeapFree(GetProcessHeap(), 0, pwszTempBuffer
);
2758 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer
);
2762 /******************************************************************************
2763 * RegLoadMUIStringA [ADVAPI32.@]
2765 * See RegLoadMUIStringW
2767 LSTATUS WINAPI
RegLoadMUIStringA(HKEY hKey
, LPCSTR pszValue
, LPSTR pszBuffer
, DWORD cbBuffer
,
2768 LPDWORD pcbData
, DWORD dwFlags
, LPCSTR pszBaseDir
)
2770 UNICODE_STRING valueW
, baseDirW
;
2772 DWORD cbData
= cbBuffer
* sizeof(WCHAR
);
2775 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
2776 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
2777 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszBaseDir
) ||
2778 !(pwszBuffer
= HeapAlloc(GetProcessHeap(), 0, cbData
)))
2780 result
= ERROR_NOT_ENOUGH_MEMORY
;
2784 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, dwFlags
,
2787 if (result
== ERROR_SUCCESS
) {
2788 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszBuffer
, cbBuffer
, NULL
, NULL
);
2794 HeapFree(GetProcessHeap(), 0, pwszBuffer
);
2795 RtlFreeUnicodeString(&baseDirW
);
2796 RtlFreeUnicodeString(&valueW
);
2801 /******************************************************************************
2802 * RegDisablePredefinedCache [ADVAPI32.@]
2804 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2810 * Success: ERROR_SUCCESS
2811 * Failure: nonzero error code from Winerror.h
2814 * This is useful for services that use impersonation.
2816 LSTATUS WINAPI
RegDisablePredefinedCache(void)
2818 HKEY hkey_current_user
;
2819 int idx
= HandleToUlong(HKEY_CURRENT_USER
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
2821 /* prevent caching of future requests */
2822 hkcu_cache_disabled
= TRUE
;
2824 hkey_current_user
= InterlockedExchangePointer( (void **)&special_root_keys
[idx
], NULL
);
2826 if (hkey_current_user
)
2827 NtClose( hkey_current_user
);
2829 return ERROR_SUCCESS
;
2832 /******************************************************************************
2833 * RegDeleteTreeW [ADVAPI32.@]
2836 LSTATUS WINAPI
RegDeleteTreeW(HKEY hKey
, LPCWSTR lpszSubKey
)
2839 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
2840 DWORD dwMaxLen
, dwSize
;
2841 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
2842 HKEY hSubKey
= hKey
;
2844 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
2848 ret
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
2849 if (ret
) return ret
;
2852 /* Get highest length for keys, values */
2853 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
2854 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
2855 if (ret
) goto cleanup
;
2859 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
2860 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
2862 /* Name too big: alloc a buffer for it */
2863 if (!(lpszName
= HeapAlloc( GetProcessHeap(), 0, dwMaxLen
*sizeof(WCHAR
))))
2865 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2871 /* Recursively delete all the subkeys */
2875 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
2876 NULL
, NULL
, NULL
)) break;
2878 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
2879 if (ret
) goto cleanup
;
2883 ret
= RegDeleteKeyW(hKey
, lpszSubKey
);
2888 if (RegEnumValueW(hKey
, 0, lpszName
, &dwSize
,
2889 NULL
, NULL
, NULL
, NULL
)) break;
2891 ret
= RegDeleteValueW(hKey
, lpszName
);
2892 if (ret
) goto cleanup
;
2896 /* Free buffer if allocated */
2897 if (lpszName
!= szNameBuf
)
2898 HeapFree( GetProcessHeap(), 0, lpszName
);
2900 RegCloseKey(hSubKey
);
2904 /******************************************************************************
2905 * RegDeleteTreeA [ADVAPI32.@]
2908 LSTATUS WINAPI
RegDeleteTreeA(HKEY hKey
, LPCSTR lpszSubKey
)
2911 UNICODE_STRING lpszSubKeyW
;
2913 if (lpszSubKey
) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW
, lpszSubKey
);
2914 else lpszSubKeyW
.Buffer
= NULL
;
2915 ret
= RegDeleteTreeW( hKey
, lpszSubKeyW
.Buffer
);
2916 RtlFreeUnicodeString( &lpszSubKeyW
);
2920 /******************************************************************************
2921 * RegDisableReflectionKey [ADVAPI32.@]
2924 LONG WINAPI
RegDisableReflectionKey(HKEY base
)
2926 FIXME("%p: stub\n", base
);
2927 return ERROR_SUCCESS
;