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
38 #include "advapi32_misc.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
45 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
46 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
48 static const WCHAR name_CLASSES_ROOT
[] =
49 {'M','a','c','h','i','n','e','\\',
50 'S','o','f','t','w','a','r','e','\\',
51 'C','l','a','s','s','e','s',0};
52 static const WCHAR name_LOCAL_MACHINE
[] =
53 {'M','a','c','h','i','n','e',0};
54 static const WCHAR name_USERS
[] =
56 static const WCHAR name_PERFORMANCE_DATA
[] =
57 {'P','e','r','f','D','a','t','a',0};
58 static const WCHAR name_CURRENT_CONFIG
[] =
59 {'M','a','c','h','i','n','e','\\',
60 'S','y','s','t','e','m','\\',
61 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
62 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
63 'C','u','r','r','e','n','t',0};
64 static const WCHAR name_DYN_DATA
[] =
65 {'D','y','n','D','a','t','a',0};
67 static const WCHAR
* const root_key_names
[] =
70 NULL
, /* HKEY_CURRENT_USER is determined dynamically */
73 name_PERFORMANCE_DATA
,
78 #define NB_SPECIAL_ROOT_KEYS (sizeof(root_key_names)/sizeof(root_key_names[0]))
80 static HKEY special_root_keys
[NB_SPECIAL_ROOT_KEYS
];
81 static BOOL hkcu_cache_disabled
;
83 static const BOOL is_win64
= (sizeof(void *) > sizeof(int));
85 /* check if value type needs string conversion (Ansi<->Unicode) */
86 static inline BOOL
is_string( DWORD type
)
88 return (type
== REG_SZ
) || (type
== REG_EXPAND_SZ
) || (type
== REG_MULTI_SZ
);
91 /* check if current version is NT or Win95 */
92 static inline BOOL
is_version_nt(void)
94 return !(GetVersion() & 0x80000000);
97 static BOOL
is_wow6432node( const UNICODE_STRING
*name
)
99 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e'};
101 return (name
->Length
== sizeof(wow6432nodeW
) &&
102 !memicmpW( name
->Buffer
, wow6432nodeW
, sizeof(wow6432nodeW
)/sizeof(WCHAR
) ));
105 /* open the Wow6432Node subkey of the specified key */
106 static HANDLE
open_wow6432node( HANDLE key
)
108 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
109 OBJECT_ATTRIBUTES attr
;
110 UNICODE_STRING nameW
;
113 attr
.Length
= sizeof(attr
);
114 attr
.RootDirectory
= key
;
115 attr
.ObjectName
= &nameW
;
117 attr
.SecurityDescriptor
= NULL
;
118 attr
.SecurityQualityOfService
= NULL
;
119 RtlInitUnicodeString( &nameW
, wow6432nodeW
);
120 if (NtOpenKey( &ret
, MAXIMUM_ALLOWED
, &attr
)) ret
= 0;
124 /* wrapper for NtCreateKey that creates the key recursively if necessary */
125 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
126 const UNICODE_STRING
*class, ULONG options
, PULONG dispos
)
128 BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
129 NTSTATUS status
= STATUS_OBJECT_NAME_NOT_FOUND
;
130 HANDLE subkey
, root
= attr
->RootDirectory
;
132 if (!force_wow32
) status
= NtCreateKey( &subkey
, access
, attr
, 0, class, options
, dispos
);
134 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
136 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
137 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
140 while (i
< len
&& buffer
[i
] != '\\') i
++;
141 if (i
== len
&& !force_wow32
) return status
;
143 attrs
= attr
->Attributes
;
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
)))
155 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
156 attr
->RootDirectory
= subkey
;
162 attr
->Attributes
= attrs
;
163 status
= NtCreateKey( &subkey
, access
, attr
, 0, class, options
, dispos
);
167 attr
->Attributes
= attrs
& ~OBJ_OPENLINK
;
168 status
= NtCreateKey( &subkey
, access
, attr
, 0, class,
169 options
& ~REG_OPTION_CREATE_LINK
, dispos
);
171 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
172 if (status
) return status
;
174 attr
->RootDirectory
= subkey
;
175 while (i
< len
&& buffer
[i
] == '\\') i
++;
177 while (i
< len
&& buffer
[i
] != '\\') i
++;
180 attr
->RootDirectory
= subkey
;
181 if (force_wow32
&& (subkey
= open_wow6432node( attr
->RootDirectory
)))
183 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
184 attr
->RootDirectory
= subkey
;
186 *retkey
= attr
->RootDirectory
;
190 /* wrapper for NtOpenKey to handle Wow6432 nodes */
191 static NTSTATUS
open_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
194 BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
195 HANDLE subkey
, root
= attr
->RootDirectory
;
196 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
197 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
200 if (!force_wow32
) return NtOpenKey( (HANDLE
*)retkey
, access
, attr
);
202 if (len
&& buffer
[0] == '\\') return STATUS_OBJECT_PATH_INVALID
;
203 while (i
< len
&& buffer
[i
] != '\\') i
++;
204 attrs
= attr
->Attributes
;
205 attr
->ObjectName
= &str
;
209 str
.Buffer
= buffer
+ pos
;
210 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
211 if (force_wow32
&& pos
)
213 if (is_wow6432node( &str
)) force_wow32
= FALSE
;
214 else if ((subkey
= open_wow6432node( attr
->RootDirectory
)))
216 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
217 attr
->RootDirectory
= subkey
;
223 attr
->Attributes
= attrs
;
224 status
= NtOpenKey( &subkey
, access
, attr
);
228 attr
->Attributes
= attrs
& ~OBJ_OPENLINK
;
229 status
= NtOpenKey( &subkey
, access
, attr
);
231 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
232 if (status
) return status
;
233 attr
->RootDirectory
= subkey
;
235 while (i
< len
&& buffer
[i
] == '\\') i
++;
237 while (i
< len
&& buffer
[i
] != '\\') i
++;
239 if (force_wow32
&& (subkey
= open_wow6432node( attr
->RootDirectory
)))
241 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
242 attr
->RootDirectory
= subkey
;
244 *retkey
= attr
->RootDirectory
;
248 /* create one of the HKEY_* special root keys */
249 static HKEY
create_special_root_hkey( HKEY hkey
, DWORD access
)
252 int idx
= HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
254 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CURRENT_USER
))
256 if (RtlOpenCurrentUser( access
, (HANDLE
*)&hkey
)) return 0;
257 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey
);
259 /* don't cache the key in the table if caching is disabled */
260 if (hkcu_cache_disabled
)
265 OBJECT_ATTRIBUTES attr
;
268 attr
.Length
= sizeof(attr
);
269 attr
.RootDirectory
= 0;
270 attr
.ObjectName
= &name
;
272 attr
.SecurityDescriptor
= NULL
;
273 attr
.SecurityQualityOfService
= NULL
;
274 RtlInitUnicodeString( &name
, root_key_names
[idx
] );
275 if (create_key( &hkey
, access
, &attr
, NULL
, 0, NULL
)) return 0;
276 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
279 if (!(access
& (KEY_WOW64_64KEY
| KEY_WOW64_32KEY
)))
281 if (!(ret
= InterlockedCompareExchangePointer( (void **)&special_root_keys
[idx
], hkey
, 0 )))
284 NtClose( hkey
); /* somebody beat us to it */
291 /* map the hkey from special root to normal key if necessary */
292 static inline HKEY
get_special_root_hkey( HKEY hkey
, REGSAM access
)
296 if ((HandleToUlong(hkey
) >= HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
))
297 && (HandleToUlong(hkey
) <= HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
301 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
))
302 mask
= KEY_WOW64_32KEY
| KEY_WOW64_64KEY
;
304 if ((access
& mask
) ||
305 !(ret
= special_root_keys
[HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
)]))
306 ret
= create_special_root_hkey( hkey
, MAXIMUM_ALLOWED
| (access
& mask
) );
312 /******************************************************************************
313 * RegOverridePredefKey [ADVAPI32.@]
315 LSTATUS WINAPI
RegOverridePredefKey( HKEY hkey
, HKEY override
)
320 TRACE("(%p %p)\n", hkey
, override
);
322 if ((HandleToUlong(hkey
) < HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
))
323 || (HandleToUlong(hkey
) > HandleToUlong(HKEY_SPECIAL_ROOT_LAST
)))
324 return ERROR_INVALID_PARAMETER
;
325 idx
= HandleToUlong(hkey
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
329 NTSTATUS status
= NtDuplicateObject( GetCurrentProcess(), override
,
330 GetCurrentProcess(), (HANDLE
*)&override
,
331 0, 0, DUPLICATE_SAME_ACCESS
);
332 if (status
) return RtlNtStatusToDosError( status
);
335 old_key
= InterlockedExchangePointer( (void **)&special_root_keys
[idx
], override
);
336 if (old_key
) NtClose( old_key
);
337 return ERROR_SUCCESS
;
341 /******************************************************************************
342 * RegCreateKeyExW [ADVAPI32.@]
344 * See RegCreateKeyExA.
346 LSTATUS WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
, LPWSTR
class,
347 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
348 PHKEY retkey
, LPDWORD dispos
)
350 OBJECT_ATTRIBUTES attr
;
351 UNICODE_STRING nameW
, classW
;
353 if (reserved
) return ERROR_INVALID_PARAMETER
;
354 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
356 attr
.Length
= sizeof(attr
);
357 attr
.RootDirectory
= hkey
;
358 attr
.ObjectName
= &nameW
;
360 attr
.SecurityDescriptor
= NULL
;
361 attr
.SecurityQualityOfService
= NULL
;
362 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
363 RtlInitUnicodeString( &nameW
, name
);
364 RtlInitUnicodeString( &classW
, class );
366 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
, &classW
, options
, dispos
) );
370 /******************************************************************************
371 * RegCreateKeyExA [ADVAPI32.@]
373 * Open a registry key, creating it if it doesn't exist.
376 * hkey [I] Handle of the parent registry key
377 * name [I] Name of the new key to open or create
378 * reserved [I] Reserved, pass 0
379 * class [I] The object type of the new key
380 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
381 * access [I] Access level desired
382 * sa [I] Security attributes for the key
383 * retkey [O] Destination for the resulting handle
384 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
387 * Success: ERROR_SUCCESS.
388 * Failure: A standard Win32 error code. retkey remains untouched.
391 * MAXIMUM_ALLOWED in access mask not supported by server
393 LSTATUS WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, LPSTR
class,
394 DWORD options
, REGSAM access
, SECURITY_ATTRIBUTES
*sa
,
395 PHKEY retkey
, LPDWORD dispos
)
397 OBJECT_ATTRIBUTES attr
;
398 UNICODE_STRING classW
;
399 ANSI_STRING nameA
, classA
;
402 if (reserved
) return ERROR_INVALID_PARAMETER
;
403 if (!is_version_nt())
405 access
= MAXIMUM_ALLOWED
; /* Win95 ignores the access mask */
406 if (name
&& *name
== '\\') name
++; /* win9x,ME ignores one (and only one) beginning backslash */
408 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
410 attr
.Length
= sizeof(attr
);
411 attr
.RootDirectory
= hkey
;
412 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
414 attr
.SecurityDescriptor
= NULL
;
415 attr
.SecurityQualityOfService
= NULL
;
416 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
417 RtlInitAnsiString( &nameA
, name
);
418 RtlInitAnsiString( &classA
, class );
420 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
423 if (!(status
= RtlAnsiStringToUnicodeString( &classW
, &classA
, TRUE
)))
425 status
= create_key( retkey
, access
, &attr
, &classW
, options
, dispos
);
426 RtlFreeUnicodeString( &classW
);
429 return RtlNtStatusToDosError( status
);
433 /******************************************************************************
434 * RegCreateKeyW [ADVAPI32.@]
436 * Creates the specified reg key.
439 * hKey [I] Handle to an open key.
440 * lpSubKey [I] Name of a key that will be opened or created.
441 * phkResult [O] Receives a handle to the opened or created key.
444 * Success: ERROR_SUCCESS
445 * Failure: nonzero error code defined in Winerror.h
447 LSTATUS WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpSubKey
, PHKEY phkResult
)
449 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
450 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
451 return RegCreateKeyExW( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
452 MAXIMUM_ALLOWED
, NULL
, phkResult
, NULL
);
456 /******************************************************************************
457 * RegCreateKeyA [ADVAPI32.@]
461 LSTATUS WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpSubKey
, PHKEY phkResult
)
463 return RegCreateKeyExA( hkey
, lpSubKey
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
464 MAXIMUM_ALLOWED
, NULL
, phkResult
, NULL
);
469 /******************************************************************************
470 * RegOpenKeyExW [ADVAPI32.@]
474 LSTATUS WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR name
, DWORD options
, REGSAM access
, PHKEY retkey
)
476 OBJECT_ATTRIBUTES attr
;
477 UNICODE_STRING nameW
;
479 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
480 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
) && name
&& *name
== '\\') name
++;
482 if (!retkey
) return ERROR_INVALID_PARAMETER
;
483 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
485 attr
.Length
= sizeof(attr
);
486 attr
.RootDirectory
= hkey
;
487 attr
.ObjectName
= &nameW
;
489 attr
.SecurityDescriptor
= NULL
;
490 attr
.SecurityQualityOfService
= NULL
;
491 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
492 RtlInitUnicodeString( &nameW
, name
);
493 return RtlNtStatusToDosError( open_key( retkey
, access
, &attr
) );
497 /******************************************************************************
498 * RegOpenKeyExA [ADVAPI32.@]
500 * Open a registry key.
503 * hkey [I] Handle of open key
504 * name [I] Name of subkey to open
505 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
506 * access [I] Security access mask
507 * retkey [O] Handle to open key
510 * Success: ERROR_SUCCESS
511 * Failure: A standard Win32 error code. retkey is set to 0.
514 * Unlike RegCreateKeyExA(), this function will not create the key if it
517 LSTATUS WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR name
, DWORD options
, REGSAM access
, PHKEY retkey
)
519 OBJECT_ATTRIBUTES attr
;
523 if (!is_version_nt()) access
= MAXIMUM_ALLOWED
; /* Win95 ignores the access mask */
526 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
527 if (HandleToUlong(hkey
) == HandleToUlong(HKEY_CLASSES_ROOT
) && name
&& *name
== '\\') name
++;
530 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
532 attr
.Length
= sizeof(attr
);
533 attr
.RootDirectory
= hkey
;
534 attr
.ObjectName
= &NtCurrentTeb()->StaticUnicodeString
;
536 attr
.SecurityDescriptor
= NULL
;
537 attr
.SecurityQualityOfService
= NULL
;
538 if (options
& REG_OPTION_OPEN_LINK
) attr
.Attributes
|= OBJ_OPENLINK
;
540 RtlInitAnsiString( &nameA
, name
);
541 if (!(status
= RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString
,
544 status
= open_key( retkey
, access
, &attr
);
546 return RtlNtStatusToDosError( status
);
550 /******************************************************************************
551 * RegOpenKeyW [ADVAPI32.@]
555 LSTATUS WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR name
, PHKEY retkey
)
558 return ERROR_INVALID_PARAMETER
;
563 return ERROR_SUCCESS
;
565 return RegOpenKeyExW( hkey
, name
, 0, MAXIMUM_ALLOWED
, retkey
);
569 /******************************************************************************
570 * RegOpenKeyA [ADVAPI32.@]
572 * Open a registry key.
575 * hkey [I] Handle of parent key to open the new key under
576 * name [I] Name of the key under hkey to open
577 * retkey [O] Destination for the resulting Handle
580 * Success: ERROR_SUCCESS
581 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
583 LSTATUS WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR name
, PHKEY retkey
)
586 return ERROR_INVALID_PARAMETER
;
591 return ERROR_SUCCESS
;
593 return RegOpenKeyExA( hkey
, name
, 0, MAXIMUM_ALLOWED
, retkey
);
597 /******************************************************************************
598 * RegOpenCurrentUser [ADVAPI32.@]
600 * Get a handle to the HKEY_CURRENT_USER key for the user
601 * the current thread is impersonating.
604 * access [I] Desired access rights to the key
605 * retkey [O] Handle to the opened key
608 * Success: ERROR_SUCCESS
609 * Failure: nonzero error code from Winerror.h
612 * This function is supposed to retrieve a handle to the
613 * HKEY_CURRENT_USER for the user the current thread is impersonating.
614 * Since Wine does not currently allow threads to impersonate other users,
615 * this stub should work fine.
617 LSTATUS WINAPI
RegOpenCurrentUser( REGSAM access
, PHKEY retkey
)
619 return RegOpenKeyExA( HKEY_CURRENT_USER
, "", 0, access
, retkey
);
624 /******************************************************************************
625 * RegEnumKeyExW [ADVAPI32.@]
627 * Enumerate subkeys of the specified open registry key.
630 * hkey [I] Handle to key to enumerate
631 * index [I] Index of subkey to enumerate
632 * name [O] Buffer for subkey name
633 * name_len [O] Size of subkey buffer
634 * reserved [I] Reserved
635 * class [O] Buffer for class string
636 * class_len [O] Size of class buffer
637 * ft [O] Time key last written to
640 * Success: ERROR_SUCCESS
641 * Failure: System error code. If there are no more subkeys available, the
642 * function returns ERROR_NO_MORE_ITEMS.
644 LSTATUS WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD index
, LPWSTR name
, LPDWORD name_len
,
645 LPDWORD reserved
, LPWSTR
class, LPDWORD class_len
, FILETIME
*ft
)
648 char buffer
[256], *buf_ptr
= buffer
;
649 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
652 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
653 name_len
? *name_len
: 0, reserved
, class, class_len
, ft
);
655 if (reserved
) return ERROR_INVALID_PARAMETER
;
656 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
658 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
659 buffer
, sizeof(buffer
), &total_size
);
661 while (status
== STATUS_BUFFER_OVERFLOW
)
663 /* retry with a dynamically allocated buffer */
664 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
665 if (!(buf_ptr
= heap_alloc( total_size
)))
666 return ERROR_NOT_ENOUGH_MEMORY
;
667 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
668 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
669 buf_ptr
, total_size
, &total_size
);
674 DWORD len
= info
->NameLength
/ sizeof(WCHAR
);
675 DWORD cls_len
= info
->ClassLength
/ sizeof(WCHAR
);
677 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
679 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
680 status
= STATUS_BUFFER_OVERFLOW
;
684 memcpy( name
, info
->Name
, info
->NameLength
);
688 *class_len
= cls_len
;
691 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
698 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
699 return RtlNtStatusToDosError( status
);
703 /******************************************************************************
704 * RegEnumKeyExA [ADVAPI32.@]
708 LSTATUS WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD index
, LPSTR name
, LPDWORD name_len
,
709 LPDWORD reserved
, LPSTR
class, LPDWORD class_len
, FILETIME
*ft
)
712 char buffer
[256], *buf_ptr
= buffer
;
713 KEY_NODE_INFORMATION
*info
= (KEY_NODE_INFORMATION
*)buffer
;
716 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey
, index
, name
, name_len
,
717 name_len
? *name_len
: 0, reserved
, class, class_len
, ft
);
719 if (reserved
) return ERROR_INVALID_PARAMETER
;
720 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
722 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
723 buffer
, sizeof(buffer
), &total_size
);
725 while (status
== STATUS_BUFFER_OVERFLOW
)
727 /* retry with a dynamically allocated buffer */
728 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
729 if (!(buf_ptr
= heap_alloc( total_size
)))
730 return ERROR_NOT_ENOUGH_MEMORY
;
731 info
= (KEY_NODE_INFORMATION
*)buf_ptr
;
732 status
= NtEnumerateKey( hkey
, index
, KeyNodeInformation
,
733 buf_ptr
, total_size
, &total_size
);
740 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
741 RtlUnicodeToMultiByteSize( &cls_len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
743 if (ft
) *ft
= *(FILETIME
*)&info
->LastWriteTime
;
745 if (len
>= *name_len
|| (class && class_len
&& (cls_len
>= *class_len
)))
746 status
= STATUS_BUFFER_OVERFLOW
;
750 RtlUnicodeToMultiByteN( name
, len
, NULL
, info
->Name
, info
->NameLength
);
754 *class_len
= cls_len
;
757 RtlUnicodeToMultiByteN( class, cls_len
, NULL
,
758 (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
766 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
767 return RtlNtStatusToDosError( status
);
771 /******************************************************************************
772 * RegEnumKeyW [ADVAPI32.@]
774 * Enumerates subkeys of the specified open reg key.
777 * hKey [I] Handle to an open key.
778 * dwIndex [I] Index of the subkey of hKey to retrieve.
779 * lpName [O] Name of the subkey.
780 * cchName [I] Size of lpName in TCHARS.
783 * Success: ERROR_SUCCESS
784 * Failure: system error code. If there are no more subkeys available, the
785 * function returns ERROR_NO_MORE_ITEMS.
787 LSTATUS WINAPI
RegEnumKeyW( HKEY hkey
, DWORD index
, LPWSTR name
, DWORD name_len
)
789 return RegEnumKeyExW( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
793 /******************************************************************************
794 * RegEnumKeyA [ADVAPI32.@]
798 LSTATUS WINAPI
RegEnumKeyA( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
800 return RegEnumKeyExA( hkey
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
804 /******************************************************************************
805 * RegQueryInfoKeyW [ADVAPI32.@]
807 * Retrieves information about the specified registry key.
810 * hkey [I] Handle to key to query
811 * class [O] Buffer for class string
812 * class_len [O] Size of class string buffer
813 * reserved [I] Reserved
814 * subkeys [O] Buffer for number of subkeys
815 * max_subkey [O] Buffer for longest subkey name length
816 * max_class [O] Buffer for longest class string length
817 * values [O] Buffer for number of value entries
818 * max_value [O] Buffer for longest value name length
819 * max_data [O] Buffer for longest value data length
820 * security [O] Buffer for security descriptor length
821 * modif [O] Modification time
824 * Success: ERROR_SUCCESS
825 * Failure: system error code.
828 * - win95 allows class to be valid and class_len to be NULL
829 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
830 * - both allow class to be NULL and class_len to be NULL
831 * (it's hard to test validity, so test !NULL instead)
833 LSTATUS WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR
class, LPDWORD class_len
, LPDWORD reserved
,
834 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
835 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
836 LPDWORD security
, FILETIME
*modif
)
839 char buffer
[256], *buf_ptr
= buffer
;
840 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
843 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
844 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
846 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
847 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
849 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
850 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
854 /* retry with a dynamically allocated buffer */
855 while (status
== STATUS_BUFFER_OVERFLOW
)
857 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
858 if (!(buf_ptr
= heap_alloc( total_size
)))
859 return ERROR_NOT_ENOUGH_MEMORY
;
860 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
861 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
864 if (status
) goto done
;
866 if (class_len
&& (info
->ClassLength
/sizeof(WCHAR
) + 1 > *class_len
))
868 status
= STATUS_BUFFER_TOO_SMALL
;
872 memcpy( class, buf_ptr
+ info
->ClassOffset
, info
->ClassLength
);
873 class[info
->ClassLength
/sizeof(WCHAR
)] = 0;
876 else status
= STATUS_SUCCESS
;
878 if (class_len
) *class_len
= info
->ClassLength
/ sizeof(WCHAR
);
879 if (subkeys
) *subkeys
= info
->SubKeys
;
880 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
881 if (max_class
) *max_class
= info
->MaxClassLen
;
882 if (values
) *values
= info
->Values
;
883 if (max_value
) *max_value
= info
->MaxValueNameLen
;
884 if (max_data
) *max_data
= info
->MaxValueDataLen
;
885 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
888 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
889 return RtlNtStatusToDosError( status
);
893 /******************************************************************************
894 * RegQueryMultipleValuesA [ADVAPI32.@]
896 * Retrieves the type and data for a list of value names associated with a key.
899 * hKey [I] Handle to an open key.
900 * val_list [O] Array of VALENT structures that describes the entries.
901 * num_vals [I] Number of elements in val_list.
902 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
903 * ldwTotsize [I/O] Size of lpValueBuf.
906 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
907 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
910 LSTATUS WINAPI
RegQueryMultipleValuesA( HKEY hkey
, PVALENTA val_list
, DWORD num_vals
,
911 LPSTR lpValueBuf
, LPDWORD ldwTotsize
)
914 DWORD maxBytes
= *ldwTotsize
;
916 LPSTR bufptr
= lpValueBuf
;
919 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
921 for(i
=0; i
< num_vals
; ++i
)
924 val_list
[i
].ve_valuelen
=0;
925 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
926 if(status
!= ERROR_SUCCESS
)
931 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
933 status
= RegQueryValueExA(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
934 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
935 if(status
!= ERROR_SUCCESS
)
940 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
942 bufptr
+= val_list
[i
].ve_valuelen
;
945 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
947 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
951 /******************************************************************************
952 * RegQueryMultipleValuesW [ADVAPI32.@]
954 * See RegQueryMultipleValuesA.
956 LSTATUS WINAPI
RegQueryMultipleValuesW( HKEY hkey
, PVALENTW val_list
, DWORD num_vals
,
957 LPWSTR lpValueBuf
, LPDWORD ldwTotsize
)
960 DWORD maxBytes
= *ldwTotsize
;
962 LPSTR bufptr
= (LPSTR
)lpValueBuf
;
965 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey
, val_list
, num_vals
, lpValueBuf
, ldwTotsize
, *ldwTotsize
);
967 for(i
=0; i
< num_vals
; ++i
)
969 val_list
[i
].ve_valuelen
=0;
970 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, NULL
, NULL
, &val_list
[i
].ve_valuelen
);
971 if(status
!= ERROR_SUCCESS
)
976 if(lpValueBuf
!= NULL
&& *ldwTotsize
+ val_list
[i
].ve_valuelen
<= maxBytes
)
978 status
= RegQueryValueExW(hkey
, val_list
[i
].ve_valuename
, NULL
, &val_list
[i
].ve_type
,
979 (LPBYTE
)bufptr
, &val_list
[i
].ve_valuelen
);
980 if(status
!= ERROR_SUCCESS
)
985 val_list
[i
].ve_valueptr
= (DWORD_PTR
)bufptr
;
987 bufptr
+= val_list
[i
].ve_valuelen
;
990 *ldwTotsize
+= val_list
[i
].ve_valuelen
;
992 return lpValueBuf
!= NULL
&& *ldwTotsize
<= maxBytes
? ERROR_SUCCESS
: ERROR_MORE_DATA
;
995 /******************************************************************************
996 * RegQueryInfoKeyA [ADVAPI32.@]
998 * Retrieves information about a registry key.
1001 * hKey [I] Handle to an open key.
1002 * lpClass [O] Class string of the key.
1003 * lpcClass [I/O] size of lpClass.
1004 * lpReserved [I] Reserved; must be NULL.
1005 * lpcSubKeys [O] Number of subkeys contained by the key.
1006 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
1007 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
1009 * lpcValues [O] Number of values associated with the key.
1010 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
1011 * lpcMaxValueLen [O] Longest data component among the key's values
1012 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
1013 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
1016 * Success: ERROR_SUCCESS
1017 * Failure: nonzero error code from Winerror.h
1019 LSTATUS WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR
class, LPDWORD class_len
, LPDWORD reserved
,
1020 LPDWORD subkeys
, LPDWORD max_subkey
, LPDWORD max_class
,
1021 LPDWORD values
, LPDWORD max_value
, LPDWORD max_data
,
1022 LPDWORD security
, FILETIME
*modif
)
1025 char buffer
[256], *buf_ptr
= buffer
;
1026 KEY_FULL_INFORMATION
*info
= (KEY_FULL_INFORMATION
*)buffer
;
1027 DWORD total_size
, len
;
1029 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey
, class, class_len
? *class_len
: 0,
1030 reserved
, subkeys
, max_subkey
, values
, max_value
, max_data
, security
, modif
);
1032 if (class && !class_len
&& is_version_nt()) return ERROR_INVALID_PARAMETER
;
1033 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1035 status
= NtQueryKey( hkey
, KeyFullInformation
, buffer
, sizeof(buffer
), &total_size
);
1036 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1038 if (class || class_len
)
1040 /* retry with a dynamically allocated buffer */
1041 while (status
== STATUS_BUFFER_OVERFLOW
)
1043 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1044 if (!(buf_ptr
= heap_alloc( total_size
)))
1045 return ERROR_NOT_ENOUGH_MEMORY
;
1046 info
= (KEY_FULL_INFORMATION
*)buf_ptr
;
1047 status
= NtQueryKey( hkey
, KeyFullInformation
, buf_ptr
, total_size
, &total_size
);
1050 if (status
) goto done
;
1052 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
), info
->ClassLength
);
1055 if (len
+ 1 > *class_len
) status
= STATUS_BUFFER_OVERFLOW
;
1058 if (class && !status
)
1060 RtlUnicodeToMultiByteN( class, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->ClassOffset
),
1061 info
->ClassLength
);
1065 else status
= STATUS_SUCCESS
;
1067 if (subkeys
) *subkeys
= info
->SubKeys
;
1068 if (max_subkey
) *max_subkey
= info
->MaxNameLen
;
1069 if (max_class
) *max_class
= info
->MaxClassLen
;
1070 if (values
) *values
= info
->Values
;
1071 if (max_value
) *max_value
= info
->MaxValueNameLen
;
1072 if (max_data
) *max_data
= info
->MaxValueDataLen
;
1073 if (modif
) *modif
= *(FILETIME
*)&info
->LastWriteTime
;
1076 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1077 return RtlNtStatusToDosError( status
);
1081 /******************************************************************************
1082 * RegCloseKey [ADVAPI32.@]
1084 * Close an open registry key.
1087 * hkey [I] Handle of key to close
1090 * Success: ERROR_SUCCESS
1091 * Failure: Error code
1093 LSTATUS WINAPI
RegCloseKey( HKEY hkey
)
1095 if (!hkey
) return ERROR_INVALID_HANDLE
;
1096 if (hkey
>= (HKEY
)0x80000000) return ERROR_SUCCESS
;
1097 return RtlNtStatusToDosError( NtClose( hkey
) );
1101 /******************************************************************************
1102 * RegDeleteKeyExW [ADVAPI32.@]
1104 LSTATUS WINAPI
RegDeleteKeyExW( HKEY hkey
, LPCWSTR name
, REGSAM access
, DWORD reserved
)
1109 if (!name
) return ERROR_INVALID_PARAMETER
;
1111 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
1113 access
&= KEY_WOW64_64KEY
| KEY_WOW64_32KEY
;
1114 if (!(ret
= RegOpenKeyExW( hkey
, name
, 0, access
| DELETE
, &tmp
)))
1116 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
1119 TRACE("%s ret=%08x\n", debugstr_w(name
), ret
);
1124 /******************************************************************************
1125 * RegDeleteKeyW [ADVAPI32.@]
1127 * See RegDeleteKeyA.
1129 LSTATUS WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR name
)
1131 return RegDeleteKeyExW( hkey
, name
, 0, 0 );
1135 /******************************************************************************
1136 * RegDeleteKeyExA [ADVAPI32.@]
1138 LSTATUS WINAPI
RegDeleteKeyExA( HKEY hkey
, LPCSTR name
, REGSAM access
, DWORD reserved
)
1143 if (!name
) return ERROR_INVALID_PARAMETER
;
1145 if (!(hkey
= get_special_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
1147 access
&= KEY_WOW64_64KEY
| KEY_WOW64_32KEY
;
1148 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, access
| DELETE
, &tmp
)))
1150 if (!is_version_nt()) /* win95 does recursive key deletes */
1154 while(!RegEnumKeyA(tmp
, 0, sub
, sizeof(sub
)))
1156 if(RegDeleteKeyExA(tmp
, sub
, access
, reserved
)) /* recurse */
1160 ret
= RtlNtStatusToDosError( NtDeleteKey( tmp
) );
1163 TRACE("%s ret=%08x\n", debugstr_a(name
), ret
);
1168 /******************************************************************************
1169 * RegDeleteKeyA [ADVAPI32.@]
1171 * Delete a registry key.
1174 * hkey [I] Handle to parent key containing the key to delete
1175 * name [I] Name of the key user hkey to delete
1179 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1180 * right. In reality, it opens a new handle with DELETE access.
1183 * Success: ERROR_SUCCESS
1184 * Failure: Error code
1186 LSTATUS WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR name
)
1188 return RegDeleteKeyExA( hkey
, name
, 0, 0 );
1193 /******************************************************************************
1194 * RegSetValueExW [ADVAPI32.@]
1196 * Set the data and contents of a registry value.
1199 * hkey [I] Handle of key to set value for
1200 * name [I] Name of value to set
1201 * reserved [I] Reserved, must be zero
1202 * type [I] Type of the value being set
1203 * data [I] The new contents of the value to set
1204 * count [I] Size of data
1207 * Success: ERROR_SUCCESS
1208 * Failure: Error code
1210 LSTATUS WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR name
, DWORD reserved
,
1211 DWORD type
, const BYTE
*data
, DWORD count
)
1213 UNICODE_STRING nameW
;
1215 /* no need for version check, not implemented on win9x anyway */
1217 if ((data
&& ((ULONG_PTR
)data
>> 16) == 0) || (!data
&& count
)) return ERROR_NOACCESS
;
1219 if (count
&& is_string(type
))
1221 LPCWSTR str
= (LPCWSTR
)data
;
1222 /* if user forgot to count terminating null, add it (yes NT does this) */
1223 if (str
[count
/ sizeof(WCHAR
) - 1] && !str
[count
/ sizeof(WCHAR
)])
1224 count
+= sizeof(WCHAR
);
1226 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1228 RtlInitUnicodeString( &nameW
, name
);
1229 return RtlNtStatusToDosError( NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
) );
1233 /******************************************************************************
1234 * RegSetValueExA [ADVAPI32.@]
1236 * See RegSetValueExW.
1239 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1240 * NT does definitely care (aj)
1242 LSTATUS WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1243 const BYTE
*data
, DWORD count
)
1246 UNICODE_STRING nameW
;
1247 WCHAR
*dataW
= NULL
;
1250 if (!is_version_nt()) /* win95 */
1254 if (!data
) return ERROR_INVALID_PARAMETER
;
1255 count
= strlen((const char *)data
) + 1;
1258 else if (count
&& is_string(type
))
1260 /* if user forgot to count terminating null, add it (yes NT does this) */
1261 if (data
[count
-1] && !data
[count
]) count
++;
1264 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1266 if (is_string( type
)) /* need to convert to Unicode */
1269 RtlMultiByteToUnicodeSize( &lenW
, (const char *)data
, count
);
1270 if (!(dataW
= heap_alloc( lenW
))) return ERROR_OUTOFMEMORY
;
1271 RtlMultiByteToUnicodeN( dataW
, lenW
, NULL
, (const char *)data
, count
);
1273 data
= (BYTE
*)dataW
;
1276 RtlInitAnsiString( &nameA
, name
);
1277 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1279 status
= NtSetValueKey( hkey
, &nameW
, 0, type
, data
, count
);
1280 RtlFreeUnicodeString( &nameW
);
1283 return RtlNtStatusToDosError( status
);
1287 /******************************************************************************
1288 * RegSetValueW [ADVAPI32.@]
1290 * Sets the data for the default or unnamed value of a reg key.
1293 * hkey [I] Handle to an open key.
1294 * subkey [I] Name of a subkey of hKey.
1295 * type [I] Type of information to store.
1296 * data [I] String that contains the data to set for the default value.
1297 * count [I] Ignored.
1300 * Success: ERROR_SUCCESS
1301 * Failure: nonzero error code from Winerror.h
1303 LSTATUS WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR subkey
, DWORD type
, LPCWSTR data
, DWORD count
)
1305 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_w(subkey
), type
, debugstr_w(data
), count
);
1307 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1309 return RegSetKeyValueW( hkey
, subkey
, NULL
, type
, data
, (strlenW(data
) + 1)*sizeof(WCHAR
) );
1312 /******************************************************************************
1313 * RegSetValueA [ADVAPI32.@]
1317 LSTATUS WINAPI
RegSetValueA( HKEY hkey
, LPCSTR subkey
, DWORD type
, LPCSTR data
, DWORD count
)
1319 TRACE("(%p,%s,%d,%s,%d)\n", hkey
, debugstr_a(subkey
), type
, debugstr_a(data
), count
);
1321 if (type
!= REG_SZ
|| !data
) return ERROR_INVALID_PARAMETER
;
1323 return RegSetKeyValueA( hkey
, subkey
, NULL
, type
, data
, strlen(data
) + 1 );
1326 /******************************************************************************
1327 * RegSetKeyValueW [ADVAPI32.@]
1329 LONG WINAPI
RegSetKeyValueW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR name
, DWORD type
, const void *data
, DWORD len
)
1331 HKEY hsubkey
= NULL
;
1334 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey
, debugstr_w(subkey
), debugstr_w(name
), type
, data
, len
);
1336 if (subkey
&& subkey
[0]) /* need to create the subkey */
1338 if ((ret
= RegCreateKeyW( hkey
, subkey
, &hsubkey
)) != ERROR_SUCCESS
) return ret
;
1342 ret
= RegSetValueExW( hkey
, name
, 0, type
, (const BYTE
*)data
, len
);
1343 if (hsubkey
) RegCloseKey( hsubkey
);
1347 /******************************************************************************
1348 * RegSetKeyValueA [ADVAPI32.@]
1350 LONG WINAPI
RegSetKeyValueA( HKEY hkey
, LPCSTR subkey
, LPCSTR name
, DWORD type
, const void *data
, DWORD len
)
1352 HKEY hsubkey
= NULL
;
1355 TRACE("(%p,%s,%s,%d,%p,%d)\n", hkey
, debugstr_a(subkey
), debugstr_a(name
), type
, data
, len
);
1357 if (subkey
&& subkey
[0]) /* need to create the subkey */
1359 if ((ret
= RegCreateKeyA( hkey
, subkey
, &hsubkey
)) != ERROR_SUCCESS
) return ret
;
1363 ret
= RegSetValueExA( hkey
, name
, 0, type
, (const BYTE
*)data
, len
);
1364 if (hsubkey
) RegCloseKey( hsubkey
);
1368 /******************************************************************************
1369 * RegQueryValueExW [ADVAPI32.@]
1371 * See RegQueryValueExA.
1373 LSTATUS WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR name
, LPDWORD reserved
, LPDWORD type
,
1374 LPBYTE data
, LPDWORD count
)
1377 UNICODE_STRING name_str
;
1379 char buffer
[256], *buf_ptr
= buffer
;
1380 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1381 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1383 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1384 hkey
, debugstr_w(name
), reserved
, type
, data
, count
,
1385 (count
&& data
) ? *count
: 0 );
1387 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1388 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1390 RtlInitUnicodeString( &name_str
, name
);
1392 if (data
) total_size
= min( sizeof(buffer
), *count
+ info_size
);
1395 total_size
= info_size
;
1396 if (count
) *count
= 0;
1399 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1400 buffer
, total_size
, &total_size
);
1401 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1405 /* retry with a dynamically allocated buffer */
1406 while (status
== STATUS_BUFFER_OVERFLOW
&& total_size
- info_size
<= *count
)
1408 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1409 if (!(buf_ptr
= heap_alloc( total_size
)))
1410 return ERROR_NOT_ENOUGH_MEMORY
;
1411 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1412 status
= NtQueryValueKey( hkey
, &name_str
, KeyValuePartialInformation
,
1413 buf_ptr
, total_size
, &total_size
);
1418 memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1419 /* if the type is REG_SZ and data is not 0-terminated
1420 * and there is enough space in the buffer NT appends a \0 */
1421 if (total_size
- info_size
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1423 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info_size
);
1424 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1427 else if (status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1429 else status
= STATUS_SUCCESS
;
1431 if (type
) *type
= info
->Type
;
1432 if (count
) *count
= total_size
- info_size
;
1435 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1436 return RtlNtStatusToDosError(status
);
1440 /******************************************************************************
1441 * RegQueryValueExA [ADVAPI32.@]
1443 * Get the type and contents of a specified value under with a key.
1446 * hkey [I] Handle of the key to query
1447 * name [I] Name of value under hkey to query
1448 * reserved [I] Reserved - must be NULL
1449 * type [O] Destination for the value type, or NULL if not required
1450 * data [O] Destination for the values contents, or NULL if not required
1451 * count [I/O] Size of data, updated with the number of bytes returned
1454 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1455 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1456 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1457 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1460 * MSDN states that if data is too small it is partially filled. In reality
1461 * it remains untouched.
1463 LSTATUS WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1464 LPBYTE data
, LPDWORD count
)
1468 UNICODE_STRING nameW
;
1469 DWORD total_size
, datalen
= 0;
1470 char buffer
[256], *buf_ptr
= buffer
;
1471 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1472 static const int info_size
= offsetof( KEY_VALUE_PARTIAL_INFORMATION
, Data
);
1474 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1475 hkey
, debugstr_a(name
), reserved
, type
, data
, count
, count
? *count
: 0 );
1477 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1478 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1480 if (count
) datalen
= *count
;
1481 if (!data
&& count
) *count
= 0;
1483 /* this matches Win9x behaviour - NT sets *type to a random value */
1484 if (type
) *type
= REG_NONE
;
1486 RtlInitAnsiString( &nameA
, name
);
1487 if ((status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
1488 return RtlNtStatusToDosError(status
);
1490 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1491 buffer
, sizeof(buffer
), &total_size
);
1492 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1494 /* we need to fetch the contents for a string type even if not requested,
1495 * because we need to compute the length of the ASCII string. */
1496 if (data
|| is_string(info
->Type
))
1498 /* retry with a dynamically allocated buffer */
1499 while (status
== STATUS_BUFFER_OVERFLOW
)
1501 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1502 if (!(buf_ptr
= heap_alloc( total_size
)))
1504 status
= STATUS_NO_MEMORY
;
1507 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buf_ptr
;
1508 status
= NtQueryValueKey( hkey
, &nameW
, KeyValuePartialInformation
,
1509 buf_ptr
, total_size
, &total_size
);
1512 if (status
) goto done
;
1514 if (is_string(info
->Type
))
1518 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info_size
),
1519 total_size
- info_size
);
1522 if (len
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1525 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info_size
),
1526 total_size
- info_size
);
1527 /* if the type is REG_SZ and data is not 0-terminated
1528 * and there is enough space in the buffer NT appends a \0 */
1529 if (len
< datalen
&& data
[len
-1]) data
[len
] = 0;
1532 total_size
= len
+ info_size
;
1536 if (total_size
- info_size
> datalen
) status
= STATUS_BUFFER_OVERFLOW
;
1537 else memcpy( data
, buf_ptr
+ info_size
, total_size
- info_size
);
1540 else status
= STATUS_SUCCESS
;
1542 if (type
) *type
= info
->Type
;
1543 if (count
) *count
= total_size
- info_size
;
1546 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1547 RtlFreeUnicodeString( &nameW
);
1548 return RtlNtStatusToDosError(status
);
1552 /******************************************************************************
1553 * RegQueryValueW [ADVAPI32.@]
1555 * Retrieves the data associated with the default or unnamed value of a key.
1558 * hkey [I] Handle to an open key.
1559 * name [I] Name of the subkey of hKey.
1560 * data [O] Receives the string associated with the default value
1562 * count [I/O] Size of lpValue in bytes.
1565 * Success: ERROR_SUCCESS
1566 * Failure: nonzero error code from Winerror.h
1568 LSTATUS WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR name
, LPWSTR data
, LPLONG count
)
1573 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_w(name
), data
, count
? *count
: 0 );
1575 if (name
&& name
[0])
1577 if ((ret
= RegOpenKeyW( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1579 ret
= RegQueryValueExW( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1580 if (subkey
!= hkey
) RegCloseKey( subkey
);
1581 if (ret
== ERROR_FILE_NOT_FOUND
)
1583 /* return empty string if default value not found */
1584 if (data
) *data
= 0;
1585 if (count
) *count
= sizeof(WCHAR
);
1586 ret
= ERROR_SUCCESS
;
1592 /******************************************************************************
1593 * RegQueryValueA [ADVAPI32.@]
1595 * See RegQueryValueW.
1597 LSTATUS WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR name
, LPSTR data
, LPLONG count
)
1602 TRACE("(%p,%s,%p,%d)\n", hkey
, debugstr_a(name
), data
, count
? *count
: 0 );
1604 if (name
&& name
[0])
1606 if ((ret
= RegOpenKeyA( hkey
, name
, &subkey
)) != ERROR_SUCCESS
) return ret
;
1608 ret
= RegQueryValueExA( subkey
, NULL
, NULL
, NULL
, (LPBYTE
)data
, (LPDWORD
)count
);
1609 if (subkey
!= hkey
) RegCloseKey( subkey
);
1610 if (ret
== ERROR_FILE_NOT_FOUND
)
1612 /* return empty string if default value not found */
1613 if (data
) *data
= 0;
1614 if (count
) *count
= 1;
1615 ret
= ERROR_SUCCESS
;
1621 /******************************************************************************
1622 * ADVAPI_ApplyRestrictions [internal]
1624 * Helper function for RegGetValueA/W.
1626 static VOID
ADVAPI_ApplyRestrictions( DWORD dwFlags
, DWORD dwType
,
1627 DWORD cbData
, PLONG ret
)
1629 /* Check if the type is restricted by the passed flags */
1630 if (*ret
== ERROR_SUCCESS
|| *ret
== ERROR_MORE_DATA
)
1636 case REG_NONE
: dwMask
= RRF_RT_REG_NONE
; break;
1637 case REG_SZ
: dwMask
= RRF_RT_REG_SZ
; break;
1638 case REG_EXPAND_SZ
: dwMask
= RRF_RT_REG_EXPAND_SZ
; break;
1639 case REG_MULTI_SZ
: dwMask
= RRF_RT_REG_MULTI_SZ
; break;
1640 case REG_BINARY
: dwMask
= RRF_RT_REG_BINARY
; break;
1641 case REG_DWORD
: dwMask
= RRF_RT_REG_DWORD
; break;
1642 case REG_QWORD
: dwMask
= RRF_RT_REG_QWORD
; break;
1645 if (dwFlags
& dwMask
)
1647 /* Type is not restricted, check for size mismatch */
1648 if (dwType
== REG_BINARY
)
1652 if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_DWORD
)
1654 else if ((dwFlags
& RRF_RT_ANY
) == RRF_RT_QWORD
)
1657 if (cbExpect
&& cbData
!= cbExpect
)
1658 *ret
= ERROR_DATATYPE_MISMATCH
;
1661 else *ret
= ERROR_UNSUPPORTED_TYPE
;
1666 /******************************************************************************
1667 * RegGetValueW [ADVAPI32.@]
1669 * Retrieves the type and data for a value name associated with a key,
1670 * optionally expanding its content and restricting its type.
1673 * hKey [I] Handle to an open key.
1674 * pszSubKey [I] Name of the subkey of hKey.
1675 * pszValue [I] Name of value under hKey/szSubKey to query.
1676 * dwFlags [I] Flags restricting the value type to retrieve.
1677 * pdwType [O] Destination for the values type, may be NULL.
1678 * pvData [O] Destination for the values content, may be NULL.
1679 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1680 * retrieve the whole content, including the trailing '\0'
1684 * Success: ERROR_SUCCESS
1685 * Failure: nonzero error code from Winerror.h
1688 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1689 * expanded and pdwType is set to REG_SZ instead.
1690 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1691 * without RRF_NOEXPAND is thus not allowed.
1692 * An exception is the case where RRF_RT_ANY is specified, because then
1693 * RRF_NOEXPAND is allowed.
1695 LSTATUS WINAPI
RegGetValueW( HKEY hKey
, LPCWSTR pszSubKey
, LPCWSTR pszValue
,
1696 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1699 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1703 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1704 hKey
, debugstr_w(pszSubKey
), debugstr_w(pszValue
), dwFlags
, pdwType
,
1705 pvData
, pcbData
, cbData
);
1707 if (pvData
&& !pcbData
)
1708 return ERROR_INVALID_PARAMETER
;
1709 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1710 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1711 return ERROR_INVALID_PARAMETER
;
1713 if (pszSubKey
&& pszSubKey
[0])
1715 ret
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1716 if (ret
!= ERROR_SUCCESS
) return ret
;
1719 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1721 /* If we are going to expand we need to read in the whole the value even
1722 * if the passed buffer was too small as the expanded string might be
1723 * smaller than the unexpanded one and could fit into cbData bytes. */
1724 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1725 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1730 pvBuf
= heap_alloc(cbData
);
1733 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1737 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1738 ret
= RegQueryValueExW(hKey
, pszValue
, NULL
,
1739 &dwType
, pvBuf
, &cbData
);
1742 /* Even if cbData was large enough we have to copy the
1743 * string since ExpandEnvironmentStrings can't handle
1744 * overlapping buffers. */
1745 CopyMemory(pvBuf
, pvData
, cbData
);
1748 /* Both the type or the value itself could have been modified in
1749 * between so we have to keep retrying until the buffer is large
1750 * enough or we no longer have to expand the value. */
1751 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1753 if (ret
== ERROR_SUCCESS
)
1755 /* Recheck dwType in case it changed since the first call */
1756 if (dwType
== REG_EXPAND_SZ
)
1758 cbData
= ExpandEnvironmentStringsW(pvBuf
, pvData
,
1759 pcbData
? *pcbData
: 0) * sizeof(WCHAR
);
1761 if(pvData
&& pcbData
&& cbData
> *pcbData
)
1762 ret
= ERROR_MORE_DATA
;
1765 CopyMemory(pvData
, pvBuf
, *pcbData
);
1771 if (pszSubKey
&& pszSubKey
[0])
1774 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1776 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1777 ZeroMemory(pvData
, *pcbData
);
1779 if (pdwType
) *pdwType
= dwType
;
1780 if (pcbData
) *pcbData
= cbData
;
1786 /******************************************************************************
1787 * RegGetValueA [ADVAPI32.@]
1791 LSTATUS WINAPI
RegGetValueA( HKEY hKey
, LPCSTR pszSubKey
, LPCSTR pszValue
,
1792 DWORD dwFlags
, LPDWORD pdwType
, PVOID pvData
,
1795 DWORD dwType
, cbData
= pcbData
? *pcbData
: 0;
1799 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
1800 hKey
, debugstr_a(pszSubKey
), debugstr_a(pszValue
), dwFlags
,
1801 pdwType
, pvData
, pcbData
, cbData
);
1803 if (pvData
&& !pcbData
)
1804 return ERROR_INVALID_PARAMETER
;
1805 if ((dwFlags
& RRF_RT_REG_EXPAND_SZ
) && !(dwFlags
& RRF_NOEXPAND
) &&
1806 ((dwFlags
& RRF_RT_ANY
) != RRF_RT_ANY
))
1807 return ERROR_INVALID_PARAMETER
;
1809 if (pszSubKey
&& pszSubKey
[0])
1811 ret
= RegOpenKeyExA(hKey
, pszSubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1812 if (ret
!= ERROR_SUCCESS
) return ret
;
1815 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
, &dwType
, pvData
, &cbData
);
1817 /* If we are going to expand we need to read in the whole the value even
1818 * if the passed buffer was too small as the expanded string might be
1819 * smaller than the unexpanded one and could fit into cbData bytes. */
1820 if ((ret
== ERROR_SUCCESS
|| ret
== ERROR_MORE_DATA
) &&
1821 dwType
== REG_EXPAND_SZ
&& !(dwFlags
& RRF_NOEXPAND
))
1826 pvBuf
= heap_alloc(cbData
);
1829 ret
= ERROR_NOT_ENOUGH_MEMORY
;
1833 if (ret
== ERROR_MORE_DATA
|| !pvData
)
1834 ret
= RegQueryValueExA(hKey
, pszValue
, NULL
,
1835 &dwType
, pvBuf
, &cbData
);
1838 /* Even if cbData was large enough we have to copy the
1839 * string since ExpandEnvironmentStrings can't handle
1840 * overlapping buffers. */
1841 CopyMemory(pvBuf
, pvData
, cbData
);
1844 /* Both the type or the value itself could have been modified in
1845 * between so we have to keep retrying until the buffer is large
1846 * enough or we no longer have to expand the value. */
1847 } while (dwType
== REG_EXPAND_SZ
&& ret
== ERROR_MORE_DATA
);
1849 if (ret
== ERROR_SUCCESS
)
1851 /* Recheck dwType in case it changed since the first call */
1852 if (dwType
== REG_EXPAND_SZ
)
1854 cbData
= ExpandEnvironmentStringsA(pvBuf
, pvData
,
1855 pcbData
? *pcbData
: 0);
1857 if(pvData
&& pcbData
&& cbData
> *pcbData
)
1858 ret
= ERROR_MORE_DATA
;
1861 CopyMemory(pvData
, pvBuf
, *pcbData
);
1867 if (pszSubKey
&& pszSubKey
[0])
1870 ADVAPI_ApplyRestrictions(dwFlags
, dwType
, cbData
, &ret
);
1872 if (pvData
&& ret
!= ERROR_SUCCESS
&& (dwFlags
& RRF_ZEROONFAILURE
))
1873 ZeroMemory(pvData
, *pcbData
);
1875 if (pdwType
) *pdwType
= dwType
;
1876 if (pcbData
) *pcbData
= cbData
;
1882 /******************************************************************************
1883 * RegEnumValueW [ADVAPI32.@]
1885 * Enumerates the values for the specified open registry key.
1888 * hkey [I] Handle to key to query
1889 * index [I] Index of value to query
1890 * value [O] Value string
1891 * val_count [I/O] Size of value buffer (in wchars)
1892 * reserved [I] Reserved
1893 * type [O] Type code
1894 * data [O] Value data
1895 * count [I/O] Size of data buffer (in bytes)
1898 * Success: ERROR_SUCCESS
1899 * Failure: nonzero error code from Winerror.h
1902 LSTATUS WINAPI
RegEnumValueW( HKEY hkey
, DWORD index
, LPWSTR value
, LPDWORD val_count
,
1903 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1907 char buffer
[256], *buf_ptr
= buffer
;
1908 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1909 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1911 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1912 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1914 /* NT only checks count, not val_count */
1915 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
1916 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
1918 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
1919 if (data
) total_size
+= *count
;
1920 total_size
= min( sizeof(buffer
), total_size
);
1922 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1923 buffer
, total_size
, &total_size
);
1924 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
1928 /* retry with a dynamically allocated buffer */
1929 while (status
== STATUS_BUFFER_OVERFLOW
)
1931 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1932 if (!(buf_ptr
= heap_alloc( total_size
)))
1933 return ERROR_NOT_ENOUGH_MEMORY
;
1934 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
1935 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
1936 buf_ptr
, total_size
, &total_size
);
1939 if (status
) goto done
;
1943 if (info
->NameLength
/sizeof(WCHAR
) >= *val_count
)
1945 status
= STATUS_BUFFER_OVERFLOW
;
1948 memcpy( value
, info
->Name
, info
->NameLength
);
1949 *val_count
= info
->NameLength
/ sizeof(WCHAR
);
1950 value
[*val_count
] = 0;
1955 if (total_size
- info
->DataOffset
> *count
)
1957 status
= STATUS_BUFFER_OVERFLOW
;
1960 memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
1961 if (total_size
- info
->DataOffset
<= *count
-sizeof(WCHAR
) && is_string(info
->Type
))
1963 /* if the type is REG_SZ and data is not 0-terminated
1964 * and there is enough space in the buffer NT appends a \0 */
1965 WCHAR
*ptr
= (WCHAR
*)(data
+ total_size
- info
->DataOffset
);
1966 if (ptr
> (WCHAR
*)data
&& ptr
[-1]) *ptr
= 0;
1970 else status
= STATUS_SUCCESS
;
1973 if (type
) *type
= info
->Type
;
1974 if (count
) *count
= info
->DataLength
;
1977 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
1978 return RtlNtStatusToDosError(status
);
1982 /******************************************************************************
1983 * RegEnumValueA [ADVAPI32.@]
1985 * See RegEnumValueW.
1987 LSTATUS WINAPI
RegEnumValueA( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1988 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1992 char buffer
[256], *buf_ptr
= buffer
;
1993 KEY_VALUE_FULL_INFORMATION
*info
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
1994 static const int info_size
= offsetof( KEY_VALUE_FULL_INFORMATION
, Name
);
1996 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1997 hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1999 /* NT only checks count, not val_count */
2000 if ((data
&& !count
) || reserved
) return ERROR_INVALID_PARAMETER
;
2001 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2003 total_size
= info_size
+ (MAX_PATH
+ 1) * sizeof(WCHAR
);
2004 if (data
) total_size
+= *count
;
2005 total_size
= min( sizeof(buffer
), total_size
);
2007 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
2008 buffer
, total_size
, &total_size
);
2009 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
) goto done
;
2011 /* we need to fetch the contents for a string type even if not requested,
2012 * because we need to compute the length of the ASCII string. */
2013 if (value
|| data
|| is_string(info
->Type
))
2015 /* retry with a dynamically allocated buffer */
2016 while (status
== STATUS_BUFFER_OVERFLOW
)
2018 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
2019 if (!(buf_ptr
= heap_alloc( total_size
)))
2020 return ERROR_NOT_ENOUGH_MEMORY
;
2021 info
= (KEY_VALUE_FULL_INFORMATION
*)buf_ptr
;
2022 status
= NtEnumerateValueKey( hkey
, index
, KeyValueFullInformation
,
2023 buf_ptr
, total_size
, &total_size
);
2026 if (status
) goto done
;
2028 if (is_string(info
->Type
))
2031 RtlUnicodeToMultiByteSize( &len
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2032 total_size
- info
->DataOffset
);
2035 if (len
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2038 RtlUnicodeToMultiByteN( (char*)data
, len
, NULL
, (WCHAR
*)(buf_ptr
+ info
->DataOffset
),
2039 total_size
- info
->DataOffset
);
2040 /* if the type is REG_SZ and data is not 0-terminated
2041 * and there is enough space in the buffer NT appends a \0 */
2042 if (len
< *count
&& data
[len
-1]) data
[len
] = 0;
2045 info
->DataLength
= len
;
2049 if (total_size
- info
->DataOffset
> *count
) status
= STATUS_BUFFER_OVERFLOW
;
2050 else memcpy( data
, buf_ptr
+ info
->DataOffset
, total_size
- info
->DataOffset
);
2053 if (value
&& !status
)
2057 RtlUnicodeToMultiByteSize( &len
, info
->Name
, info
->NameLength
);
2058 if (len
>= *val_count
)
2060 status
= STATUS_BUFFER_OVERFLOW
;
2063 len
= *val_count
- 1;
2064 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2070 RtlUnicodeToMultiByteN( value
, len
, NULL
, info
->Name
, info
->NameLength
);
2076 else status
= STATUS_SUCCESS
;
2078 if (type
) *type
= info
->Type
;
2079 if (count
) *count
= info
->DataLength
;
2082 if (buf_ptr
!= buffer
) heap_free( buf_ptr
);
2083 return RtlNtStatusToDosError(status
);
2086 /******************************************************************************
2087 * RegDeleteValueW [ADVAPI32.@]
2089 * See RegDeleteValueA.
2091 LSTATUS WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR name
)
2093 return RegDeleteKeyValueW( hkey
, NULL
, name
);
2096 /******************************************************************************
2097 * RegDeleteValueA [ADVAPI32.@]
2099 * Delete a value from the registry.
2102 * hkey [I] Registry handle of the key holding the value
2103 * name [I] Name of the value under hkey to delete
2106 * Success: ERROR_SUCCESS
2107 * Failure: nonzero error code from Winerror.h
2109 LSTATUS WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR name
)
2111 return RegDeleteKeyValueA( hkey
, NULL
, name
);
2114 /******************************************************************************
2115 * RegDeleteKeyValueW [ADVAPI32.@]
2117 LONG WINAPI
RegDeleteKeyValueW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR name
)
2119 UNICODE_STRING nameW
;
2123 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2127 if ((ret
= RegOpenKeyExW( hkey
, subkey
, 0, KEY_SET_VALUE
, &hsubkey
)))
2132 RtlInitUnicodeString( &nameW
, name
);
2133 ret
= RtlNtStatusToDosError( NtDeleteValueKey( hkey
, &nameW
) );
2134 if (hsubkey
) RegCloseKey( hsubkey
);
2138 /******************************************************************************
2139 * RegDeleteKeyValueA [ADVAPI32.@]
2141 LONG WINAPI
RegDeleteKeyValueA( HKEY hkey
, LPCSTR subkey
, LPCSTR name
)
2143 UNICODE_STRING nameW
;
2148 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2152 LONG ret
= RegOpenKeyExA( hkey
, subkey
, 0, KEY_SET_VALUE
, &hsubkey
);
2158 RtlInitAnsiString( &nameA
, name
);
2159 if (!(status
= RtlAnsiStringToUnicodeString( &nameW
, &nameA
, TRUE
)))
2161 status
= NtDeleteValueKey( hkey
, &nameW
);
2162 RtlFreeUnicodeString( &nameW
);
2165 if (hsubkey
) RegCloseKey( hsubkey
);
2166 return RtlNtStatusToDosError( status
);
2169 /******************************************************************************
2170 * RegLoadKeyW [ADVAPI32.@]
2172 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2173 * registration information from a specified file into that subkey.
2176 * hkey [I] Handle of open key
2177 * subkey [I] Address of name of subkey
2178 * filename [I] Address of filename for registry information
2181 * Success: ERROR_SUCCESS
2182 * Failure: nonzero error code from Winerror.h
2184 LSTATUS WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR subkey
, LPCWSTR filename
)
2186 OBJECT_ATTRIBUTES destkey
, file
;
2187 UNICODE_STRING subkeyW
, filenameW
;
2190 if (!(hkey
= get_special_root_hkey(hkey
, 0))) return ERROR_INVALID_HANDLE
;
2192 destkey
.Length
= sizeof(destkey
);
2193 destkey
.RootDirectory
= hkey
; /* root key: HKLM or HKU */
2194 destkey
.ObjectName
= &subkeyW
; /* name of the key */
2195 destkey
.Attributes
= 0;
2196 destkey
.SecurityDescriptor
= NULL
;
2197 destkey
.SecurityQualityOfService
= NULL
;
2198 RtlInitUnicodeString(&subkeyW
, subkey
);
2200 file
.Length
= sizeof(file
);
2201 file
.RootDirectory
= NULL
;
2202 file
.ObjectName
= &filenameW
; /* file containing the hive */
2203 file
.Attributes
= OBJ_CASE_INSENSITIVE
;
2204 file
.SecurityDescriptor
= NULL
;
2205 file
.SecurityQualityOfService
= NULL
;
2206 RtlDosPathNameToNtPathName_U(filename
, &filenameW
, NULL
, NULL
);
2208 status
= NtLoadKey(&destkey
, &file
);
2209 RtlFreeUnicodeString(&filenameW
);
2210 return RtlNtStatusToDosError( status
);
2214 /******************************************************************************
2215 * RegLoadKeyA [ADVAPI32.@]
2219 LSTATUS WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR subkey
, LPCSTR filename
)
2221 UNICODE_STRING subkeyW
, filenameW
;
2222 STRING subkeyA
, filenameA
;
2226 RtlInitAnsiString(&subkeyA
, subkey
);
2227 RtlInitAnsiString(&filenameA
, filename
);
2229 RtlInitUnicodeString(&subkeyW
, NULL
);
2230 RtlInitUnicodeString(&filenameW
, NULL
);
2231 if (!(status
= RtlAnsiStringToUnicodeString(&subkeyW
, &subkeyA
, TRUE
)) &&
2232 !(status
= RtlAnsiStringToUnicodeString(&filenameW
, &filenameA
, TRUE
)))
2234 ret
= RegLoadKeyW(hkey
, subkeyW
.Buffer
, filenameW
.Buffer
);
2236 else ret
= RtlNtStatusToDosError(status
);
2237 RtlFreeUnicodeString(&subkeyW
);
2238 RtlFreeUnicodeString(&filenameW
);
2243 /******************************************************************************
2244 * RegSaveKeyW [ADVAPI32.@]
2246 * Save a key and all of its subkeys and values to a new file in the standard format.
2249 * hkey [I] Handle of key where save begins
2250 * lpFile [I] Address of filename to save to
2251 * sa [I] Address of security structure
2254 * Success: ERROR_SUCCESS
2255 * Failure: nonzero error code from Winerror.h
2257 LSTATUS WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR file
, LPSECURITY_ATTRIBUTES sa
)
2259 static const WCHAR format
[] =
2260 {'r','e','g','%','0','4','x','.','t','m','p',0};
2261 WCHAR buffer
[MAX_PATH
];
2267 TRACE( "(%p,%s,%p)\n", hkey
, debugstr_w(file
), sa
);
2269 if (!file
|| !*file
) return ERROR_INVALID_PARAMETER
;
2270 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2272 err
= GetLastError();
2273 GetFullPathNameW( file
, sizeof(buffer
)/sizeof(WCHAR
), buffer
, &nameW
);
2277 snprintfW( nameW
, 16, format
, count
++ );
2278 handle
= CreateFileW( buffer
, GENERIC_WRITE
, 0, NULL
,
2279 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
2280 if (handle
!= INVALID_HANDLE_VALUE
) break;
2281 if ((ret
= GetLastError()) != ERROR_FILE_EXISTS
) goto done
;
2283 /* Something gone haywire ? Please report if this happens abnormally */
2285 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
);
2288 ret
= RtlNtStatusToDosError(NtSaveKey(hkey
, handle
));
2290 CloseHandle( handle
);
2293 if (!MoveFileExW( buffer
, file
, MOVEFILE_REPLACE_EXISTING
))
2295 ERR( "Failed to move %s to %s\n", debugstr_w(buffer
),
2297 ret
= GetLastError();
2300 if (ret
) DeleteFileW( buffer
);
2303 SetLastError( err
); /* restore last error code */
2308 /******************************************************************************
2309 * RegSaveKeyA [ADVAPI32.@]
2313 LSTATUS WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR file
, LPSECURITY_ATTRIBUTES sa
)
2315 UNICODE_STRING
*fileW
= &NtCurrentTeb()->StaticUnicodeString
;
2319 RtlInitAnsiString(&fileA
, file
);
2320 if ((status
= RtlAnsiStringToUnicodeString(fileW
, &fileA
, FALSE
)))
2321 return RtlNtStatusToDosError( status
);
2322 return RegSaveKeyW(hkey
, fileW
->Buffer
, sa
);
2326 /******************************************************************************
2327 * RegRestoreKeyW [ADVAPI32.@]
2329 * Read the registry information from a file and copy it over a key.
2332 * hkey [I] Handle of key where restore begins
2333 * lpFile [I] Address of filename containing saved tree
2334 * dwFlags [I] Optional flags
2337 * Success: ERROR_SUCCESS
2338 * Failure: nonzero error code from Winerror.h
2340 LSTATUS WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
2342 TRACE("(%p,%s,%d)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2344 /* It seems to do this check before the hkey check */
2345 if (!lpFile
|| !*lpFile
)
2346 return ERROR_INVALID_PARAMETER
;
2348 FIXME("(%p,%s,%d): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
2350 /* Check for file existence */
2352 return ERROR_SUCCESS
;
2356 /******************************************************************************
2357 * RegRestoreKeyA [ADVAPI32.@]
2359 * See RegRestoreKeyW.
2361 LSTATUS WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
2363 UNICODE_STRING lpFileW
;
2366 RtlCreateUnicodeStringFromAsciiz( &lpFileW
, lpFile
);
2367 ret
= RegRestoreKeyW( hkey
, lpFileW
.Buffer
, dwFlags
);
2368 RtlFreeUnicodeString( &lpFileW
);
2373 /******************************************************************************
2374 * RegUnLoadKeyW [ADVAPI32.@]
2376 * Unload a registry key and its subkeys from the registry.
2379 * hkey [I] Handle of open key
2380 * lpSubKey [I] Address of name of subkey to unload
2383 * Success: ERROR_SUCCESS
2384 * Failure: nonzero error code from Winerror.h
2386 LSTATUS WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
2390 OBJECT_ATTRIBUTES attr
;
2391 UNICODE_STRING subkey
;
2393 TRACE("(%p,%s)\n",hkey
, debugstr_w(lpSubKey
));
2395 ret
= RegOpenKeyW(hkey
,lpSubKey
,&shkey
);
2397 return ERROR_INVALID_PARAMETER
;
2399 RtlInitUnicodeString(&subkey
, lpSubKey
);
2400 InitializeObjectAttributes(&attr
, &subkey
, OBJ_CASE_INSENSITIVE
, shkey
, NULL
);
2401 ret
= RtlNtStatusToDosError(NtUnloadKey(&attr
));
2409 /******************************************************************************
2410 * RegUnLoadKeyA [ADVAPI32.@]
2412 * See RegUnLoadKeyW.
2414 LSTATUS WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
2416 UNICODE_STRING lpSubKeyW
;
2419 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2420 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
.Buffer
);
2421 RtlFreeUnicodeString( &lpSubKeyW
);
2426 /******************************************************************************
2427 * RegReplaceKeyW [ADVAPI32.@]
2429 * Replace the file backing a registry key and all its subkeys with another file.
2432 * hkey [I] Handle of open key
2433 * lpSubKey [I] Address of name of subkey
2434 * lpNewFile [I] Address of filename for file with new data
2435 * lpOldFile [I] Address of filename for backup file
2438 * Success: ERROR_SUCCESS
2439 * Failure: nonzero error code from Winerror.h
2441 LSTATUS WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
2444 FIXME("(%p,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
2445 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
2446 return ERROR_SUCCESS
;
2450 /******************************************************************************
2451 * RegReplaceKeyA [ADVAPI32.@]
2453 * See RegReplaceKeyW.
2455 LSTATUS WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
2458 UNICODE_STRING lpSubKeyW
;
2459 UNICODE_STRING lpNewFileW
;
2460 UNICODE_STRING lpOldFileW
;
2463 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW
, lpSubKey
);
2464 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW
, lpOldFile
);
2465 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW
, lpNewFile
);
2466 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
.Buffer
, lpNewFileW
.Buffer
, lpOldFileW
.Buffer
);
2467 RtlFreeUnicodeString( &lpOldFileW
);
2468 RtlFreeUnicodeString( &lpNewFileW
);
2469 RtlFreeUnicodeString( &lpSubKeyW
);
2474 /******************************************************************************
2475 * RegSetKeySecurity [ADVAPI32.@]
2477 * Set the security of an open registry key.
2480 * hkey [I] Open handle of key to set
2481 * SecurityInfo [I] Descriptor contents
2482 * pSecurityDesc [I] Address of descriptor for key
2485 * Success: ERROR_SUCCESS
2486 * Failure: nonzero error code from Winerror.h
2488 LSTATUS WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
2489 PSECURITY_DESCRIPTOR pSecurityDesc
)
2491 TRACE("(%p,%d,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
2493 /* It seems to perform this check before the hkey check */
2494 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
2495 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
2496 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
2497 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
2500 return ERROR_INVALID_PARAMETER
;
2503 return ERROR_INVALID_PARAMETER
;
2505 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2507 return RtlNtStatusToDosError( NtSetSecurityObject( hkey
, SecurityInfo
, pSecurityDesc
) );
2511 /******************************************************************************
2512 * RegGetKeySecurity [ADVAPI32.@]
2514 * Get a copy of the security descriptor for a given registry key.
2517 * hkey [I] Open handle of key to set
2518 * SecurityInformation [I] Descriptor contents
2519 * pSecurityDescriptor [O] Address of descriptor for key
2520 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2523 * Success: ERROR_SUCCESS
2524 * Failure: Error code
2526 LSTATUS WINAPI
RegGetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInformation
,
2527 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
2528 LPDWORD lpcbSecurityDescriptor
)
2530 TRACE("(%p,%d,%p,%d)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
2531 *lpcbSecurityDescriptor
);
2533 if (!(hkey
= get_special_root_hkey( hkey
, 0 ))) return ERROR_INVALID_HANDLE
;
2535 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey
,
2536 SecurityInformation
, pSecurityDescriptor
,
2537 *lpcbSecurityDescriptor
, lpcbSecurityDescriptor
) );
2541 /******************************************************************************
2542 * RegFlushKey [ADVAPI32.@]
2544 * Immediately write a registry key to registry.
2547 * hkey [I] Handle of key to write
2550 * Success: ERROR_SUCCESS
2551 * Failure: Error code
2553 LSTATUS WINAPI
RegFlushKey( HKEY hkey
)
2555 hkey
= get_special_root_hkey( hkey
, 0 );
2556 if (!hkey
) return ERROR_INVALID_HANDLE
;
2558 return RtlNtStatusToDosError( NtFlushKey( hkey
) );
2562 /******************************************************************************
2563 * RegConnectRegistryW [ADVAPI32.@]
2565 * Establish a connection to a predefined registry key on another computer.
2568 * lpMachineName [I] Address of name of remote computer
2569 * hHey [I] Predefined registry handle
2570 * phkResult [I] Address of buffer for remote registry handle
2573 * Success: ERROR_SUCCESS
2574 * Failure: nonzero error code from Winerror.h
2576 LSTATUS WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
2581 TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName
), hKey
, phkResult
);
2583 if (!lpMachineName
|| !*lpMachineName
) {
2584 /* Use the local machine name */
2585 ret
= RegOpenKeyW( hKey
, NULL
, phkResult
);
2588 WCHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
2589 DWORD len
= sizeof(compName
) / sizeof(WCHAR
);
2591 /* MSDN says lpMachineName must start with \\ : not so */
2592 if( lpMachineName
[0] == '\\' && lpMachineName
[1] == '\\')
2594 if (GetComputerNameW(compName
, &len
))
2596 if (!strcmpiW(lpMachineName
, compName
))
2597 ret
= RegOpenKeyW(hKey
, NULL
, phkResult
);
2600 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName
));
2601 ret
= ERROR_BAD_NETPATH
;
2605 ret
= GetLastError();
2611 /******************************************************************************
2612 * RegConnectRegistryA [ADVAPI32.@]
2614 * See RegConnectRegistryW.
2616 LSTATUS WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, PHKEY reskey
)
2618 UNICODE_STRING machineW
;
2621 RtlCreateUnicodeStringFromAsciiz( &machineW
, machine
);
2622 ret
= RegConnectRegistryW( machineW
.Buffer
, hkey
, reskey
);
2623 RtlFreeUnicodeString( &machineW
);
2628 /******************************************************************************
2629 * RegNotifyChangeKeyValue [ADVAPI32.@]
2631 * Notify the caller about changes to the attributes or contents of a registry key.
2634 * hkey [I] Handle of key to watch
2635 * fWatchSubTree [I] Flag for subkey notification
2636 * fdwNotifyFilter [I] Changes to be reported
2637 * hEvent [I] Handle of signaled event
2638 * fAsync [I] Flag for asynchronous reporting
2641 * Success: ERROR_SUCCESS
2642 * Failure: nonzero error code from Winerror.h
2644 LSTATUS WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
2645 DWORD fdwNotifyFilter
, HANDLE hEvent
,
2649 IO_STATUS_BLOCK iosb
;
2651 hkey
= get_special_root_hkey( hkey
, 0 );
2652 if (!hkey
) return ERROR_INVALID_HANDLE
;
2654 TRACE("(%p,%i,%d,%p,%i)\n", hkey
, fWatchSubTree
, fdwNotifyFilter
,
2657 status
= NtNotifyChangeKey( hkey
, hEvent
, NULL
, NULL
, &iosb
,
2658 fdwNotifyFilter
, fAsync
, NULL
, 0,
2661 if (status
&& status
!= STATUS_TIMEOUT
)
2662 return RtlNtStatusToDosError( status
);
2664 return ERROR_SUCCESS
;
2667 /******************************************************************************
2668 * RegOpenUserClassesRoot [ADVAPI32.@]
2670 * Open the HKEY_CLASSES_ROOT key for a user.
2673 * hToken [I] Handle of token representing the user
2674 * dwOptions [I] Reserved, must be 0
2675 * samDesired [I] Desired access rights
2676 * phkResult [O] Destination for the resulting key handle
2679 * Success: ERROR_SUCCESS
2680 * Failure: nonzero error code from Winerror.h
2683 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2684 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2685 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2687 LSTATUS WINAPI
RegOpenUserClassesRoot(
2694 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken
, dwOptions
, samDesired
, phkResult
);
2696 *phkResult
= HKEY_CLASSES_ROOT
;
2697 return ERROR_SUCCESS
;
2700 /******************************************************************************
2701 * load_string [Internal]
2703 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2704 * avoid importing user32, which is higher level than advapi32. Helper for
2707 static int load_string(HINSTANCE hModule
, UINT resId
, LPWSTR pwszBuffer
, INT cMaxChars
)
2714 /* Negative values have to be inverted. */
2715 if (HIWORD(resId
) == 0xffff)
2716 resId
= (UINT
)(-((INT
)resId
));
2718 /* Load the resource into memory and get a pointer to it. */
2719 hResource
= FindResourceW(hModule
, MAKEINTRESOURCEW(LOWORD(resId
>> 4) + 1), (LPWSTR
)RT_STRING
);
2720 if (!hResource
) return 0;
2721 hMemory
= LoadResource(hModule
, hResource
);
2722 if (!hMemory
) return 0;
2723 pString
= LockResource(hMemory
);
2725 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2726 idxString
= resId
& 0xf;
2727 while (idxString
--) pString
+= *pString
+ 1;
2729 /* If no buffer is given, return length of the string. */
2730 if (!pwszBuffer
) return *pString
;
2732 /* Else copy over the string, respecting the buffer size. */
2733 cMaxChars
= (*pString
< cMaxChars
) ? *pString
: (cMaxChars
- 1);
2734 if (cMaxChars
>= 0) {
2735 memcpy(pwszBuffer
, pString
+1, cMaxChars
* sizeof(WCHAR
));
2736 pwszBuffer
[cMaxChars
] = '\0';
2742 /******************************************************************************
2743 * RegLoadMUIStringW [ADVAPI32.@]
2745 * Load the localized version of a string resource from some PE, respective
2746 * id and path of which are given in the registry value in the format
2747 * @[path]\dllname,-resourceId
2750 * hKey [I] Key, of which to load the string value from.
2751 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2752 * pszBuffer [O] Buffer to store the localized string in.
2753 * cbBuffer [I] Size of the destination buffer in bytes.
2754 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2755 * dwFlags [I] None supported yet.
2756 * pszBaseDir [I] Not supported yet.
2759 * Success: ERROR_SUCCESS,
2760 * Failure: nonzero error code from winerror.h
2763 * This is an API of Windows Vista, which wasn't available at the time this code
2764 * was written. We have to check for the correct behaviour once it's available.
2766 LSTATUS WINAPI
RegLoadMUIStringW(HKEY hKey
, LPCWSTR pwszValue
, LPWSTR pwszBuffer
, DWORD cbBuffer
,
2767 LPDWORD pcbData
, DWORD dwFlags
, LPCWSTR pwszBaseDir
)
2769 DWORD dwValueType
, cbData
;
2770 LPWSTR pwszTempBuffer
= NULL
, pwszExpandedBuffer
= NULL
;
2773 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2774 "dwFlags = %d, pwszBaseDir = %s)\n", hKey
, debugstr_w(pwszValue
), pwszBuffer
,
2775 cbBuffer
, pcbData
, dwFlags
, debugstr_w(pwszBaseDir
));
2777 /* Parameter sanity checks. */
2778 if (!hKey
|| !pwszBuffer
)
2779 return ERROR_INVALID_PARAMETER
;
2781 if (pwszBaseDir
&& *pwszBaseDir
) {
2782 FIXME("BaseDir parameter not yet supported!\n");
2783 return ERROR_INVALID_PARAMETER
;
2786 /* Check for value existence and correctness of its type, allocate a buffer and load it. */
2787 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, NULL
, &cbData
);
2788 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2789 if (!(dwValueType
== REG_SZ
|| dwValueType
== REG_EXPAND_SZ
) || !cbData
) {
2790 result
= ERROR_FILE_NOT_FOUND
;
2793 pwszTempBuffer
= heap_alloc(cbData
);
2794 if (!pwszTempBuffer
) {
2795 result
= ERROR_NOT_ENOUGH_MEMORY
;
2798 result
= RegQueryValueExW(hKey
, pwszValue
, NULL
, &dwValueType
, (LPBYTE
)pwszTempBuffer
, &cbData
);
2799 if (result
!= ERROR_SUCCESS
) goto cleanup
;
2801 /* Expand environment variables, if appropriate, or copy the original string over. */
2802 if (dwValueType
== REG_EXPAND_SZ
) {
2803 cbData
= ExpandEnvironmentStringsW(pwszTempBuffer
, NULL
, 0) * sizeof(WCHAR
);
2804 if (!cbData
) goto cleanup
;
2805 pwszExpandedBuffer
= heap_alloc(cbData
);
2806 if (!pwszExpandedBuffer
) {
2807 result
= ERROR_NOT_ENOUGH_MEMORY
;
2810 ExpandEnvironmentStringsW(pwszTempBuffer
, pwszExpandedBuffer
, cbData
);
2812 pwszExpandedBuffer
= heap_alloc(cbData
);
2813 memcpy(pwszExpandedBuffer
, pwszTempBuffer
, cbData
);
2816 /* If the value references a resource based string, parse the value and load the string.
2817 * Else just copy over the original value. */
2818 result
= ERROR_SUCCESS
;
2819 if (*pwszExpandedBuffer
!= '@') { /* '@' is the prefix for resource based string entries. */
2820 lstrcpynW(pwszBuffer
, pwszExpandedBuffer
, cbBuffer
/ sizeof(WCHAR
));
2822 WCHAR
*pComma
= strrchrW(pwszExpandedBuffer
, ',');
2826 /* Format of the expanded value is 'path_to_dll,-resId' */
2827 if (!pComma
|| pComma
[1] != '-') {
2828 result
= ERROR_BADKEY
;
2832 uiStringId
= atoiW(pComma
+2);
2835 hModule
= LoadLibraryW(pwszExpandedBuffer
+ 1);
2836 if (!hModule
|| !load_string(hModule
, uiStringId
, pwszBuffer
, cbBuffer
/sizeof(WCHAR
)))
2837 result
= ERROR_BADKEY
;
2838 FreeLibrary(hModule
);
2842 heap_free(pwszTempBuffer
);
2843 heap_free(pwszExpandedBuffer
);
2847 /******************************************************************************
2848 * RegLoadMUIStringA [ADVAPI32.@]
2850 * See RegLoadMUIStringW
2852 LSTATUS WINAPI
RegLoadMUIStringA(HKEY hKey
, LPCSTR pszValue
, LPSTR pszBuffer
, DWORD cbBuffer
,
2853 LPDWORD pcbData
, DWORD dwFlags
, LPCSTR pszBaseDir
)
2855 UNICODE_STRING valueW
, baseDirW
;
2857 DWORD cbData
= cbBuffer
* sizeof(WCHAR
);
2860 valueW
.Buffer
= baseDirW
.Buffer
= pwszBuffer
= NULL
;
2861 if (!RtlCreateUnicodeStringFromAsciiz(&valueW
, pszValue
) ||
2862 !RtlCreateUnicodeStringFromAsciiz(&baseDirW
, pszBaseDir
) ||
2863 !(pwszBuffer
= heap_alloc(cbData
)))
2865 result
= ERROR_NOT_ENOUGH_MEMORY
;
2869 result
= RegLoadMUIStringW(hKey
, valueW
.Buffer
, pwszBuffer
, cbData
, NULL
, dwFlags
,
2872 if (result
== ERROR_SUCCESS
) {
2873 cbData
= WideCharToMultiByte(CP_ACP
, 0, pwszBuffer
, -1, pszBuffer
, cbBuffer
, NULL
, NULL
);
2879 heap_free(pwszBuffer
);
2880 RtlFreeUnicodeString(&baseDirW
);
2881 RtlFreeUnicodeString(&valueW
);
2886 /******************************************************************************
2887 * RegDisablePredefinedCache [ADVAPI32.@]
2889 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2895 * Success: ERROR_SUCCESS
2896 * Failure: nonzero error code from Winerror.h
2899 * This is useful for services that use impersonation.
2901 LSTATUS WINAPI
RegDisablePredefinedCache(void)
2903 HKEY hkey_current_user
;
2904 int idx
= HandleToUlong(HKEY_CURRENT_USER
) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST
);
2906 /* prevent caching of future requests */
2907 hkcu_cache_disabled
= TRUE
;
2909 hkey_current_user
= InterlockedExchangePointer( (void **)&special_root_keys
[idx
], NULL
);
2911 if (hkey_current_user
)
2912 NtClose( hkey_current_user
);
2914 return ERROR_SUCCESS
;
2917 /******************************************************************************
2918 * RegDeleteTreeW [ADVAPI32.@]
2921 LSTATUS WINAPI
RegDeleteTreeW(HKEY hKey
, LPCWSTR lpszSubKey
)
2924 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
2925 DWORD dwMaxLen
, dwSize
;
2926 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
2927 HKEY hSubKey
= hKey
;
2929 TRACE("(hkey=%p,%p %s)\n", hKey
, lpszSubKey
, debugstr_w(lpszSubKey
));
2933 ret
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
2934 if (ret
) return ret
;
2937 /* Get highest length for keys, values */
2938 ret
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
2939 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
2940 if (ret
) goto cleanup
;
2944 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
2945 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
2947 /* Name too big: alloc a buffer for it */
2948 if (!(lpszName
= heap_alloc( dwMaxLen
*sizeof(WCHAR
))))
2950 ret
= ERROR_NOT_ENOUGH_MEMORY
;
2956 /* Recursively delete all the subkeys */
2960 if (RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
2961 NULL
, NULL
, NULL
)) break;
2963 ret
= RegDeleteTreeW(hSubKey
, lpszName
);
2964 if (ret
) goto cleanup
;
2968 ret
= RegDeleteKeyW(hKey
, lpszSubKey
);
2973 if (RegEnumValueW(hKey
, 0, lpszName
, &dwSize
,
2974 NULL
, NULL
, NULL
, NULL
)) break;
2976 ret
= RegDeleteValueW(hKey
, lpszName
);
2977 if (ret
) goto cleanup
;
2981 /* Free buffer if allocated */
2982 if (lpszName
!= szNameBuf
)
2983 heap_free( lpszName
);
2985 RegCloseKey(hSubKey
);
2989 /******************************************************************************
2990 * RegDeleteTreeA [ADVAPI32.@]
2993 LSTATUS WINAPI
RegDeleteTreeA(HKEY hKey
, LPCSTR lpszSubKey
)
2996 UNICODE_STRING lpszSubKeyW
;
2998 if (lpszSubKey
) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW
, lpszSubKey
);
2999 else lpszSubKeyW
.Buffer
= NULL
;
3000 ret
= RegDeleteTreeW( hKey
, lpszSubKeyW
.Buffer
);
3001 RtlFreeUnicodeString( &lpszSubKeyW
);
3005 /******************************************************************************
3006 * RegDisableReflectionKey [ADVAPI32.@]
3009 LONG WINAPI
RegDisableReflectionKey(HKEY base
)
3011 FIXME("%p: stub\n", base
);
3012 return ERROR_SUCCESS
;