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