taskmgr: Small update to the Swedish translation.
[wine] / dlls / advapi32 / registry.c
CommitLineData
2fab2ef1
AJ
1/*
2 * Registry management
3 *
4 * Copyright (C) 1999 Alexandre Julliard
5 *
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
10 *
0799c1a7
AJ
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.
15 *
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.
20 *
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
360a3f91 23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
2fab2ef1
AJ
24 */
25
26#include <stdlib.h>
e37c6e18 27#include <stdarg.h>
383da68c 28#include <stdio.h>
2fab2ef1 29
1a1583a3
GG
30#include "ntstatus.h"
31#define WIN32_NO_STATUS
e37c6e18 32#include "windef.h"
2fab2ef1
AJ
33#include "winbase.h"
34#include "winreg.h"
35#include "winerror.h"
efbea2e2 36#include "winternl.h"
ac615ce5 37#include "winuser.h"
efbea2e2 38
c7e7df8b 39#include "wine/unicode.h"
0799c1a7 40#include "wine/debug.h"
2fab2ef1 41
0799c1a7 42WINE_DEFAULT_DEBUG_CHANNEL(reg);
2fab2ef1 43
f2ef2c2b
AJ
44#define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
45#define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
b88554d2 46#define NB_SPECIAL_ROOT_KEYS ((UINT_PTR)HKEY_SPECIAL_ROOT_LAST - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST + 1)
f2ef2c2b
AJ
47
48static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
52aaddcd 49static BOOL hkcu_cache_disabled;
f2ef2c2b
AJ
50
51static const WCHAR name_CLASSES_ROOT[] =
52 {'M','a','c','h','i','n','e','\\',
53 'S','o','f','t','w','a','r','e','\\',
54 'C','l','a','s','s','e','s',0};
55static const WCHAR name_LOCAL_MACHINE[] =
56 {'M','a','c','h','i','n','e',0};
57static const WCHAR name_USERS[] =
58 {'U','s','e','r',0};
59static const WCHAR name_PERFORMANCE_DATA[] =
60 {'P','e','r','f','D','a','t','a',0};
61static const WCHAR name_CURRENT_CONFIG[] =
62 {'M','a','c','h','i','n','e','\\',
63 'S','y','s','t','e','m','\\',
64 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
8e9d88c1 65 'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
f2ef2c2b
AJ
66 'C','u','r','r','e','n','t',0};
67static const WCHAR name_DYN_DATA[] =
68 {'D','y','n','D','a','t','a',0};
69
e5b4b47c 70static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] =
f2ef2c2b 71{
e852f195
AJ
72 name_CLASSES_ROOT,
73 NULL, /* HKEY_CURRENT_USER is determined dynamically */
74 name_LOCAL_MACHINE,
75 name_USERS,
76 name_PERFORMANCE_DATA,
77 name_CURRENT_CONFIG,
78 name_DYN_DATA
f2ef2c2b 79};
f2ef2c2b 80
68a5c347 81static const int is_win64 = (sizeof(void *) > sizeof(int));
2fab2ef1 82
2fab2ef1 83/* check if value type needs string conversion (Ansi<->Unicode) */
a2e7c325 84static inline int is_string( DWORD type )
2fab2ef1
AJ
85{
86 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
87}
88
7dbce65b 89/* check if current version is NT or Win95 */
a2e7c325 90static inline int is_version_nt(void)
7dbce65b
MC
91{
92 return !(GetVersion() & 0x80000000);
93}
2fab2ef1 94
68a5c347
AJ
95static BOOL is_wow6432node( const UNICODE_STRING *name )
96{
97 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e'};
98
99 return (name->Length == sizeof(wow6432nodeW) &&
100 !memicmpW( name->Buffer, wow6432nodeW, sizeof(wow6432nodeW)/sizeof(WCHAR) ));
101}
102
103/* open the Wow6432Node subkey of the specified key */
104static HANDLE open_wow6432node( HANDLE key, const UNICODE_STRING *name )
105{
106 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
107 OBJECT_ATTRIBUTES attr;
108 UNICODE_STRING nameW;
109 HANDLE ret;
110
111 attr.Length = sizeof(attr);
112 attr.RootDirectory = key;
113 attr.ObjectName = &nameW;
114 attr.Attributes = 0;
115 attr.SecurityDescriptor = NULL;
116 attr.SecurityQualityOfService = NULL;
117 RtlInitUnicodeString( &nameW, wow6432nodeW );
118 if (NtOpenKey( &ret, MAXIMUM_ALLOWED, &attr )) ret = 0;
119 return ret;
120}
121
972f96d6
AJ
122/* wrapper for NtCreateKey that creates the key recursively if necessary */
123static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
124 const UNICODE_STRING *class, ULONG options, PULONG dispos )
125{
68a5c347
AJ
126 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
127 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
128
129 if (!force_wow32) status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, class, options, dispos );
972f96d6
AJ
130
131 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
132 {
68a5c347
AJ
133 HANDLE subkey, root = attr->RootDirectory;
134 WCHAR *buffer = attr->ObjectName->Buffer;
135 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
136 UNICODE_STRING str;
137
138 while (i < len && buffer[i] != '\\') i++;
139 if (i == len && !force_wow32) return status;
972f96d6 140
972f96d6
AJ
141 attrs = attr->Attributes;
142 attr->Attributes &= ~OBJ_OPENLINK;
68a5c347 143 attr->ObjectName = &str;
972f96d6
AJ
144
145 while (i < len)
146 {
68a5c347
AJ
147 str.Buffer = buffer + pos;
148 str.Length = (i - pos) * sizeof(WCHAR);
149 if (force_wow32 && pos)
150 {
151 if (is_wow6432node( &str )) force_wow32 = FALSE;
152 else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
153 {
154 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
155 attr->RootDirectory = subkey;
156 force_wow32 = FALSE;
157 }
158 }
159 status = NtCreateKey( &subkey, access, attr, 0, class,
972f96d6 160 options & ~REG_OPTION_CREATE_LINK, dispos );
68a5c347 161 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
972f96d6 162 if (status) return status;
68a5c347
AJ
163 attr->RootDirectory = subkey;
164 while (i < len && buffer[i] == '\\') i++;
165 pos = i;
166 while (i < len && buffer[i] != '\\') i++;
972f96d6 167 }
68a5c347
AJ
168 str.Buffer = buffer + pos;
169 str.Length = (i - pos) * sizeof(WCHAR);
972f96d6 170 attr->Attributes = attrs;
972f96d6 171 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, class, options, dispos );
68a5c347 172 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
972f96d6
AJ
173 }
174 return status;
175}
176
21da080d
AJ
177/* wrapper for NtOpenKey to handle Wow6432 nodes */
178static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
179{
180 NTSTATUS status;
181 BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
182 HANDLE subkey, root = attr->RootDirectory;
183 WCHAR *buffer = attr->ObjectName->Buffer;
184 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
185 UNICODE_STRING str;
186
187 if (!force_wow32) return NtOpenKey( (HANDLE *)retkey, access, attr );
188
189 if (len && buffer[0] == '\\') return STATUS_OBJECT_PATH_INVALID;
190 while (i < len && buffer[i] != '\\') i++;
191 attrs = attr->Attributes;
192 attr->Attributes &= ~OBJ_OPENLINK;
193 attr->ObjectName = &str;
194
195 while (i < len)
196 {
197 str.Buffer = buffer + pos;
198 str.Length = (i - pos) * sizeof(WCHAR);
199 if (force_wow32 && pos)
200 {
201 if (is_wow6432node( &str )) force_wow32 = FALSE;
202 else if ((subkey = open_wow6432node( attr->RootDirectory, &str )))
203 {
204 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
205 attr->RootDirectory = subkey;
206 force_wow32 = FALSE;
207 }
208 }
209 status = NtOpenKey( &subkey, access, attr );
210 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
211 if (status) return status;
212 attr->RootDirectory = subkey;
213 while (i < len && buffer[i] == '\\') i++;
214 pos = i;
215 while (i < len && buffer[i] != '\\') i++;
216 }
217 str.Buffer = buffer + pos;
218 str.Length = (i - pos) * sizeof(WCHAR);
219 attr->Attributes = attrs;
220 status = NtOpenKey( (PHANDLE)retkey, access, attr );
221 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
222 return status;
223
224}
225
f2ef2c2b 226/* create one of the HKEY_* special root keys */
972f96d6 227static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
f2ef2c2b
AJ
228{
229 HKEY ret = 0;
261e3764 230 int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
f2ef2c2b
AJ
231
232 if (hkey == HKEY_CURRENT_USER)
233 {
972f96d6 234 if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
cbacde52 235 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
52aaddcd
RS
236
237 /* don't cache the key in the table if caching is disabled */
238 if (hkcu_cache_disabled)
239 return hkey;
f2ef2c2b
AJ
240 }
241 else
242 {
243 OBJECT_ATTRIBUTES attr;
e852f195 244 UNICODE_STRING name;
f2ef2c2b
AJ
245
246 attr.Length = sizeof(attr);
247 attr.RootDirectory = 0;
e852f195 248 attr.ObjectName = &name;
f2ef2c2b
AJ
249 attr.Attributes = 0;
250 attr.SecurityDescriptor = NULL;
251 attr.SecurityQualityOfService = NULL;
e852f195 252 RtlInitUnicodeString( &name, root_key_names[idx] );
972f96d6 253 if (create_key( &hkey, access, &attr, NULL, 0, NULL )) return 0;
cbacde52 254 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
f2ef2c2b
AJ
255 }
256
cbacde52 257 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
f2ef2c2b
AJ
258 ret = hkey;
259 else
260 NtClose( hkey ); /* somebody beat us to it */
261 return ret;
262}
263
264/* map the hkey from special root to normal key if necessary */
a2e7c325 265static inline HKEY get_special_root_hkey( HKEY hkey )
f2ef2c2b
AJ
266{
267 HKEY ret = hkey;
268
269 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
270 {
261e3764 271 if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
7fea0e33 272 ret = create_special_root_hkey( hkey, MAXIMUM_ALLOWED );
f2ef2c2b
AJ
273 }
274 return ret;
275}
276
a44e0b0f 277
df0f42fe
AJ
278/******************************************************************************
279 * RegOverridePredefKey [ADVAPI32.@]
280 */
281LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
282{
283 HKEY old_key;
284 int idx;
285
286 if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST))
287 return ERROR_INVALID_PARAMETER;
288 idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
289
290 if (override)
291 {
292 NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
293 GetCurrentProcess(), (HANDLE *)&override,
294 0, 0, DUPLICATE_SAME_ACCESS );
295 if (status) return RtlNtStatusToDosError( status );
296 }
297
298 old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
299 if (old_key) NtClose( old_key );
300 return ERROR_SUCCESS;
301}
302
303
2fab2ef1 304/******************************************************************************
6a358c40 305 * RegCreateKeyExW [ADVAPI32.@]
2fab2ef1 306 *
50ce0844 307 * See RegCreateKeyExA.
2fab2ef1 308 */
af183df6 309LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
0542e835
BJY
310 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
311 PHKEY retkey, LPDWORD dispos )
2fab2ef1 312{
bcf393a5
AJ
313 OBJECT_ATTRIBUTES attr;
314 UNICODE_STRING nameW, classW;
2fab2ef1
AJ
315
316 if (reserved) return ERROR_INVALID_PARAMETER;
f2ef2c2b 317 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2fab2ef1 318
bcf393a5
AJ
319 attr.Length = sizeof(attr);
320 attr.RootDirectory = hkey;
321 attr.ObjectName = &nameW;
322 attr.Attributes = 0;
323 attr.SecurityDescriptor = NULL;
324 attr.SecurityQualityOfService = NULL;
6c078502 325 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
bcf393a5
AJ
326 RtlInitUnicodeString( &nameW, name );
327 RtlInitUnicodeString( &classW, class );
328
972f96d6 329 return RtlNtStatusToDosError( create_key( retkey, access, &attr, &classW, options, dispos ) );
2fab2ef1
AJ
330}
331
332
333/******************************************************************************
6a358c40 334 * RegCreateKeyExA [ADVAPI32.@]
a44e0b0f 335 *
50ce0844
JG
336 * Open a registry key, creating it if it doesn't exist.
337 *
338 * PARAMS
6a358c40
JH
339 * hkey [I] Handle of the parent registry key
340 * name [I] Name of the new key to open or create
341 * reserved [I] Reserved, pass 0
342 * class [I] The object type of the new key
343 * options [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
344 * access [I] Access level desired
345 * sa [I] Security attributes for the key
346 * retkey [O] Destination for the resulting handle
347 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
50ce0844
JG
348 *
349 * RETURNS
6a358c40
JH
350 * Success: ERROR_SUCCESS.
351 * Failure: A standard Win32 error code. retkey remains untouched.
50ce0844
JG
352 *
353 * FIXME
6a358c40 354 * MAXIMUM_ALLOWED in access mask not supported by server
2fab2ef1 355 */
af183df6 356LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
0542e835
BJY
357 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
358 PHKEY retkey, LPDWORD dispos )
2fab2ef1 359{
bcf393a5 360 OBJECT_ATTRIBUTES attr;
ab5e9759 361 UNICODE_STRING classW;
bcf393a5
AJ
362 ANSI_STRING nameA, classA;
363 NTSTATUS status;
2fab2ef1
AJ
364
365 if (reserved) return ERROR_INVALID_PARAMETER;
62b69d64
RK
366 if (!is_version_nt())
367 {
7fea0e33 368 access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
62b69d64
RK
369 if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
370 }
f2ef2c2b 371 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2fab2ef1 372
bcf393a5
AJ
373 attr.Length = sizeof(attr);
374 attr.RootDirectory = hkey;
ab5e9759 375 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
bcf393a5
AJ
376 attr.Attributes = 0;
377 attr.SecurityDescriptor = NULL;
378 attr.SecurityQualityOfService = NULL;
6c078502 379 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
bcf393a5
AJ
380 RtlInitAnsiString( &nameA, name );
381 RtlInitAnsiString( &classA, class );
382
ab5e9759
AJ
383 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
384 &nameA, FALSE )))
2fab2ef1 385 {
bcf393a5
AJ
386 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
387 {
972f96d6 388 status = create_key( retkey, access, &attr, &classW, options, dispos );
bcf393a5
AJ
389 RtlFreeUnicodeString( &classW );
390 }
2fab2ef1 391 }
bcf393a5 392 return RtlNtStatusToDosError( status );
2fab2ef1
AJ
393}
394
395
396/******************************************************************************
6a358c40
JH
397 * RegCreateKeyW [ADVAPI32.@]
398 *
399 * Creates the specified reg key.
400 *
401 * PARAMS
402 * hKey [I] Handle to an open key.
403 * lpSubKey [I] Name of a key that will be opened or created.
404 * phkResult [O] Receives a handle to the opened or created key.
405 *
406 * RETURNS
407 * Success: ERROR_SUCCESS
408 * Failure: nonzero error code defined in Winerror.h
2fab2ef1 409 */
af183df6 410LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
2fab2ef1
AJ
411{
412 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
413 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
6a358c40 414 return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
7fea0e33 415 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
2fab2ef1
AJ
416}
417
418
419/******************************************************************************
6a358c40
JH
420 * RegCreateKeyA [ADVAPI32.@]
421 *
d45811ce 422 * See RegCreateKeyW.
2fab2ef1 423 */
af183df6 424LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
2fab2ef1 425{
6a358c40 426 return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
7fea0e33 427 MAXIMUM_ALLOWED, NULL, phkResult, NULL );
2fab2ef1
AJ
428}
429
430
431
432/******************************************************************************
6a358c40
JH
433 * RegOpenKeyExW [ADVAPI32.@]
434 *
50ce0844 435 * See RegOpenKeyExA.
2fab2ef1 436 */
6c078502 437LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM access, PHKEY retkey )
2fab2ef1 438{
bcf393a5
AJ
439 OBJECT_ATTRIBUTES attr;
440 UNICODE_STRING nameW;
441
aacb511d
LZ
442 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
443 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
444
0e98500e 445 if (!retkey) return ERROR_INVALID_PARAMETER;
f2ef2c2b
AJ
446 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
447
bcf393a5
AJ
448 attr.Length = sizeof(attr);
449 attr.RootDirectory = hkey;
450 attr.ObjectName = &nameW;
451 attr.Attributes = 0;
452 attr.SecurityDescriptor = NULL;
453 attr.SecurityQualityOfService = NULL;
6c078502 454 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
bcf393a5 455 RtlInitUnicodeString( &nameW, name );
21da080d 456 return RtlNtStatusToDosError( open_key( retkey, access, &attr ) );
2fab2ef1
AJ
457}
458
459
460/******************************************************************************
6a358c40 461 * RegOpenKeyExA [ADVAPI32.@]
50ce0844
JG
462 *
463 * Open a registry key.
464 *
465 * PARAMS
6a358c40
JH
466 * hkey [I] Handle of open key
467 * name [I] Name of subkey to open
6c078502 468 * options [I] Open options (can be set to REG_OPTION_OPEN_LINK)
6a358c40
JH
469 * access [I] Security access mask
470 * retkey [O] Handle to open key
50ce0844
JG
471 *
472 * RETURNS
6a358c40
JH
473 * Success: ERROR_SUCCESS
474 * Failure: A standard Win32 error code. retkey is set to 0.
50ce0844
JG
475 *
476 * NOTES
6a358c40
JH
477 * Unlike RegCreateKeyExA(), this function will not create the key if it
478 * does not exist.
2fab2ef1 479 */
6c078502 480LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
2fab2ef1 481{
bcf393a5 482 OBJECT_ATTRIBUTES attr;
bcf393a5
AJ
483 STRING nameA;
484 NTSTATUS status;
485
7fea0e33 486 if (!is_version_nt()) access = MAXIMUM_ALLOWED; /* Win95 ignores the access mask */
aacb511d
LZ
487 else
488 {
489 /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
490 if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
491 }
7dbce65b 492
f2ef2c2b
AJ
493 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
494
bcf393a5
AJ
495 attr.Length = sizeof(attr);
496 attr.RootDirectory = hkey;
ab5e9759 497 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
bcf393a5
AJ
498 attr.Attributes = 0;
499 attr.SecurityDescriptor = NULL;
500 attr.SecurityQualityOfService = NULL;
6c078502 501 if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK;
bcf393a5
AJ
502
503 RtlInitAnsiString( &nameA, name );
ab5e9759
AJ
504 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
505 &nameA, FALSE )))
bcf393a5 506 {
21da080d 507 status = open_key( retkey, access, &attr );
bcf393a5
AJ
508 }
509 return RtlNtStatusToDosError( status );
2fab2ef1
AJ
510}
511
512
513/******************************************************************************
6a358c40 514 * RegOpenKeyW [ADVAPI32.@]
2fab2ef1 515 *
50ce0844 516 * See RegOpenKeyA.
2fab2ef1 517 */
af183df6 518LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
2fab2ef1 519{
0ca3b3b4
DR
520 if (!retkey)
521 return ERROR_INVALID_PARAMETER;
522
e8d1e2f7
JH
523 if (!name || !*name)
524 {
525 *retkey = hkey;
526 return ERROR_SUCCESS;
527 }
7fea0e33 528 return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
2fab2ef1
AJ
529}
530
531
532/******************************************************************************
6a358c40 533 * RegOpenKeyA [ADVAPI32.@]
50ce0844
JG
534 *
535 * Open a registry key.
536 *
537 * PARAMS
6a358c40
JH
538 * hkey [I] Handle of parent key to open the new key under
539 * name [I] Name of the key under hkey to open
540 * retkey [O] Destination for the resulting Handle
50ce0844
JG
541 *
542 * RETURNS
6a358c40 543 * Success: ERROR_SUCCESS
0ca3b3b4 544 * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0.
2fab2ef1 545 */
af183df6 546LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
2fab2ef1 547{
0ca3b3b4
DR
548 if (!retkey)
549 return ERROR_INVALID_PARAMETER;
550
e8d1e2f7
JH
551 if (!name || !*name)
552 {
553 *retkey = hkey;
554 return ERROR_SUCCESS;
555 }
7fea0e33 556 return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey );
2fab2ef1
AJ
557}
558
559
44f84b55 560/******************************************************************************
6a358c40 561 * RegOpenCurrentUser [ADVAPI32.@]
ec350525
MA
562 *
563 * Get a handle to the HKEY_CURRENT_USER key for the user
564 * the current thread is impersonating.
565 *
566 * PARAMS
567 * access [I] Desired access rights to the key
568 * retkey [O] Handle to the opened key
569 *
570 * RETURNS
571 * Success: ERROR_SUCCESS
572 * Failure: nonzero error code from Winerror.h
573 *
574 * FIXME
575 * This function is supposed to retrieve a handle to the
576 * HKEY_CURRENT_USER for the user the current thread is impersonating.
577 * Since Wine does not currently allow threads to impersonate other users,
578 * this stub should work fine.
44f84b55 579 */
af183df6 580LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
44f84b55
DE
581{
582 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
583}
584
585
2fab2ef1
AJ
586
587/******************************************************************************
6a358c40 588 * RegEnumKeyExW [ADVAPI32.@]
2fab2ef1 589 *
ec350525
MA
590 * Enumerate subkeys of the specified open registry key.
591 *
2fab2ef1 592 * PARAMS
6a358c40
JH
593 * hkey [I] Handle to key to enumerate
594 * index [I] Index of subkey to enumerate
595 * name [O] Buffer for subkey name
596 * name_len [O] Size of subkey buffer
597 * reserved [I] Reserved
598 * class [O] Buffer for class string
599 * class_len [O] Size of class buffer
600 * ft [O] Time key last written to
601 *
602 * RETURNS
603 * Success: ERROR_SUCCESS
604 * Failure: System error code. If there are no more subkeys available, the
605 * function returns ERROR_NO_MORE_ITEMS.
2fab2ef1 606 */
af183df6 607LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
0542e835 608 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
2fab2ef1 609{
454355ec
AJ
610 NTSTATUS status;
611 char buffer[256], *buf_ptr = buffer;
612 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
613 DWORD total_size;
2fab2ef1 614
414cdc04
AT
615 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
616 name_len ? *name_len : 0, reserved, class, class_len, ft );
2fab2ef1
AJ
617
618 if (reserved) return ERROR_INVALID_PARAMETER;
f2ef2c2b 619 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
0bb6fdda 620
454355ec
AJ
621 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
622 buffer, sizeof(buffer), &total_size );
2fab2ef1 623
454355ec
AJ
624 while (status == STATUS_BUFFER_OVERFLOW)
625 {
626 /* retry with a dynamically allocated buffer */
627 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
628 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
629 return ERROR_NOT_ENOUGH_MEMORY;
630 info = (KEY_NODE_INFORMATION *)buf_ptr;
631 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
632 buf_ptr, total_size, &total_size );
633 }
2fab2ef1 634
454355ec 635 if (!status)
2fab2ef1 636 {
454355ec
AJ
637 DWORD len = info->NameLength / sizeof(WCHAR);
638 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
639
6b6596a1 640 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
454355ec 641
20a4cc31 642 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
454355ec
AJ
643 status = STATUS_BUFFER_OVERFLOW;
644 else
645 {
646 *name_len = len;
647 memcpy( name, info->Name, info->NameLength );
648 name[len] = 0;
649 if (class_len)
650 {
651 *class_len = cls_len;
652 if (class)
653 {
654 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
655 class[cls_len] = 0;
656 }
657 }
658 }
2fab2ef1 659 }
454355ec
AJ
660
661 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
662 return RtlNtStatusToDosError( status );
2fab2ef1
AJ
663}
664
665
666/******************************************************************************
6a358c40
JH
667 * RegEnumKeyExA [ADVAPI32.@]
668 *
d45811ce 669 * See RegEnumKeyExW.
2fab2ef1 670 */
af183df6 671LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
0542e835 672 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
2fab2ef1 673{
454355ec
AJ
674 NTSTATUS status;
675 char buffer[256], *buf_ptr = buffer;
676 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
677 DWORD total_size;
2fab2ef1 678
414cdc04
AT
679 TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
680 name_len ? *name_len : 0, reserved, class, class_len, ft );
2fab2ef1
AJ
681
682 if (reserved) return ERROR_INVALID_PARAMETER;
f2ef2c2b 683 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
0bb6fdda 684
454355ec
AJ
685 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
686 buffer, sizeof(buffer), &total_size );
2fab2ef1 687
454355ec
AJ
688 while (status == STATUS_BUFFER_OVERFLOW)
689 {
690 /* retry with a dynamically allocated buffer */
691 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
692 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
693 return ERROR_NOT_ENOUGH_MEMORY;
694 info = (KEY_NODE_INFORMATION *)buf_ptr;
695 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
696 buf_ptr, total_size, &total_size );
697 }
2fab2ef1 698
454355ec 699 if (!status)
2fab2ef1 700 {
60fd03d2 701 DWORD len, cls_len;
454355ec 702
60fd03d2
AJ
703 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
704 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
705 info->ClassLength );
6b6596a1 706 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
454355ec 707
20a4cc31 708 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
454355ec
AJ
709 status = STATUS_BUFFER_OVERFLOW;
710 else
711 {
712 *name_len = len;
60fd03d2 713 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
454355ec
AJ
714 name[len] = 0;
715 if (class_len)
716 {
717 *class_len = cls_len;
718 if (class)
719 {
60fd03d2
AJ
720 RtlUnicodeToMultiByteN( class, cls_len, NULL,
721 (WCHAR *)(buf_ptr + info->ClassOffset),
722 info->ClassLength );
454355ec
AJ
723 class[cls_len] = 0;
724 }
725 }
726 }
2fab2ef1 727 }
454355ec
AJ
728
729 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
730 return RtlNtStatusToDosError( status );
2fab2ef1
AJ
731}
732
733
734/******************************************************************************
6a358c40
JH
735 * RegEnumKeyW [ADVAPI32.@]
736 *
d347ebe1 737 * Enumerates subkeys of the specified open reg key.
6a358c40
JH
738 *
739 * PARAMS
740 * hKey [I] Handle to an open key.
741 * dwIndex [I] Index of the subkey of hKey to retrieve.
742 * lpName [O] Name of the subkey.
743 * cchName [I] Size of lpName in TCHARS.
744 *
745 * RETURNS
746 * Success: ERROR_SUCCESS
747 * Failure: system error code. If there are no more subkeys available, the
748 * function returns ERROR_NO_MORE_ITEMS.
2fab2ef1 749 */
af183df6 750LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
2fab2ef1
AJ
751{
752 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
753}
754
755
756/******************************************************************************
6a358c40
JH
757 * RegEnumKeyA [ADVAPI32.@]
758 *
d45811ce 759 * See RegEnumKeyW.
2fab2ef1 760 */
af183df6 761LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
2fab2ef1
AJ
762{
763 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
764}
765
766
767/******************************************************************************
6a358c40 768 * RegQueryInfoKeyW [ADVAPI32.@]
2fab2ef1 769 *
d45811ce
MA
770 * Retrieves information about the specified registry key.
771 *
2fab2ef1
AJ
772 * PARAMS
773 * hkey [I] Handle to key to query
774 * class [O] Buffer for class string
775 * class_len [O] Size of class string buffer
776 * reserved [I] Reserved
777 * subkeys [O] Buffer for number of subkeys
778 * max_subkey [O] Buffer for longest subkey name length
779 * max_class [O] Buffer for longest class string length
780 * values [O] Buffer for number of value entries
781 * max_value [O] Buffer for longest value name length
782 * max_data [O] Buffer for longest value data length
783 * security [O] Buffer for security descriptor length
784 * modif [O] Modification time
785 *
d45811ce
MA
786 * RETURNS
787 * Success: ERROR_SUCCESS
788 * Failure: system error code.
789 *
790 * NOTES
791 * - win95 allows class to be valid and class_len to be NULL
792 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
793 * - both allow class to be NULL and class_len to be NULL
794 * (it's hard to test validity, so test !NULL instead)
2fab2ef1 795 */
af183df6 796LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
0542e835
BJY
797 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
798 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
799 LPDWORD security, FILETIME *modif )
2fab2ef1 800{
454355ec
AJ
801 NTSTATUS status;
802 char buffer[256], *buf_ptr = buffer;
803 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
804 DWORD total_size;
2fab2ef1 805
4301816d 806 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
2fab2ef1
AJ
807 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
808
7dbce65b 809 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
f2ef2c2b 810 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2fab2ef1 811
454355ec 812 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
c6615832 813 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
2fab2ef1
AJ
814
815 if (class)
816 {
454355ec
AJ
817 /* retry with a dynamically allocated buffer */
818 while (status == STATUS_BUFFER_OVERFLOW)
2fab2ef1 819 {
454355ec
AJ
820 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
821 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
822 return ERROR_NOT_ENOUGH_MEMORY;
823 info = (KEY_FULL_INFORMATION *)buf_ptr;
824 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
825 }
826
c6615832
AJ
827 if (status) goto done;
828
829 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
454355ec 830 {
c6615832
AJ
831 status = STATUS_BUFFER_OVERFLOW;
832 }
833 else
834 {
835 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
836 class[info->ClassLength/sizeof(WCHAR)] = 0;
2fab2ef1 837 }
2fab2ef1 838 }
c6615832 839 else status = STATUS_SUCCESS;
454355ec 840
c6615832
AJ
841 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
842 if (subkeys) *subkeys = info->SubKeys;
843 if (max_subkey) *max_subkey = info->MaxNameLen;
844 if (max_class) *max_class = info->MaxClassLen;
845 if (values) *values = info->Values;
846 if (max_value) *max_value = info->MaxValueNameLen;
847 if (max_data) *max_data = info->MaxValueDataLen;
6b6596a1 848 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
454355ec 849
c6615832 850 done:
454355ec
AJ
851 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
852 return RtlNtStatusToDosError( status );
2fab2ef1
AJ
853}
854
855
751c4544 856/******************************************************************************
6a358c40
JH
857 * RegQueryMultipleValuesA [ADVAPI32.@]
858 *
859 * Retrieves the type and data for a list of value names associated with a key.
860 *
861 * PARAMS
862 * hKey [I] Handle to an open key.
863 * val_list [O] Array of VALENT structures that describes the entries.
864 * num_vals [I] Number of elements in val_list.
865 * lpValueBuf [O] Pointer to a buffer that receives the data for each value.
866 * ldwTotsize [I/O] Size of lpValueBuf.
867 *
868 * RETURNS
869 * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
870 * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
871 * bytes.
751c4544 872 */
af183df6 873LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
0542e835 874 LPSTR lpValueBuf, LPDWORD ldwTotsize )
751c4544 875{
411fc5f1 876 unsigned int i;
751c4544
DS
877 DWORD maxBytes = *ldwTotsize;
878 HRESULT status;
879 LPSTR bufptr = lpValueBuf;
880 *ldwTotsize = 0;
881
4301816d 882 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
751c4544
DS
883
884 for(i=0; i < num_vals; ++i)
885 {
886
887 val_list[i].ve_valuelen=0;
888 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
889 if(status != ERROR_SUCCESS)
890 {
891 return status;
892 }
893
894 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
895 {
896 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
257c337c 897 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
751c4544
DS
898 if(status != ERROR_SUCCESS)
899 {
900 return status;
901 }
902
903 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
904
905 bufptr += val_list[i].ve_valuelen;
906 }
907
908 *ldwTotsize += val_list[i].ve_valuelen;
909 }
910 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
911}
912
913
914/******************************************************************************
6a358c40
JH
915 * RegQueryMultipleValuesW [ADVAPI32.@]
916 *
d45811ce 917 * See RegQueryMultipleValuesA.
751c4544 918 */
af183df6 919LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
0542e835 920 LPWSTR lpValueBuf, LPDWORD ldwTotsize )
751c4544 921{
411fc5f1 922 unsigned int i;
751c4544
DS
923 DWORD maxBytes = *ldwTotsize;
924 HRESULT status;
925 LPSTR bufptr = (LPSTR)lpValueBuf;
926 *ldwTotsize = 0;
927
4301816d 928 TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
751c4544
DS
929
930 for(i=0; i < num_vals; ++i)
931 {
932 val_list[i].ve_valuelen=0;
933 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
934 if(status != ERROR_SUCCESS)
935 {
936 return status;
937 }
938
939 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
940 {
941 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
257c337c 942 (LPBYTE)bufptr, &val_list[i].ve_valuelen);
751c4544
DS
943 if(status != ERROR_SUCCESS)
944 {
945 return status;
946 }
947
948 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
949
950 bufptr += val_list[i].ve_valuelen;
951 }
952
953 *ldwTotsize += val_list[i].ve_valuelen;
954 }
955 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
956}
957
2fab2ef1 958/******************************************************************************
6a358c40
JH
959 * RegQueryInfoKeyA [ADVAPI32.@]
960 *
961 * Retrieves information about a registry key.
962 *
963 * PARAMS
964 * hKey [I] Handle to an open key.
965 * lpClass [O] Class string of the key.
966 * lpcClass [I/O] size of lpClass.
967 * lpReserved [I] Reserved; must be NULL.
968 * lpcSubKeys [O] Number of subkeys contained by the key.
969 * lpcMaxSubKeyLen [O] Size of the key's subkey with the longest name.
970 * lpcMaxClassLen [O] Size of the longest string specifying a subkey
971 * class in TCHARS.
972 * lpcValues [O] Number of values associated with the key.
973 * lpcMaxValueNameLen [O] Size of the key's longest value name in TCHARS.
974 * lpcMaxValueLen [O] Longest data component among the key's values
975 * lpcbSecurityDescriptor [O] Size of the key's security descriptor.
d347ebe1 976 * lpftLastWriteTime [O] FILETIME structure that is the last write time.
6a358c40
JH
977 *
978 * RETURNS
979 * Success: ERROR_SUCCESS
980 * Failure: nonzero error code from Winerror.h
2fab2ef1 981 */
af183df6 982LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
0542e835
BJY
983 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
984 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
985 LPDWORD security, FILETIME *modif )
2fab2ef1 986{
454355ec
AJ
987 NTSTATUS status;
988 char buffer[256], *buf_ptr = buffer;
989 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
c6615832 990 DWORD total_size, len;
2fab2ef1 991
4301816d 992 TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
2fab2ef1
AJ
993 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
994
7dbce65b 995 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
f2ef2c2b 996 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2fab2ef1 997
454355ec 998 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
c6615832 999 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
2fab2ef1 1000
454355ec 1001 if (class || class_len)
2fab2ef1 1002 {
454355ec
AJ
1003 /* retry with a dynamically allocated buffer */
1004 while (status == STATUS_BUFFER_OVERFLOW)
1005 {
1006 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1007 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1008 return ERROR_NOT_ENOUGH_MEMORY;
1009 info = (KEY_FULL_INFORMATION *)buf_ptr;
1010 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
1011 }
1012
c6615832
AJ
1013 if (status) goto done;
1014
60fd03d2 1015 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
c6615832 1016 if (class_len)
2fab2ef1 1017 {
c6615832
AJ
1018 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
1019 *class_len = len;
1020 }
1021 if (class && !status)
1022 {
60fd03d2
AJ
1023 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
1024 info->ClassLength );
c6615832 1025 class[len] = 0;
2fab2ef1 1026 }
2fab2ef1 1027 }
c6615832 1028 else status = STATUS_SUCCESS;
454355ec 1029
c6615832
AJ
1030 if (subkeys) *subkeys = info->SubKeys;
1031 if (max_subkey) *max_subkey = info->MaxNameLen;
1032 if (max_class) *max_class = info->MaxClassLen;
1033 if (values) *values = info->Values;
1034 if (max_value) *max_value = info->MaxValueNameLen;
1035 if (max_data) *max_data = info->MaxValueDataLen;
6b6596a1 1036 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
454355ec 1037
c6615832 1038 done:
454355ec
AJ
1039 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1040 return RtlNtStatusToDosError( status );
2fab2ef1
AJ
1041}
1042
1043
1044/******************************************************************************
6a358c40 1045 * RegCloseKey [ADVAPI32.@]
2fab2ef1 1046 *
50ce0844 1047 * Close an open registry key.
2fab2ef1
AJ
1048 *
1049 * PARAMS
6a358c40 1050 * hkey [I] Handle of key to close
2fab2ef1
AJ
1051 *
1052 * RETURNS
6a358c40
JH
1053 * Success: ERROR_SUCCESS
1054 * Failure: Error code
2fab2ef1 1055 */
af183df6 1056LSTATUS WINAPI RegCloseKey( HKEY hkey )
2fab2ef1 1057{
e8d1e2f7 1058 if (!hkey) return ERROR_INVALID_HANDLE;
d5e2b7c8 1059 if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
bcf393a5 1060 return RtlNtStatusToDosError( NtClose( hkey ) );
2fab2ef1
AJ
1061}
1062
1063
1064/******************************************************************************
9b7d1041 1065 * RegDeleteKeyExW [ADVAPI32.@]
2fab2ef1 1066 */
9b7d1041 1067LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD reserved )
2fab2ef1
AJ
1068{
1069 DWORD ret;
bcf393a5 1070 HKEY tmp;
2fab2ef1 1071
a9d5de84
JH
1072 if (!name) return ERROR_INVALID_PARAMETER;
1073
f2ef2c2b
AJ
1074 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1075
9b7d1041
AJ
1076 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1077 if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
da00742a 1078 {
bcf393a5
AJ
1079 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1080 RegCloseKey( tmp );
1081 }
4301816d 1082 TRACE("%s ret=%08x\n", debugstr_w(name), ret);
bcf393a5 1083 return ret;
2fab2ef1
AJ
1084}
1085
1086
1087/******************************************************************************
9b7d1041 1088 * RegDeleteKeyW [ADVAPI32.@]
45d47c42 1089 *
9b7d1041 1090 * See RegDeleteKeyA.
2fab2ef1 1091 */
9b7d1041
AJ
1092LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
1093{
1094 return RegDeleteKeyExW( hkey, name, 0, 0 );
1095}
1096
1097
1098/******************************************************************************
1099 * RegDeleteKeyExA [ADVAPI32.@]
1100 */
1101LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD reserved )
2fab2ef1
AJ
1102{
1103 DWORD ret;
bcf393a5 1104 HKEY tmp;
2fab2ef1 1105
a9d5de84
JH
1106 if (!name) return ERROR_INVALID_PARAMETER;
1107
f2ef2c2b
AJ
1108 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1109
9b7d1041
AJ
1110 access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
1111 if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
da00742a
MM
1112 {
1113 if (!is_version_nt()) /* win95 does recursive key deletes */
1114 {
1115 CHAR name[MAX_PATH];
1116
9591836f 1117 while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
da00742a 1118 {
9b7d1041 1119 if(RegDeleteKeyExA(tmp, name, access, reserved)) /* recurse */
da00742a
MM
1120 break;
1121 }
1122 }
bcf393a5
AJ
1123 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
1124 RegCloseKey( tmp );
1125 }
4301816d 1126 TRACE("%s ret=%08x\n", debugstr_a(name), ret);
bcf393a5 1127 return ret;
2fab2ef1
AJ
1128}
1129
1130
9b7d1041
AJ
1131/******************************************************************************
1132 * RegDeleteKeyA [ADVAPI32.@]
1133 *
1134 * Delete a registry key.
1135 *
1136 * PARAMS
1137 * hkey [I] Handle to parent key containing the key to delete
1138 * name [I] Name of the key user hkey to delete
1139 *
1140 * NOTES
1141 *
1142 * MSDN is wrong when it says that hkey must be opened with the DELETE access
1143 * right. In reality, it opens a new handle with DELETE access.
1144 *
1145 * RETURNS
1146 * Success: ERROR_SUCCESS
1147 * Failure: Error code
1148 */
1149LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
1150{
1151 return RegDeleteKeyExA( hkey, name, 0, 0 );
1152}
1153
1154
2fab2ef1
AJ
1155
1156/******************************************************************************
6a358c40 1157 * RegSetValueExW [ADVAPI32.@]
2fab2ef1 1158 *
50ce0844 1159 * Set the data and contents of a registry value.
2fab2ef1
AJ
1160 *
1161 * PARAMS
6a358c40
JH
1162 * hkey [I] Handle of key to set value for
1163 * name [I] Name of value to set
1164 * reserved [I] Reserved, must be zero
1165 * type [I] Type of the value being set
1166 * data [I] The new contents of the value to set
1167 * count [I] Size of data
2fab2ef1
AJ
1168 *
1169 * RETURNS
6a358c40
JH
1170 * Success: ERROR_SUCCESS
1171 * Failure: Error code
2fab2ef1 1172 */
af183df6 1173LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
0542e835 1174 DWORD type, CONST BYTE *data, DWORD count )
2fab2ef1 1175{
bcf393a5 1176 UNICODE_STRING nameW;
2fab2ef1 1177
bba76fca
AJ
1178 /* no need for version check, not implemented on win9x anyway */
1179 if (count && is_string(type))
2fab2ef1
AJ
1180 {
1181 LPCWSTR str = (LPCWSTR)data;
1182 /* if user forgot to count terminating null, add it (yes NT does this) */
1183 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
1184 count += sizeof(WCHAR);
1185 }
f2ef2c2b 1186 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
a01004d8 1187
bcf393a5
AJ
1188 RtlInitUnicodeString( &nameW, name );
1189 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
2fab2ef1
AJ
1190}
1191
1192
1193/******************************************************************************
6a358c40
JH
1194 * RegSetValueExA [ADVAPI32.@]
1195 *
d45811ce 1196 * See RegSetValueExW.
bba76fca
AJ
1197 *
1198 * NOTES
1199 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
1200 * NT does definitely care (aj)
2fab2ef1 1201 */
af183df6 1202LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
0542e835 1203 CONST BYTE *data, DWORD count )
2fab2ef1 1204{
bcf393a5 1205 ANSI_STRING nameA;
acc41b50 1206 UNICODE_STRING nameW;
bcf393a5
AJ
1207 WCHAR *dataW = NULL;
1208 NTSTATUS status;
2fab2ef1 1209
7dbce65b 1210 if (!is_version_nt()) /* win95 */
918da64a 1211 {
bba76fca
AJ
1212 if (type == REG_SZ)
1213 {
1214 if (!data) return ERROR_INVALID_PARAMETER;
280bcf6e 1215 count = strlen((const char *)data) + 1;
bba76fca 1216 }
918da64a
AJ
1217 }
1218 else if (count && is_string(type))
2fab2ef1
AJ
1219 {
1220 /* if user forgot to count terminating null, add it (yes NT does this) */
1221 if (data[count-1] && !data[count]) count++;
1222 }
a01004d8 1223
f2ef2c2b
AJ
1224 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1225
bcf393a5 1226 if (is_string( type )) /* need to convert to Unicode */
a01004d8 1227 {
60fd03d2 1228 DWORD lenW;
280bcf6e 1229 RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
60fd03d2 1230 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
280bcf6e 1231 RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
60fd03d2 1232 count = lenW;
bcf393a5
AJ
1233 data = (BYTE *)dataW;
1234 }
a01004d8 1235
bcf393a5 1236 RtlInitAnsiString( &nameA, name );
acc41b50 1237 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
bcf393a5 1238 {
acc41b50
AJ
1239 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
1240 RtlFreeUnicodeString( &nameW );
a01004d8 1241 }
5ad7d858 1242 HeapFree( GetProcessHeap(), 0, dataW );
bcf393a5 1243 return RtlNtStatusToDosError( status );
2fab2ef1
AJ
1244}
1245
1246
1247/******************************************************************************
6a358c40
JH
1248 * RegSetValueW [ADVAPI32.@]
1249 *
1250 * Sets the data for the default or unnamed value of a reg key.
1251 *
1252 * PARAMS
1253 * hKey [I] Handle to an open key.
1254 * lpSubKey [I] Name of a subkey of hKey.
1255 * dwType [I] Type of information to store.
1256 * lpData [I] String that contains the data to set for the default value.
628183c2 1257 * cbData [I] Ignored.
6a358c40
JH
1258 *
1259 * RETURNS
1260 * Success: ERROR_SUCCESS
1261 * Failure: nonzero error code from Winerror.h
2fab2ef1 1262 */
af183df6 1263LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
2fab2ef1
AJ
1264{
1265 HKEY subkey = hkey;
1266 DWORD ret;
1267
4301816d 1268 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
2fab2ef1 1269
121be51f 1270 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
2fab2ef1
AJ
1271
1272 if (name && name[0]) /* need to create the subkey */
1273 {
1274 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1275 }
1276
0a258964 1277 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
c7e7df8b 1278 (strlenW( data ) + 1) * sizeof(WCHAR) );
2fab2ef1
AJ
1279 if (subkey != hkey) RegCloseKey( subkey );
1280 return ret;
1281}
1282
1283
1284/******************************************************************************
6a358c40
JH
1285 * RegSetValueA [ADVAPI32.@]
1286 *
d45811ce 1287 * See RegSetValueW.
2fab2ef1 1288 */
af183df6 1289LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
2fab2ef1
AJ
1290{
1291 HKEY subkey = hkey;
1292 DWORD ret;
1293
4301816d 1294 TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
2fab2ef1 1295
121be51f 1296 if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
2fab2ef1
AJ
1297
1298 if (name && name[0]) /* need to create the subkey */
1299 {
1300 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1301 }
0a258964 1302 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
2fab2ef1
AJ
1303 if (subkey != hkey) RegCloseKey( subkey );
1304 return ret;
1305}
1306
1307
1308
1309/******************************************************************************
6a358c40 1310 * RegQueryValueExW [ADVAPI32.@]
2fab2ef1 1311 *
50ce0844 1312 * See RegQueryValueExA.
2fab2ef1 1313 */
af183df6 1314LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
0542e835 1315 LPBYTE data, LPDWORD count )
2fab2ef1 1316{
bcf393a5
AJ
1317 NTSTATUS status;
1318 UNICODE_STRING name_str;
1319 DWORD total_size;
454355ec 1320 char buffer[256], *buf_ptr = buffer;
bcf393a5 1321 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
a010932a 1322 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
2fab2ef1 1323
4301816d 1324 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
8f63a714
FG
1325 hkey, debugstr_w(name), reserved, type, data, count,
1326 (count && data) ? *count : 0 );
2fab2ef1 1327
2c655f5e 1328 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
f2ef2c2b 1329 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2fab2ef1 1330
bcf393a5
AJ
1331 RtlInitUnicodeString( &name_str, name );
1332
1333 if (data) total_size = min( sizeof(buffer), *count + info_size );
bc590e87
RS
1334 else
1335 {
1336 total_size = info_size;
1337 if (count) *count = 0;
1338 }
bcf393a5
AJ
1339
1340 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1341 buffer, total_size, &total_size );
1342 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
a01004d8
AJ
1343
1344 if (data)
2fab2ef1 1345 {
bcf393a5
AJ
1346 /* retry with a dynamically allocated buffer */
1347 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
a01004d8 1348 {
bcf393a5
AJ
1349 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1350 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
454355ec
AJ
1351 return ERROR_NOT_ENOUGH_MEMORY;
1352 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1353 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1354 buf_ptr, total_size, &total_size );
bcf393a5
AJ
1355 }
1356
1357 if (!status)
1358 {
1359 memcpy( data, buf_ptr + info_size, total_size - info_size );
1360 /* if the type is REG_SZ and data is not 0-terminated
1361 * and there is enough space in the buffer NT appends a \0 */
1362 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
a01004d8 1363 {
bcf393a5
AJ
1364 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1365 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
a01004d8
AJ
1366 }
1367 }
454355ec 1368 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
2fab2ef1 1369 }
c6615832 1370 else status = STATUS_SUCCESS;
bcf393a5
AJ
1371
1372 if (type) *type = info->Type;
1373 if (count) *count = total_size - info_size;
1374
1375 done:
454355ec 1376 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
bcf393a5 1377 return RtlNtStatusToDosError(status);
2fab2ef1
AJ
1378}
1379
1380
1381/******************************************************************************
6a358c40 1382 * RegQueryValueExA [ADVAPI32.@]
2fab2ef1 1383 *
50ce0844
JG
1384 * Get the type and contents of a specified value under with a key.
1385 *
1386 * PARAMS
6a358c40
JH
1387 * hkey [I] Handle of the key to query
1388 * name [I] Name of value under hkey to query
1389 * reserved [I] Reserved - must be NULL
1390 * type [O] Destination for the value type, or NULL if not required
1391 * data [O] Destination for the values contents, or NULL if not required
1392 * count [I/O] Size of data, updated with the number of bytes returned
50ce0844
JG
1393 *
1394 * RETURNS
1395 * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1396 * Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1397 * ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1398 * ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1399 *
1400 * NOTES
1401 * MSDN states that if data is too small it is partially filled. In reality
1402 * it remains untouched.
2fab2ef1 1403 */
af183df6 1404LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
0542e835 1405 LPBYTE data, LPDWORD count )
2fab2ef1 1406{
bcf393a5
AJ
1407 NTSTATUS status;
1408 ANSI_STRING nameA;
acc41b50 1409 UNICODE_STRING nameW;
1590b1f7 1410 DWORD total_size, datalen = 0;
454355ec 1411 char buffer[256], *buf_ptr = buffer;
bcf393a5 1412 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
a010932a 1413 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
2fab2ef1 1414
4301816d 1415 TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
2fab2ef1
AJ
1416 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1417
2c655f5e 1418 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
f2ef2c2b 1419 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2fab2ef1 1420
1590b1f7 1421 if (count) datalen = *count;
bc590e87
RS
1422 if (!data && count) *count = 0;
1423
1424 /* this matches Win9x behaviour - NT sets *type to a random value */
1425 if (type) *type = REG_NONE;
1426
bcf393a5 1427 RtlInitAnsiString( &nameA, name );
acc41b50 1428 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
454355ec 1429 return RtlNtStatusToDosError(status);
a01004d8 1430
acc41b50
AJ
1431 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1432 buffer, sizeof(buffer), &total_size );
bcf393a5 1433 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
a01004d8 1434
bcf393a5
AJ
1435 /* we need to fetch the contents for a string type even if not requested,
1436 * because we need to compute the length of the ASCII string. */
1437 if (data || is_string(info->Type))
2fab2ef1 1438 {
bcf393a5
AJ
1439 /* retry with a dynamically allocated buffer */
1440 while (status == STATUS_BUFFER_OVERFLOW)
a01004d8 1441 {
bcf393a5
AJ
1442 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1443 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
454355ec 1444 {
bcf393a5 1445 status = STATUS_NO_MEMORY;
454355ec
AJ
1446 goto done;
1447 }
1448 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
acc41b50
AJ
1449 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
1450 buf_ptr, total_size, &total_size );
bcf393a5
AJ
1451 }
1452
c6615832
AJ
1453 if (status) goto done;
1454
1455 if (is_string(info->Type))
bcf393a5 1456 {
60fd03d2
AJ
1457 DWORD len;
1458
1459 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1460 total_size - info_size );
c6615832 1461 if (data && len)
a01004d8 1462 {
1590b1f7 1463 if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
c6615832 1464 else
bcf393a5 1465 {
280bcf6e 1466 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
60fd03d2 1467 total_size - info_size );
c6615832
AJ
1468 /* if the type is REG_SZ and data is not 0-terminated
1469 * and there is enough space in the buffer NT appends a \0 */
1590b1f7 1470 if (len < datalen && data[len-1]) data[len] = 0;
bcf393a5 1471 }
57f05e19 1472 }
c6615832
AJ
1473 total_size = len + info_size;
1474 }
1475 else if (data)
1476 {
1590b1f7 1477 if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
c6615832 1478 else memcpy( data, buf_ptr + info_size, total_size - info_size );
a01004d8 1479 }
2fab2ef1 1480 }
c6615832 1481 else status = STATUS_SUCCESS;
a01004d8 1482
bcf393a5
AJ
1483 if (type) *type = info->Type;
1484 if (count) *count = total_size - info_size;
bcf393a5
AJ
1485
1486 done:
454355ec 1487 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
acc41b50 1488 RtlFreeUnicodeString( &nameW );
bcf393a5 1489 return RtlNtStatusToDosError(status);
2fab2ef1
AJ
1490}
1491
1492
1493/******************************************************************************
6a358c40
JH
1494 * RegQueryValueW [ADVAPI32.@]
1495 *
1496 * Retrieves the data associated with the default or unnamed value of a key.
1497 *
1498 * PARAMS
bbde53fb
AJ
1499 * hkey [I] Handle to an open key.
1500 * name [I] Name of the subkey of hKey.
1501 * data [O] Receives the string associated with the default value
6a358c40 1502 * of the key.
bbde53fb 1503 * count [I/O] Size of lpValue in bytes.
6a358c40
JH
1504 *
1505 * RETURNS
1506 * Success: ERROR_SUCCESS
1507 * Failure: nonzero error code from Winerror.h
2fab2ef1 1508 */
af183df6 1509LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
2fab2ef1
AJ
1510{
1511 DWORD ret;
1512 HKEY subkey = hkey;
1513
4301816d 1514 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
2fab2ef1
AJ
1515
1516 if (name && name[0])
1517 {
1518 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1519 }
280bcf6e 1520 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
2fab2ef1
AJ
1521 if (subkey != hkey) RegCloseKey( subkey );
1522 if (ret == ERROR_FILE_NOT_FOUND)
1523 {
1524 /* return empty string if default value not found */
1525 if (data) *data = 0;
bbde53fb 1526 if (count) *count = sizeof(WCHAR);
2fab2ef1
AJ
1527 ret = ERROR_SUCCESS;
1528 }
1529 return ret;
1530}
1531
1532
1533/******************************************************************************
6a358c40
JH
1534 * RegQueryValueA [ADVAPI32.@]
1535 *
d45811ce 1536 * See RegQueryValueW.
2fab2ef1 1537 */
af183df6 1538LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
2fab2ef1
AJ
1539{
1540 DWORD ret;
1541 HKEY subkey = hkey;
1542
4301816d 1543 TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
2fab2ef1
AJ
1544
1545 if (name && name[0])
1546 {
1547 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1548 }
280bcf6e 1549 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
2fab2ef1
AJ
1550 if (subkey != hkey) RegCloseKey( subkey );
1551 if (ret == ERROR_FILE_NOT_FOUND)
1552 {
1553 /* return empty string if default value not found */
1554 if (data) *data = 0;
1555 if (count) *count = 1;
1556 ret = ERROR_SUCCESS;
1557 }
1558 return ret;
1559}
1560
1561
48533ae9
FN
1562/******************************************************************************
1563 * ADVAPI_ApplyRestrictions [internal]
1564 *
1565 * Helper function for RegGetValueA/W.
1566 */
2730fe6d
JH
1567static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
1568 DWORD cbData, PLONG ret )
48533ae9
FN
1569{
1570 /* Check if the type is restricted by the passed flags */
1571 if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1572 {
1573 DWORD dwMask = 0;
1574
1575 switch (dwType)
1576 {
1577 case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1578 case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1579 case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1580 case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1581 case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1582 case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1583 case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1584 }
1585
1586 if (dwFlags & dwMask)
1587 {
1588 /* Type is not restricted, check for size mismatch */
1589 if (dwType == REG_BINARY)
1590 {
1591 DWORD cbExpect = 0;
1592
96ca7087 1593 if ((dwFlags & RRF_RT_ANY) == RRF_RT_DWORD)
48533ae9 1594 cbExpect = 4;
96ca7087 1595 else if ((dwFlags & RRF_RT_ANY) == RRF_RT_QWORD)
48533ae9
FN
1596 cbExpect = 8;
1597
1598 if (cbExpect && cbData != cbExpect)
1599 *ret = ERROR_DATATYPE_MISMATCH;
1600 }
1601 }
1602 else *ret = ERROR_UNSUPPORTED_TYPE;
1603 }
1604}
1605
1606
1607/******************************************************************************
1608 * RegGetValueW [ADVAPI32.@]
1609 *
c47c6483
FG
1610 * Retrieves the type and data for a value name associated with a key,
1611 * optionally expanding its content and restricting its type.
48533ae9
FN
1612 *
1613 * PARAMS
1614 * hKey [I] Handle to an open key.
1615 * pszSubKey [I] Name of the subkey of hKey.
1616 * pszValue [I] Name of value under hKey/szSubKey to query.
1617 * dwFlags [I] Flags restricting the value type to retrieve.
1618 * pdwType [O] Destination for the values type, may be NULL.
1619 * pvData [O] Destination for the values content, may be NULL.
c47c6483
FG
1620 * pcbData [I/O] Size of pvData, updated with the size in bytes required to
1621 * retrieve the whole content, including the trailing '\0'
1622 * for strings.
48533ae9
FN
1623 *
1624 * RETURNS
1625 * Success: ERROR_SUCCESS
1626 * Failure: nonzero error code from Winerror.h
1627 *
1628 * NOTES
c47c6483
FG
1629 * - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
1630 * expanded and pdwType is set to REG_SZ instead.
48533ae9
FN
1631 * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
1632 * without RRF_NOEXPAND is thus not allowed.
9a7dc159
MK
1633 * An exception is the case where RRF_RT_ANY is specified, because then
1634 * RRF_NOEXPAND is allowed.
48533ae9 1635 */
af183df6 1636LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
48533ae9
FN
1637 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1638 LPDWORD pcbData )
1639{
1640 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1641 PVOID pvBuf = NULL;
1642 LONG ret;
1643
4301816d 1644 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
48533ae9
FN
1645 hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1646 pvData, pcbData, cbData);
1647
1da7a32b
FG
1648 if (pvData && !pcbData)
1649 return ERROR_INVALID_PARAMETER;
9a7dc159
MK
1650 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1651 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
48533ae9
FN
1652 return ERROR_INVALID_PARAMETER;
1653
1654 if (pszSubKey && pszSubKey[0])
1655 {
1656 ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1657 if (ret != ERROR_SUCCESS) return ret;
1658 }
1659
1660 ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1661
1662 /* If we are going to expand we need to read in the whole the value even
1663 * if the passed buffer was too small as the expanded string might be
1664 * smaller than the unexpanded one and could fit into cbData bytes. */
1665 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1da7a32b 1666 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
48533ae9
FN
1667 {
1668 do {
a8752003 1669 HeapFree(GetProcessHeap(), 0, pvBuf);
48533ae9
FN
1670
1671 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1672 if (!pvBuf)
1673 {
1674 ret = ERROR_NOT_ENOUGH_MEMORY;
1675 break;
1676 }
1677
1da7a32b 1678 if (ret == ERROR_MORE_DATA || !pvData)
48533ae9
FN
1679 ret = RegQueryValueExW(hKey, pszValue, NULL,
1680 &dwType, pvBuf, &cbData);
1681 else
1682 {
1683 /* Even if cbData was large enough we have to copy the
1684 * string since ExpandEnvironmentStrings can't handle
1685 * overlapping buffers. */
1686 CopyMemory(pvBuf, pvData, cbData);
1687 }
1688
1689 /* Both the type or the value itself could have been modified in
1690 * between so we have to keep retrying until the buffer is large
1691 * enough or we no longer have to expand the value. */
1692 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1693
1694 if (ret == ERROR_SUCCESS)
1695 {
1da7a32b 1696 /* Recheck dwType in case it changed since the first call */
48533ae9
FN
1697 if (dwType == REG_EXPAND_SZ)
1698 {
1699 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
d9a06b23 1700 pcbData ? *pcbData : 0) * sizeof(WCHAR);
48533ae9 1701 dwType = REG_SZ;
c47c6483 1702 if(pvData && pcbData && cbData > *pcbData)
48533ae9
FN
1703 ret = ERROR_MORE_DATA;
1704 }
1da7a32b 1705 else if (pvData)
48533ae9
FN
1706 CopyMemory(pvData, pvBuf, *pcbData);
1707 }
1708
a8752003 1709 HeapFree(GetProcessHeap(), 0, pvBuf);
48533ae9
FN
1710 }
1711
1712 if (pszSubKey && pszSubKey[0])
1713 RegCloseKey(hKey);
1714
1715 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1716
1da7a32b 1717 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
48533ae9
FN
1718 ZeroMemory(pvData, *pcbData);
1719
1720 if (pdwType) *pdwType = dwType;
1721 if (pcbData) *pcbData = cbData;
1722
1723 return ret;
1724}
1725
1726
1727/******************************************************************************
1728 * RegGetValueA [ADVAPI32.@]
1729 *
1730 * See RegGetValueW.
1731 */
af183df6 1732LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
48533ae9
FN
1733 DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1734 LPDWORD pcbData )
1735{
1736 DWORD dwType, cbData = pcbData ? *pcbData : 0;
1737 PVOID pvBuf = NULL;
1738 LONG ret;
1739
4301816d 1740 TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n",
48533ae9
FN
1741 hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1742 cbData);
1743
1da7a32b
FG
1744 if (pvData && !pcbData)
1745 return ERROR_INVALID_PARAMETER;
9a7dc159
MK
1746 if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) &&
1747 ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY))
48533ae9
FN
1748 return ERROR_INVALID_PARAMETER;
1749
1750 if (pszSubKey && pszSubKey[0])
1751 {
1752 ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1753 if (ret != ERROR_SUCCESS) return ret;
1754 }
1755
1756 ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1757
1758 /* If we are going to expand we need to read in the whole the value even
1759 * if the passed buffer was too small as the expanded string might be
1760 * smaller than the unexpanded one and could fit into cbData bytes. */
1761 if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1da7a32b 1762 dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
48533ae9
FN
1763 {
1764 do {
a8752003 1765 HeapFree(GetProcessHeap(), 0, pvBuf);
48533ae9
FN
1766
1767 pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1768 if (!pvBuf)
1769 {
1770 ret = ERROR_NOT_ENOUGH_MEMORY;
1771 break;
1772 }
1773
1da7a32b 1774 if (ret == ERROR_MORE_DATA || !pvData)
48533ae9
FN
1775 ret = RegQueryValueExA(hKey, pszValue, NULL,
1776 &dwType, pvBuf, &cbData);
1777 else
1778 {
1779 /* Even if cbData was large enough we have to copy the
1780 * string since ExpandEnvironmentStrings can't handle
1781 * overlapping buffers. */
1782 CopyMemory(pvBuf, pvData, cbData);
1783 }
1784
1785 /* Both the type or the value itself could have been modified in
1786 * between so we have to keep retrying until the buffer is large
1787 * enough or we no longer have to expand the value. */
1788 } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1789
1790 if (ret == ERROR_SUCCESS)
1791 {
1da7a32b 1792 /* Recheck dwType in case it changed since the first call */
48533ae9
FN
1793 if (dwType == REG_EXPAND_SZ)
1794 {
1795 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1796 pcbData ? *pcbData : 0);
1797 dwType = REG_SZ;
c47c6483 1798 if(pvData && pcbData && cbData > *pcbData)
48533ae9
FN
1799 ret = ERROR_MORE_DATA;
1800 }
1da7a32b 1801 else if (pvData)
48533ae9
FN
1802 CopyMemory(pvData, pvBuf, *pcbData);
1803 }
1804
a8752003 1805 HeapFree(GetProcessHeap(), 0, pvBuf);
48533ae9
FN
1806 }
1807
1808 if (pszSubKey && pszSubKey[0])
1809 RegCloseKey(hKey);
1810
1811 ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1812
1da7a32b 1813 if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
48533ae9
FN
1814 ZeroMemory(pvData, *pcbData);
1815
1816 if (pdwType) *pdwType = dwType;
1817 if (pcbData) *pcbData = cbData;
1818
1819 return ret;
1820}
1821
1822
2fab2ef1 1823/******************************************************************************
6a358c40 1824 * RegEnumValueW [ADVAPI32.@]
2fab2ef1 1825 *
d45811ce
MA
1826 * Enumerates the values for the specified open registry key.
1827 *
2fab2ef1 1828 * PARAMS
6a358c40
JH
1829 * hkey [I] Handle to key to query
1830 * index [I] Index of value to query
1831 * value [O] Value string
1832 * val_count [I/O] Size of value buffer (in wchars)
1833 * reserved [I] Reserved
1834 * type [O] Type code
1835 * data [O] Value data
1836 * count [I/O] Size of data buffer (in bytes)
1837 *
1838 * RETURNS
1839 * Success: ERROR_SUCCESS
1840 * Failure: nonzero error code from Winerror.h
2fab2ef1
AJ
1841 */
1842
af183df6 1843LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
0542e835 1844 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
2fab2ef1 1845{
0b6a79c9
AJ
1846 NTSTATUS status;
1847 DWORD total_size;
1848 char buffer[256], *buf_ptr = buffer;
1849 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
a010932a 1850 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
2fab2ef1 1851
4301816d 1852 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
2fab2ef1
AJ
1853 hkey, index, value, val_count, reserved, type, data, count );
1854
1855 /* NT only checks count, not val_count */
2c655f5e 1856 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
f2ef2c2b 1857 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2fab2ef1 1858
0b6a79c9
AJ
1859 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1860 if (data) total_size += *count;
1861 total_size = min( sizeof(buffer), total_size );
2fab2ef1 1862
0b6a79c9
AJ
1863 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1864 buffer, total_size, &total_size );
1865 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
2fab2ef1 1866
0b6a79c9 1867 if (value || data)
a01004d8 1868 {
0b6a79c9
AJ
1869 /* retry with a dynamically allocated buffer */
1870 while (status == STATUS_BUFFER_OVERFLOW)
1871 {
1872 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1873 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1874 return ERROR_NOT_ENOUGH_MEMORY;
1875 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1876 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1877 buf_ptr, total_size, &total_size );
1878 }
1879
1880 if (status) goto done;
1881
1882 if (value)
1883 {
1884 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1885 {
1886 status = STATUS_BUFFER_OVERFLOW;
c1dddbea 1887 goto overflow;
0b6a79c9
AJ
1888 }
1889 memcpy( value, info->Name, info->NameLength );
1890 *val_count = info->NameLength / sizeof(WCHAR);
1891 value[*val_count] = 0;
1892 }
1893
1894 if (data)
a01004d8 1895 {
0b6a79c9 1896 if (total_size - info->DataOffset > *count)
a01004d8 1897 {
0b6a79c9 1898 status = STATUS_BUFFER_OVERFLOW;
c1dddbea 1899 goto overflow;
0b6a79c9
AJ
1900 }
1901 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1902 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1903 {
1904 /* if the type is REG_SZ and data is not 0-terminated
1905 * and there is enough space in the buffer NT appends a \0 */
1906 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1907 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
a01004d8
AJ
1908 }
1909 }
a01004d8 1910 }
c6615832 1911 else status = STATUS_SUCCESS;
0b6a79c9 1912
c1dddbea 1913 overflow:
0b6a79c9
AJ
1914 if (type) *type = info->Type;
1915 if (count) *count = info->DataLength;
1916
1917 done:
1918 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1919 return RtlNtStatusToDosError(status);
2fab2ef1
AJ
1920}
1921
1922
1923/******************************************************************************
6a358c40
JH
1924 * RegEnumValueA [ADVAPI32.@]
1925 *
d45811ce 1926 * See RegEnumValueW.
2fab2ef1 1927 */
af183df6 1928LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
0542e835 1929 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
2fab2ef1 1930{
0b6a79c9
AJ
1931 NTSTATUS status;
1932 DWORD total_size;
1933 char buffer[256], *buf_ptr = buffer;
1934 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
a010932a 1935 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
2fab2ef1 1936
4301816d 1937 TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
2fab2ef1
AJ
1938 hkey, index, value, val_count, reserved, type, data, count );
1939
1940 /* NT only checks count, not val_count */
2c655f5e 1941 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
f2ef2c2b 1942 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2fab2ef1 1943
0b6a79c9
AJ
1944 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1945 if (data) total_size += *count;
1946 total_size = min( sizeof(buffer), total_size );
2fab2ef1 1947
0b6a79c9
AJ
1948 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1949 buffer, total_size, &total_size );
1950 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
a01004d8 1951
0b6a79c9
AJ
1952 /* we need to fetch the contents for a string type even if not requested,
1953 * because we need to compute the length of the ASCII string. */
1954 if (value || data || is_string(info->Type))
a01004d8 1955 {
0b6a79c9
AJ
1956 /* retry with a dynamically allocated buffer */
1957 while (status == STATUS_BUFFER_OVERFLOW)
a01004d8 1958 {
0b6a79c9
AJ
1959 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1960 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1961 return ERROR_NOT_ENOUGH_MEMORY;
1962 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1963 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1964 buf_ptr, total_size, &total_size );
1965 }
1966
1967 if (status) goto done;
1968
0b6a79c9
AJ
1969 if (is_string(info->Type))
1970 {
60fd03d2
AJ
1971 DWORD len;
1972 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1973 total_size - info->DataOffset );
0b6a79c9
AJ
1974 if (data && len)
1975 {
c1dddbea
AJ
1976 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1977 else
0b6a79c9 1978 {
280bcf6e 1979 RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
c1dddbea
AJ
1980 total_size - info->DataOffset );
1981 /* if the type is REG_SZ and data is not 0-terminated
1982 * and there is enough space in the buffer NT appends a \0 */
1983 if (len < *count && data[len-1]) data[len] = 0;
0b6a79c9 1984 }
a01004d8 1985 }
0b6a79c9
AJ
1986 info->DataLength = len;
1987 }
1988 else if (data)
1989 {
1990 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1991 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
a01004d8 1992 }
c1dddbea
AJ
1993
1994 if (value && !status)
1995 {
1996 DWORD len;
1997
1998 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1999 if (len >= *val_count)
2000 {
2001 status = STATUS_BUFFER_OVERFLOW;
2002 if (*val_count)
2003 {
2004 len = *val_count - 1;
2005 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2006 value[len] = 0;
2007 }
2008 }
2009 else
2010 {
2011 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
2012 value[len] = 0;
2013 *val_count = len;
2014 }
2015 }
a01004d8 2016 }
c6615832 2017 else status = STATUS_SUCCESS;
a01004d8 2018
0b6a79c9
AJ
2019 if (type) *type = info->Type;
2020 if (count) *count = info->DataLength;
2021
2022 done:
2023 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
2024 return RtlNtStatusToDosError(status);
2fab2ef1
AJ
2025}
2026
2027
2028
2029/******************************************************************************
6a358c40 2030 * RegDeleteValueW [ADVAPI32.@]
2fab2ef1 2031 *
cd4234aa 2032 * See RegDeleteValueA.
2fab2ef1 2033 */
af183df6 2034LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
2fab2ef1 2035{
bcf393a5 2036 UNICODE_STRING nameW;
f2ef2c2b
AJ
2037
2038 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2039
bcf393a5
AJ
2040 RtlInitUnicodeString( &nameW, name );
2041 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
2fab2ef1
AJ
2042}
2043
2044
2045/******************************************************************************
6a358c40 2046 * RegDeleteValueA [ADVAPI32.@]
cd4234aa
JG
2047 *
2048 * Delete a value from the registry.
2049 *
2050 * PARAMS
2051 * hkey [I] Registry handle of the key holding the value
2052 * name [I] Name of the value under hkey to delete
2053 *
2054 * RETURNS
6a358c40
JH
2055 * Success: ERROR_SUCCESS
2056 * Failure: nonzero error code from Winerror.h
2fab2ef1 2057 */
af183df6 2058LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
2fab2ef1 2059{
acc41b50
AJ
2060 ANSI_STRING nameA;
2061 UNICODE_STRING nameW;
bcf393a5 2062 NTSTATUS status;
2fab2ef1 2063
f2ef2c2b
AJ
2064 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2065
bcf393a5 2066 RtlInitAnsiString( &nameA, name );
acc41b50
AJ
2067 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
2068 {
2069 status = NtDeleteValueKey( hkey, &nameW );
2070 RtlFreeUnicodeString( &nameW );
2071 }
bcf393a5 2072 return RtlNtStatusToDosError( status );
2fab2ef1
AJ
2073}
2074
2075
2076/******************************************************************************
6a358c40 2077 * RegLoadKeyW [ADVAPI32.@]
2fab2ef1 2078 *
ec350525
MA
2079 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
2080 * registration information from a specified file into that subkey.
2081 *
2fab2ef1 2082 * PARAMS
6a358c40
JH
2083 * hkey [I] Handle of open key
2084 * subkey [I] Address of name of subkey
2085 * filename [I] Address of filename for registry information
2086 *
2087 * RETURNS
30e44c85 2088 * Success: ERROR_SUCCESS
6a358c40 2089 * Failure: nonzero error code from Winerror.h
2fab2ef1 2090 */
af183df6 2091LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
2fab2ef1 2092{
580ded65
JH
2093 OBJECT_ATTRIBUTES destkey, file;
2094 UNICODE_STRING subkeyW, filenameW;
4dfd319d 2095 NTSTATUS status;
580ded65
JH
2096
2097 if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
2098
2099 destkey.Length = sizeof(destkey);
2100 destkey.RootDirectory = hkey; /* root key: HKLM or HKU */
2101 destkey.ObjectName = &subkeyW; /* name of the key */
2102 destkey.Attributes = 0;
2103 destkey.SecurityDescriptor = NULL;
2104 destkey.SecurityQualityOfService = NULL;
2105 RtlInitUnicodeString(&subkeyW, subkey);
2106
2107 file.Length = sizeof(file);
2108 file.RootDirectory = NULL;
2109 file.ObjectName = &filenameW; /* file containing the hive */
2110 file.Attributes = OBJ_CASE_INSENSITIVE;
2111 file.SecurityDescriptor = NULL;
2112 file.SecurityQualityOfService = NULL;
2113 RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
2114
4dfd319d
EP
2115 status = NtLoadKey(&destkey, &file);
2116 RtlFreeUnicodeString(&filenameW);
2117 return RtlNtStatusToDosError( status );
2fab2ef1
AJ
2118}
2119
2120
2121/******************************************************************************
6a358c40
JH
2122 * RegLoadKeyA [ADVAPI32.@]
2123 *
d45811ce 2124 * See RegLoadKeyW.
2fab2ef1 2125 */
af183df6 2126LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
2fab2ef1 2127{
580ded65
JH
2128 UNICODE_STRING subkeyW, filenameW;
2129 STRING subkeyA, filenameA;
2130 NTSTATUS status;
4dfd319d 2131 LONG ret;
57f05e19 2132
580ded65
JH
2133 RtlInitAnsiString(&subkeyA, subkey);
2134 RtlInitAnsiString(&filenameA, filename);
57f05e19 2135
4dfd319d
EP
2136 RtlInitUnicodeString(&subkeyW, NULL);
2137 RtlInitUnicodeString(&filenameW, NULL);
2138 if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
2139 !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
2140 {
2141 ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
2142 }
2143 else ret = RtlNtStatusToDosError(status);
2144 RtlFreeUnicodeString(&subkeyW);
2145 RtlFreeUnicodeString(&filenameW);
2146 return ret;
2fab2ef1
AJ
2147}
2148
2149
2150/******************************************************************************
6a358c40 2151 * RegSaveKeyW [ADVAPI32.@]
2fab2ef1 2152 *
ec350525
MA
2153 * Save a key and all of its subkeys and values to a new file in the standard format.
2154 *
2fab2ef1 2155 * PARAMS
6a358c40
JH
2156 * hkey [I] Handle of key where save begins
2157 * lpFile [I] Address of filename to save to
2158 * sa [I] Address of security structure
2159 *
2160 * RETURNS
2161 * Success: ERROR_SUCCESS
2162 * Failure: nonzero error code from Winerror.h
2fab2ef1 2163 */
af183df6 2164LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
2fab2ef1 2165{
4550b8b7
TL
2166 static const WCHAR format[] =
2167 {'r','e','g','%','0','4','x','.','t','m','p',0};
2168 WCHAR buffer[MAX_PATH];
2fab2ef1 2169 int count = 0;
4550b8b7 2170 LPWSTR nameW;
2fab2ef1 2171 DWORD ret, err;
7375597f 2172 HANDLE handle;
2fab2ef1 2173
4550b8b7 2174 TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2fab2ef1
AJ
2175
2176 if (!file || !*file) return ERROR_INVALID_PARAMETER;
f2ef2c2b 2177 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2fab2ef1
AJ
2178
2179 err = GetLastError();
4550b8b7
TL
2180 GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
2181
2fab2ef1
AJ
2182 for (;;)
2183 {
4550b8b7
TL
2184 snprintfW( nameW, 16, format, count++ );
2185 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
da2b6a9f 2186 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2fab2ef1 2187 if (handle != INVALID_HANDLE_VALUE) break;
3d73173f 2188 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
6297451d
AM
2189
2190 /* Something gone haywire ? Please report if this happens abnormally */
2191 if (count >= 100)
4550b8b7 2192 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);
2fab2ef1
AJ
2193 }
2194
f74b0adb 2195 ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
57f05e19 2196
2fab2ef1
AJ
2197 CloseHandle( handle );
2198 if (!ret)
2199 {
4550b8b7 2200 if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2fab2ef1 2201 {
4550b8b7
TL
2202 ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
2203 debugstr_w(file) );
2fab2ef1
AJ
2204 ret = GetLastError();
2205 }
2206 }
4550b8b7 2207 if (ret) DeleteFileW( buffer );
2fab2ef1
AJ
2208
2209done:
2210 SetLastError( err ); /* restore last error code */
2211 return ret;
2212}
2213
2214
2215/******************************************************************************
6a358c40
JH
2216 * RegSaveKeyA [ADVAPI32.@]
2217 *
d45811ce 2218 * See RegSaveKeyW.
2fab2ef1 2219 */
af183df6 2220LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2fab2ef1 2221{
4550b8b7
TL
2222 UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
2223 NTSTATUS status;
2224 STRING fileA;
2225
2226 RtlInitAnsiString(&fileA, file);
2227 if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2228 return RtlNtStatusToDosError( status );
2229 return RegSaveKeyW(hkey, fileW->Buffer, sa);
2fab2ef1 2230}
5ce2329a
AJ
2231
2232
2233/******************************************************************************
d0a41774 2234 * RegRestoreKeyW [ADVAPI32.@]
5ce2329a 2235 *
ec350525
MA
2236 * Read the registry information from a file and copy it over a key.
2237 *
5ce2329a 2238 * PARAMS
6a358c40
JH
2239 * hkey [I] Handle of key where restore begins
2240 * lpFile [I] Address of filename containing saved tree
2241 * dwFlags [I] Optional flags
2242 *
2243 * RETURNS
2244 * Success: ERROR_SUCCESS
2245 * Failure: nonzero error code from Winerror.h
5ce2329a 2246 */
af183df6 2247LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
5ce2329a 2248{
4301816d 2249 TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
5ce2329a
AJ
2250
2251 /* It seems to do this check before the hkey check */
2252 if (!lpFile || !*lpFile)
2253 return ERROR_INVALID_PARAMETER;
2254
4301816d 2255 FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
5ce2329a
AJ
2256
2257 /* Check for file existence */
2258
2259 return ERROR_SUCCESS;
2260}
2261
2262
2263/******************************************************************************
d0a41774 2264 * RegRestoreKeyA [ADVAPI32.@]
6a358c40 2265 *
d45811ce 2266 * See RegRestoreKeyW.
5ce2329a 2267 */
af183df6 2268LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
5ce2329a 2269{
6f2a071d
MD
2270 UNICODE_STRING lpFileW;
2271 LONG ret;
2272
2273 RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2274 ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2275 RtlFreeUnicodeString( &lpFileW );
5ce2329a
AJ
2276 return ret;
2277}
2278
2279
2280/******************************************************************************
d0a41774 2281 * RegUnLoadKeyW [ADVAPI32.@]
5ce2329a 2282 *
ec350525
MA
2283 * Unload a registry key and its subkeys from the registry.
2284 *
5ce2329a 2285 * PARAMS
6a358c40
JH
2286 * hkey [I] Handle of open key
2287 * lpSubKey [I] Address of name of subkey to unload
2288 *
2289 * RETURNS
2290 * Success: ERROR_SUCCESS
2291 * Failure: nonzero error code from Winerror.h
5ce2329a 2292 */
af183df6 2293LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
5ce2329a 2294{
5ac945c0
MM
2295 DWORD ret;
2296 HKEY shkey;
fdff5c3a
BJY
2297 OBJECT_ATTRIBUTES attr;
2298 UNICODE_STRING subkey;
5ac945c0
MM
2299
2300 TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2301
2302 ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2303 if( ret )
2304 return ERROR_INVALID_PARAMETER;
2305
fdff5c3a
BJY
2306 RtlInitUnicodeString(&subkey, lpSubKey);
2307 InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
2308 ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
f74b0adb 2309
5ac945c0
MM
2310 RegCloseKey(shkey);
2311
2312 return ret;
5ce2329a
AJ
2313}
2314
2315
2316/******************************************************************************
d0a41774 2317 * RegUnLoadKeyA [ADVAPI32.@]
6a358c40 2318 *
d45811ce 2319 * See RegUnLoadKeyW.
5ce2329a 2320 */
af183df6 2321LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
5ce2329a 2322{
6f2a071d
MD
2323 UNICODE_STRING lpSubKeyW;
2324 LONG ret;
2325
2326 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2327 ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2328 RtlFreeUnicodeString( &lpSubKeyW );
5ce2329a
AJ
2329 return ret;
2330}
2331
2332
2333/******************************************************************************
d0a41774 2334 * RegReplaceKeyW [ADVAPI32.@]
5ce2329a 2335 *
ec350525
MA
2336 * Replace the file backing a registry key and all its subkeys with another file.
2337 *
5ce2329a 2338 * PARAMS
6a358c40
JH
2339 * hkey [I] Handle of open key
2340 * lpSubKey [I] Address of name of subkey
2341 * lpNewFile [I] Address of filename for file with new data
2342 * lpOldFile [I] Address of filename for backup file
2343 *
2344 * RETURNS
2345 * Success: ERROR_SUCCESS
2346 * Failure: nonzero error code from Winerror.h
5ce2329a 2347 */
af183df6 2348LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
5ce2329a
AJ
2349 LPCWSTR lpOldFile )
2350{
cbacde52 2351 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
5ce2329a
AJ
2352 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2353 return ERROR_SUCCESS;
2354}
2355
2356
2357/******************************************************************************
d0a41774 2358 * RegReplaceKeyA [ADVAPI32.@]
6a358c40 2359 *
d45811ce 2360 * See RegReplaceKeyW.
5ce2329a 2361 */
af183df6 2362LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
5ce2329a
AJ
2363 LPCSTR lpOldFile )
2364{
6f2a071d
MD
2365 UNICODE_STRING lpSubKeyW;
2366 UNICODE_STRING lpNewFileW;
2367 UNICODE_STRING lpOldFileW;
2368 LONG ret;
2369
2370 RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2371 RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2372 RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2373 ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2374 RtlFreeUnicodeString( &lpOldFileW );
2375 RtlFreeUnicodeString( &lpNewFileW );
2376 RtlFreeUnicodeString( &lpSubKeyW );
5ce2329a
AJ
2377 return ret;
2378}
2379
2380
2381/******************************************************************************
d0a41774 2382 * RegSetKeySecurity [ADVAPI32.@]
5ce2329a 2383 *
ec350525
MA
2384 * Set the security of an open registry key.
2385 *
5ce2329a 2386 * PARAMS
6a358c40
JH
2387 * hkey [I] Open handle of key to set
2388 * SecurityInfo [I] Descriptor contents
2389 * pSecurityDesc [I] Address of descriptor for key
2390 *
2391 * RETURNS
2392 * Success: ERROR_SUCCESS
2393 * Failure: nonzero error code from Winerror.h
5ce2329a 2394 */
af183df6 2395LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
5ce2329a
AJ
2396 PSECURITY_DESCRIPTOR pSecurityDesc )
2397{
4301816d 2398 TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
5ce2329a
AJ
2399
2400 /* It seems to perform this check before the hkey check */
2401 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2402 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2403 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2404 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2405 /* Param OK */
2406 } else
2407 return ERROR_INVALID_PARAMETER;
2408
2409 if (!pSecurityDesc)
2410 return ERROR_INVALID_PARAMETER;
2411
4301816d 2412 FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
5ce2329a
AJ
2413
2414 return ERROR_SUCCESS;
2415}
2416
2417
2418/******************************************************************************
d0a41774 2419 * RegGetKeySecurity [ADVAPI32.@]
50ce0844
JG
2420 *
2421 * Get a copy of the security descriptor for a given registry key.
5ce2329a
AJ
2422 *
2423 * PARAMS
6a358c40
JH
2424 * hkey [I] Open handle of key to set
2425 * SecurityInformation [I] Descriptor contents
2426 * pSecurityDescriptor [O] Address of descriptor for key
2427 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
5ce2329a
AJ
2428 *
2429 * RETURNS
6a358c40
JH
2430 * Success: ERROR_SUCCESS
2431 * Failure: Error code
5ce2329a 2432 */
af183df6 2433LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
5ce2329a
AJ
2434 PSECURITY_DESCRIPTOR pSecurityDescriptor,
2435 LPDWORD lpcbSecurityDescriptor )
2436{
4301816d 2437 TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
7579145a 2438 *lpcbSecurityDescriptor);
5ce2329a 2439
81e7d69d 2440 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
79313d37 2441
81e7d69d
JL
2442 return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
2443 SecurityInformation, pSecurityDescriptor,
2444 *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
5ce2329a
AJ
2445}
2446
2447
2448/******************************************************************************
d0a41774 2449 * RegFlushKey [ADVAPI32.@]
50ce0844
JG
2450 *
2451 * Immediately write a registry key to registry.
5ce2329a
AJ
2452 *
2453 * PARAMS
6a358c40 2454 * hkey [I] Handle of key to write
5ce2329a
AJ
2455 *
2456 * RETURNS
6a358c40
JH
2457 * Success: ERROR_SUCCESS
2458 * Failure: Error code
5ce2329a 2459 */
af183df6 2460LSTATUS WINAPI RegFlushKey( HKEY hkey )
5ce2329a 2461{
43cb03be
MH
2462 hkey = get_special_root_hkey( hkey );
2463 if (!hkey) return ERROR_INVALID_HANDLE;
2464
2465 return RtlNtStatusToDosError( NtFlushKey( hkey ) );
5ce2329a
AJ
2466}
2467
2468
2469/******************************************************************************
d0a41774 2470 * RegConnectRegistryW [ADVAPI32.@]
5ce2329a 2471 *
d347ebe1 2472 * Establish a connection to a predefined registry key on another computer.
ec350525 2473 *
5ce2329a 2474 * PARAMS
6a358c40
JH
2475 * lpMachineName [I] Address of name of remote computer
2476 * hHey [I] Predefined registry handle
2477 * phkResult [I] Address of buffer for remote registry handle
2478 *
2479 * RETURNS
2480 * Success: ERROR_SUCCESS
2481 * Failure: nonzero error code from Winerror.h
5ce2329a 2482 */
af183df6 2483LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
5cf56a3a 2484 PHKEY phkResult )
5ce2329a 2485{
ae176d16
JL
2486 LONG ret;
2487
cbacde52 2488 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
5ce2329a
AJ
2489
2490 if (!lpMachineName || !*lpMachineName) {
2491 /* Use the local machine name */
ae176d16 2492 ret = RegOpenKeyW( hKey, NULL, phkResult );
5ce2329a 2493 }
c16e7058 2494 else {
ae176d16
JL
2495 WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2496 DWORD len = sizeof(compName) / sizeof(WCHAR);
5ce2329a 2497
c16e7058
RK
2498 /* MSDN says lpMachineName must start with \\ : not so */
2499 if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\')
2500 lpMachineName += 2;
ae176d16
JL
2501 if (GetComputerNameW(compName, &len))
2502 {
c16e7058 2503 if (!strcmpiW(lpMachineName, compName))
ae176d16
JL
2504 ret = RegOpenKeyW(hKey, NULL, phkResult);
2505 else
2506 {
c16e7058 2507 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
ae176d16
JL
2508 ret = ERROR_BAD_NETPATH;
2509 }
2510 }
2511 else
2512 ret = GetLastError();
2513 }
2514 return ret;
5ce2329a
AJ
2515}
2516
2517
2518/******************************************************************************
d0a41774 2519 * RegConnectRegistryA [ADVAPI32.@]
6a358c40 2520 *
d45811ce 2521 * See RegConnectRegistryW.
5ce2329a 2522 */
af183df6 2523LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
5ce2329a 2524{
6f2a071d
MD
2525 UNICODE_STRING machineW;
2526 LONG ret;
2527
2528 RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2529 ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2530 RtlFreeUnicodeString( &machineW );
5ce2329a
AJ
2531 return ret;
2532}
2533
2534
2535/******************************************************************************
d0a41774 2536 * RegNotifyChangeKeyValue [ADVAPI32.@]
5ce2329a 2537 *
ec350525
MA
2538 * Notify the caller about changes to the attributes or contents of a registry key.
2539 *
5ce2329a 2540 * PARAMS
6a358c40
JH
2541 * hkey [I] Handle of key to watch
2542 * fWatchSubTree [I] Flag for subkey notification
2543 * fdwNotifyFilter [I] Changes to be reported
2544 * hEvent [I] Handle of signaled event
2545 * fAsync [I] Flag for asynchronous reporting
2546 *
2547 * RETURNS
2548 * Success: ERROR_SUCCESS
2549 * Failure: nonzero error code from Winerror.h
5ce2329a 2550 */
af183df6 2551LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
5ce2329a
AJ
2552 DWORD fdwNotifyFilter, HANDLE hEvent,
2553 BOOL fAsync )
2554{
efbea2e2
RS
2555 NTSTATUS status;
2556 IO_STATUS_BLOCK iosb;
11f4b444 2557
efbea2e2
RS
2558 hkey = get_special_root_hkey( hkey );
2559 if (!hkey) return ERROR_INVALID_HANDLE;
11f4b444 2560
4301816d 2561 TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
efbea2e2 2562 hEvent, fAsync);
11f4b444 2563
efbea2e2 2564 status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
91080639
AS
2565 fdwNotifyFilter, fAsync, NULL, 0,
2566 fWatchSubTree);
11f4b444 2567
efbea2e2
RS
2568 if (status && status != STATUS_TIMEOUT)
2569 return RtlNtStatusToDosError( status );
2570
2571 return ERROR_SUCCESS;
5ce2329a 2572}
65e81827
RS
2573
2574/******************************************************************************
2575 * RegOpenUserClassesRoot [ADVAPI32.@]
50ce0844
JG
2576 *
2577 * Open the HKEY_CLASSES_ROOT key for a user.
65e81827
RS
2578 *
2579 * PARAMS
6a358c40 2580 * hToken [I] Handle of token representing the user
d347ebe1 2581 * dwOptions [I] Reserved, must be 0
6a358c40
JH
2582 * samDesired [I] Desired access rights
2583 * phkResult [O] Destination for the resulting key handle
65e81827 2584 *
6a358c40
JH
2585 * RETURNS
2586 * Success: ERROR_SUCCESS
2587 * Failure: nonzero error code from Winerror.h
2588 *
50ce0844 2589 * NOTES
6a358c40
JH
2590 * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2591 * "HKEY_LOCAL_MACHINE\Software\Classes" and the
2592 * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
65e81827 2593 */
af183df6 2594LSTATUS WINAPI RegOpenUserClassesRoot(
65e81827
RS
2595 HANDLE hToken,
2596 DWORD dwOptions,
2597 REGSAM samDesired,
2598 PHKEY phkResult
2599)
2600{
4301816d 2601 FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
65e81827
RS
2602
2603 *phkResult = HKEY_CLASSES_ROOT;
2604 return ERROR_SUCCESS;
2605}
ac615ce5
MJ
2606
2607/******************************************************************************
2608 * load_string [Internal]
2609 *
2610 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2611 * avoid importing user32, which is higher level than advapi32. Helper for
2612 * RegLoadMUIString.
2613 */
2614static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2615{
2616 HGLOBAL hMemory;
2617 HRSRC hResource;
2618 WCHAR *pString;
2619 int idxString;
2620
2621 /* Negative values have to be inverted. */
2622 if (HIWORD(resId) == 0xffff)
2623 resId = (UINT)(-((INT)resId));
2624
2625 /* Load the resource into memory and get a pointer to it. */
2626 hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2627 if (!hResource) return 0;
2628 hMemory = LoadResource(hModule, hResource);
2629 if (!hMemory) return 0;
2630 pString = LockResource(hMemory);
2631
2632 /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2633 idxString = resId & 0xf;
2634 while (idxString--) pString += *pString + 1;
2635
2636 /* If no buffer is given, return length of the string. */
2637 if (!pwszBuffer) return *pString;
2638
2639 /* Else copy over the string, respecting the buffer size. */
2640 cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2641 if (cMaxChars >= 0) {
2642 memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2643 pwszBuffer[cMaxChars] = '\0';
2644 }
2645
2646 return cMaxChars;
2647}
2648
2649/******************************************************************************
2650 * RegLoadMUIStringW [ADVAPI32.@]
2651 *
2652 * Load the localized version of a string resource from some PE, respective
2653 * id and path of which are given in the registry value in the format
2654 * @[path]\dllname,-resourceId
2655 *
2656 * PARAMS
2657 * hKey [I] Key, of which to load the string value from.
2658 * pszValue [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2659 * pszBuffer [O] Buffer to store the localized string in.
2660 * cbBuffer [I] Size of the destination buffer in bytes.
2661 * pcbData [O] Number of bytes written to pszBuffer (optional, may be NULL).
2662 * dwFlags [I] None supported yet.
2663 * pszBaseDir [I] Not supported yet.
2664 *
2665 * RETURNS
2666 * Success: ERROR_SUCCESS,
2667 * Failure: nonzero error code from winerror.h
2668 *
2669 * NOTES
2670 * This is an API of Windows Vista, which wasn't available at the time this code
2671 * was written. We have to check for the correct behaviour once it's available.
2672 */
af183df6 2673LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
ac615ce5
MJ
2674 LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2675{
2676 DWORD dwValueType, cbData;
2677 LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2678 LONG result;
2679
4301816d
HL
2680 TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
2681 "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer,
ac615ce5
MJ
2682 cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2683
2684 /* Parameter sanity checks. */
2685 if (!hKey || !pwszBuffer)
2686 return ERROR_INVALID_PARAMETER;
2687
2688 if (pwszBaseDir && *pwszBaseDir) {
2689 FIXME("BaseDir parameter not yet supported!\n");
2690 return ERROR_INVALID_PARAMETER;
2691 }
2692
2693 /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2694 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2695 if (result != ERROR_SUCCESS) goto cleanup;
2696 if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2697 result = ERROR_FILE_NOT_FOUND;
2698 goto cleanup;
2699 }
2700 pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2701 if (!pwszTempBuffer) {
2702 result = ERROR_NOT_ENOUGH_MEMORY;
2703 goto cleanup;
2704 }
2705 result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2706 if (result != ERROR_SUCCESS) goto cleanup;
2707
2708 /* Expand environment variables, if appropriate, or copy the original string over. */
2709 if (dwValueType == REG_EXPAND_SZ) {
2710 cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2711 if (!cbData) goto cleanup;
2712 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2713 if (!pwszExpandedBuffer) {
2714 result = ERROR_NOT_ENOUGH_MEMORY;
2715 goto cleanup;
2716 }
2717 ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2718 } else {
2719 pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2720 memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2721 }
2722
2723 /* If the value references a resource based string, parse the value and load the string.
2724 * Else just copy over the original value. */
2725 result = ERROR_SUCCESS;
2726 if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2727 lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2728 } else {
2729 WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2730 UINT uiStringId;
2731 HMODULE hModule;
2732
2733 /* Format of the expanded value is 'path_to_dll,-resId' */
2734 if (!pComma || pComma[1] != '-') {
2735 result = ERROR_BADKEY;
2736 goto cleanup;
2737 }
2738
2739 uiStringId = atoiW(pComma+2);
2740 *pComma = '\0';
2741
2742 hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2743 if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2744 result = ERROR_BADKEY;
2745 FreeLibrary(hModule);
2746 }
2747
2748cleanup:
2749 HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2750 HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2751 return result;
2752}
2753
2754/******************************************************************************
2755 * RegLoadMUIStringA [ADVAPI32.@]
2756 *
2757 * See RegLoadMUIStringW
2758 */
af183df6 2759LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
ac615ce5
MJ
2760 LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2761{
2762 UNICODE_STRING valueW, baseDirW;
2763 WCHAR *pwszBuffer;
2764 DWORD cbData = cbBuffer * sizeof(WCHAR);
2765 LONG result;
2766
2767 valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2768 if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2769 !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2770 !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2771 {
2772 result = ERROR_NOT_ENOUGH_MEMORY;
2773 goto cleanup;
2774 }
2775
2776 result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags,
2777 baseDirW.Buffer);
2778
2779 if (result == ERROR_SUCCESS) {
2780 cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2781 if (pcbData)
2782 *pcbData = cbData;
2783 }
2784
2785cleanup:
2786 HeapFree(GetProcessHeap(), 0, pwszBuffer);
2787 RtlFreeUnicodeString(&baseDirW);
2788 RtlFreeUnicodeString(&valueW);
2789
2790 return result;
2791}
52aaddcd
RS
2792
2793/******************************************************************************
2794 * RegDisablePredefinedCache [ADVAPI32.@]
2795 *
2796 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
2797 *
2798 * PARAMS
2799 * None.
2800 *
2801 * RETURNS
2802 * Success: ERROR_SUCCESS
2803 * Failure: nonzero error code from Winerror.h
2804 *
2805 * NOTES
2806 * This is useful for services that use impersonation.
2807 */
af183df6 2808LSTATUS WINAPI RegDisablePredefinedCache(void)
52aaddcd
RS
2809{
2810 HKEY hkey_current_user;
2811 int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
2812
2813 /* prevent caching of future requests */
2814 hkcu_cache_disabled = TRUE;
2815
2816 hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );
2817
2818 if (hkey_current_user)
2819 NtClose( hkey_current_user );
2820
2821 return ERROR_SUCCESS;
2822}
88b6bc4f
SL
2823
2824/******************************************************************************
2825 * RegDeleteTreeW [ADVAPI32.@]
2826 *
2827 */
af183df6 2828LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
88b6bc4f
SL
2829{
2830 LONG ret;
2831 DWORD dwMaxSubkeyLen, dwMaxValueLen;
2832 DWORD dwMaxLen, dwSize;
2833 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2834 HKEY hSubKey = hKey;
2835
2836 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
2837
2838 if(lpszSubKey)
2839 {
2840 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2841 if (ret) return ret;
2842 }
2843
2844 /* Get highest length for keys, values */
2845 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
2846 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
2847 if (ret) goto cleanup;
2848
2849 dwMaxSubkeyLen++;
2850 dwMaxValueLen++;
2851 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
2852 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
2853 {
2854 /* Name too big: alloc a buffer for it */
2855 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
2856 {
2857 ret = ERROR_NOT_ENOUGH_MEMORY;
2858 goto cleanup;
2859 }
2860 }
2861
2862
2863 /* Recursively delete all the subkeys */
2864 while (TRUE)
2865 {
2866 dwSize = dwMaxLen;
2867 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
2868 NULL, NULL, NULL)) break;
2869
2870 ret = RegDeleteTreeW(hSubKey, lpszName);
2871 if (ret) goto cleanup;
2872 }
2873
2874 if (lpszSubKey)
2875 ret = RegDeleteKeyW(hKey, lpszSubKey);
2876 else
2877 while (TRUE)
2878 {
2879 dwSize = dwMaxLen;
2880 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
2881 NULL, NULL, NULL, NULL)) break;
2882
2883 ret = RegDeleteValueW(hKey, lpszName);
2884 if (ret) goto cleanup;
2885 }
2886
2887cleanup:
2888 /* Free buffer if allocated */
2889 if (lpszName != szNameBuf)
2890 HeapFree( GetProcessHeap(), 0, lpszName);
2891 if(lpszSubKey)
2892 RegCloseKey(hSubKey);
2893 return ret;
2894}
2895
2896/******************************************************************************
2897 * RegDeleteTreeA [ADVAPI32.@]
2898 *
2899 */
af183df6 2900LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
88b6bc4f
SL
2901{
2902 LONG ret;
2903 UNICODE_STRING lpszSubKeyW;
2904
2905 if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
2906 else lpszSubKeyW.Buffer = NULL;
2907 ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
2908 RtlFreeUnicodeString( &lpszSubKeyW );
2909 return ret;
2910}