Removed obsolete INT_Int31Handler.
[wine/multimedia.git] / dlls / advapi32 / registry.c
blob3d3e4d5bc7c5b1f6ed356aded95b2d9d7216f178
1 /*
2 * Registry management
4 * Copyright (C) 1999 Alexandre Julliard
6 * Based on misc/registry.c code
7 * Copyright (C) 1996 Marcus Meissner
8 * Copyright (C) 1998 Matthew Becker
9 * Copyright (C) 1999 Sylvain St-Germain
11 * This file is concerned about handle management and interaction with the Wine server.
12 * Registry file I/O is in misc/registry.c.
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include <stdlib.h>
30 #include <stdio.h>
32 #include "winbase.h"
33 #include "winreg.h"
34 #include "winerror.h"
35 #include "wine/unicode.h"
36 #include "heap.h"
37 #include "wine/server.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(reg);
42 /* allowed bits for access mask */
43 #define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
45 #define HKEY_SPECIAL_ROOT_FIRST HKEY_CLASSES_ROOT
46 #define HKEY_SPECIAL_ROOT_LAST HKEY_DYN_DATA
47 #define NB_SPECIAL_ROOT_KEYS ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
49 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
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};
70 #define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
71 static UNICODE_STRING root_key_names[NB_SPECIAL_ROOT_KEYS] =
73 DECL_STR(CLASSES_ROOT),
74 { 0, 0, NULL }, /* HKEY_CURRENT_USER is determined dynamically */
75 DECL_STR(LOCAL_MACHINE),
76 DECL_STR(USERS),
77 DECL_STR(PERFORMANCE_DATA),
78 DECL_STR(CURRENT_CONFIG),
79 DECL_STR(DYN_DATA)
81 #undef DECL_STR
84 /* check if value type needs string conversion (Ansi<->Unicode) */
85 inline static int is_string( DWORD type )
87 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
90 /* check if current version is NT or Win95 */
91 inline static int is_version_nt(void)
93 return !(GetVersion() & 0x80000000);
96 /* create one of the HKEY_* special root keys */
97 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
99 HKEY ret = 0;
100 int idx = (UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST;
102 if (hkey == HKEY_CURRENT_USER)
104 if (RtlOpenCurrentUser( access, &hkey )) return 0;
105 TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
107 else
109 OBJECT_ATTRIBUTES attr;
111 attr.Length = sizeof(attr);
112 attr.RootDirectory = 0;
113 attr.ObjectName = &root_key_names[idx];
114 attr.Attributes = 0;
115 attr.SecurityDescriptor = NULL;
116 attr.SecurityQualityOfService = NULL;
117 if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
118 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
121 if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
122 ret = hkey;
123 else
124 NtClose( hkey ); /* somebody beat us to it */
125 return ret;
128 /* map the hkey from special root to normal key if necessary */
129 inline static HKEY get_special_root_hkey( HKEY hkey )
131 HKEY ret = hkey;
133 if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
135 if (!(ret = special_root_keys[(UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST]))
136 ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
138 return ret;
142 /******************************************************************************
143 * RegCreateKeyExW [ADVAPI32.@]
145 * PARAMS
146 * hkey [I] Handle of an open key
147 * name [I] Address of subkey name
148 * reserved [I] Reserved - must be 0
149 * class [I] Address of class string
150 * options [I] Special options flag
151 * access [I] Desired security access
152 * sa [I] Address of key security structure
153 * retkey [O] Address of buffer for opened handle
154 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
156 * NOTES
157 * in case of failing retkey remains untouched
159 * FIXME MAXIMUM_ALLOWED in access mask not supported by server
161 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
162 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
163 PHKEY retkey, LPDWORD dispos )
165 OBJECT_ATTRIBUTES attr;
166 UNICODE_STRING nameW, classW;
168 if (reserved) return ERROR_INVALID_PARAMETER;
169 if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
170 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
172 attr.Length = sizeof(attr);
173 attr.RootDirectory = hkey;
174 attr.ObjectName = &nameW;
175 attr.Attributes = 0;
176 attr.SecurityDescriptor = NULL;
177 attr.SecurityQualityOfService = NULL;
178 RtlInitUnicodeString( &nameW, name );
179 RtlInitUnicodeString( &classW, class );
181 return RtlNtStatusToDosError( NtCreateKey( retkey, access, &attr, 0,
182 &classW, options, dispos ) );
186 /******************************************************************************
187 * RegCreateKeyExA [ADVAPI32.@]
189 * FIXME MAXIMUM_ALLOWED in access mask not supported by server
191 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
192 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
193 PHKEY retkey, LPDWORD dispos )
195 OBJECT_ATTRIBUTES attr;
196 UNICODE_STRING classW;
197 ANSI_STRING nameA, classA;
198 NTSTATUS status;
200 if (reserved) return ERROR_INVALID_PARAMETER;
201 if (!is_version_nt()) access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
202 else if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
203 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
205 attr.Length = sizeof(attr);
206 attr.RootDirectory = hkey;
207 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
208 attr.Attributes = 0;
209 attr.SecurityDescriptor = NULL;
210 attr.SecurityQualityOfService = NULL;
211 RtlInitAnsiString( &nameA, name );
212 RtlInitAnsiString( &classA, class );
214 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
215 &nameA, FALSE )))
217 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
219 status = NtCreateKey( retkey, access, &attr, 0, &classW, options, dispos );
220 RtlFreeUnicodeString( &classW );
223 return RtlNtStatusToDosError( status );
227 /******************************************************************************
228 * RegCreateKeyW [ADVAPI32.@]
230 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
232 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
233 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
234 return RegCreateKeyExW( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
235 KEY_ALL_ACCESS, NULL, retkey, NULL );
239 /******************************************************************************
240 * RegCreateKeyA [ADVAPI32.@]
242 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
244 return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
245 KEY_ALL_ACCESS, NULL, retkey, NULL );
250 /******************************************************************************
251 * RegOpenKeyExW [ADVAPI32.@]
253 * Opens the specified key
255 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
257 * PARAMS
258 * hkey [I] Handle of open key
259 * name [I] Name of subkey to open
260 * reserved [I] Reserved - must be zero
261 * access [I] Security access mask
262 * retkey [O] Handle to open key
264 * RETURNS
265 * Success: ERROR_SUCCESS
266 * Failure: Error code
268 * NOTES
269 * in case of failing is retkey = 0
271 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
273 OBJECT_ATTRIBUTES attr;
274 UNICODE_STRING nameW;
276 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
278 attr.Length = sizeof(attr);
279 attr.RootDirectory = hkey;
280 attr.ObjectName = &nameW;
281 attr.Attributes = 0;
282 attr.SecurityDescriptor = NULL;
283 attr.SecurityQualityOfService = NULL;
284 RtlInitUnicodeString( &nameW, name );
285 return RtlNtStatusToDosError( NtOpenKey( retkey, access, &attr ) );
289 /******************************************************************************
290 * RegOpenKeyExA [ADVAPI32.@]
292 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
294 OBJECT_ATTRIBUTES attr;
295 STRING nameA;
296 NTSTATUS status;
298 if (!is_version_nt()) access = KEY_ALL_ACCESS; /* Win95 ignores the access mask */
300 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
302 attr.Length = sizeof(attr);
303 attr.RootDirectory = hkey;
304 attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
305 attr.Attributes = 0;
306 attr.SecurityDescriptor = NULL;
307 attr.SecurityQualityOfService = NULL;
309 RtlInitAnsiString( &nameA, name );
310 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
311 &nameA, FALSE )))
313 status = NtOpenKey( retkey, access, &attr );
315 return RtlNtStatusToDosError( status );
319 /******************************************************************************
320 * RegOpenKeyW [ADVAPI32.@]
322 * PARAMS
323 * hkey [I] Handle of open key
324 * name [I] Address of name of subkey to open
325 * retkey [O] Handle to open key
327 * RETURNS
328 * Success: ERROR_SUCCESS
329 * Failure: Error code
331 * NOTES
332 * in case of failing is retkey = 0
334 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
336 return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
340 /******************************************************************************
341 * RegOpenKeyA [ADVAPI32.@]
343 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
345 return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
349 /******************************************************************************
350 * RegOpenCurrentUser [ADVAPI32.@]
351 * FIXME: This function is supposed to retrieve a handle to the
352 * HKEY_CURRENT_USER for the user the current thread is impersonating.
353 * Since Wine does not currently allow threads to impersonate other users,
354 * this stub should work fine.
356 DWORD WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
358 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
363 /******************************************************************************
364 * RegEnumKeyExW [ADVAPI32.@]
366 * PARAMS
367 * hkey [I] Handle to key to enumerate
368 * index [I] Index of subkey to enumerate
369 * name [O] Buffer for subkey name
370 * name_len [O] Size of subkey buffer
371 * reserved [I] Reserved
372 * class [O] Buffer for class string
373 * class_len [O] Size of class buffer
374 * ft [O] Time key last written to
376 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
377 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
379 NTSTATUS status;
380 char buffer[256], *buf_ptr = buffer;
381 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
382 DWORD total_size;
384 TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
385 name_len ? *name_len : -1, reserved, class, class_len, ft );
387 if (reserved) return ERROR_INVALID_PARAMETER;
388 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
390 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
391 buffer, sizeof(buffer), &total_size );
393 while (status == STATUS_BUFFER_OVERFLOW)
395 /* retry with a dynamically allocated buffer */
396 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
397 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
398 return ERROR_NOT_ENOUGH_MEMORY;
399 info = (KEY_NODE_INFORMATION *)buf_ptr;
400 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
401 buf_ptr, total_size, &total_size );
404 if (!status)
406 DWORD len = info->NameLength / sizeof(WCHAR);
407 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
409 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
411 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
412 status = STATUS_BUFFER_OVERFLOW;
413 else
415 *name_len = len;
416 memcpy( name, info->Name, info->NameLength );
417 name[len] = 0;
418 if (class_len)
420 *class_len = cls_len;
421 if (class)
423 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
424 class[cls_len] = 0;
430 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
431 return RtlNtStatusToDosError( status );
435 /******************************************************************************
436 * RegEnumKeyExA [ADVAPI32.@]
438 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
439 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
441 NTSTATUS status;
442 char buffer[256], *buf_ptr = buffer;
443 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
444 DWORD total_size;
446 TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
447 name_len ? *name_len : -1, reserved, class, class_len, ft );
449 if (reserved) return ERROR_INVALID_PARAMETER;
450 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
452 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
453 buffer, sizeof(buffer), &total_size );
455 while (status == STATUS_BUFFER_OVERFLOW)
457 /* retry with a dynamically allocated buffer */
458 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
459 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
460 return ERROR_NOT_ENOUGH_MEMORY;
461 info = (KEY_NODE_INFORMATION *)buf_ptr;
462 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
463 buf_ptr, total_size, &total_size );
466 if (!status)
468 DWORD len, cls_len;
470 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
471 RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
472 info->ClassLength );
473 if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
475 if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
476 status = STATUS_BUFFER_OVERFLOW;
477 else
479 *name_len = len;
480 RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
481 name[len] = 0;
482 if (class_len)
484 *class_len = cls_len;
485 if (class)
487 RtlUnicodeToMultiByteN( class, cls_len, NULL,
488 (WCHAR *)(buf_ptr + info->ClassOffset),
489 info->ClassLength );
490 class[cls_len] = 0;
496 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
497 return RtlNtStatusToDosError( status );
501 /******************************************************************************
502 * RegEnumKeyW [ADVAPI32.@]
504 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
506 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
510 /******************************************************************************
511 * RegEnumKeyA [ADVAPI32.@]
513 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
515 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
519 /******************************************************************************
520 * RegQueryInfoKeyW [ADVAPI32.@]
522 * PARAMS
523 * hkey [I] Handle to key to query
524 * class [O] Buffer for class string
525 * class_len [O] Size of class string buffer
526 * reserved [I] Reserved
527 * subkeys [O] Buffer for number of subkeys
528 * max_subkey [O] Buffer for longest subkey name length
529 * max_class [O] Buffer for longest class string length
530 * values [O] Buffer for number of value entries
531 * max_value [O] Buffer for longest value name length
532 * max_data [O] Buffer for longest value data length
533 * security [O] Buffer for security descriptor length
534 * modif [O] Modification time
536 * - win95 allows class to be valid and class_len to be NULL
537 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
538 * - both allow class to be NULL and class_len to be NULL
539 * (it's hard to test validity, so test !NULL instead)
541 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
542 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
543 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
544 LPDWORD security, FILETIME *modif )
546 NTSTATUS status;
547 char buffer[256], *buf_ptr = buffer;
548 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
549 DWORD total_size;
551 TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
552 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
554 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
555 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
557 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
558 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
560 if (class)
562 /* retry with a dynamically allocated buffer */
563 while (status == STATUS_BUFFER_OVERFLOW)
565 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
566 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
567 return ERROR_NOT_ENOUGH_MEMORY;
568 info = (KEY_FULL_INFORMATION *)buf_ptr;
569 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
572 if (status) goto done;
574 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
576 status = STATUS_BUFFER_OVERFLOW;
578 else
580 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
581 class[info->ClassLength/sizeof(WCHAR)] = 0;
584 else status = STATUS_SUCCESS;
586 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
587 if (subkeys) *subkeys = info->SubKeys;
588 if (max_subkey) *max_subkey = info->MaxNameLen;
589 if (max_class) *max_class = info->MaxClassLen;
590 if (values) *values = info->Values;
591 if (max_value) *max_value = info->MaxValueNameLen;
592 if (max_data) *max_data = info->MaxValueDataLen;
593 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
595 done:
596 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
597 return RtlNtStatusToDosError( status );
601 /******************************************************************************
602 * RegQueryMultipleValuesA [ADVAPI32.@]
604 DWORD WINAPI RegQueryMultipleValuesA(HKEY hkey, PVALENTA val_list, DWORD num_vals,
605 LPSTR lpValueBuf, LPDWORD ldwTotsize)
607 int i;
608 DWORD maxBytes = *ldwTotsize;
609 HRESULT status;
610 LPSTR bufptr = lpValueBuf;
611 *ldwTotsize = 0;
613 TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
615 for(i=0; i < num_vals; ++i)
618 val_list[i].ve_valuelen=0;
619 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
620 if(status != ERROR_SUCCESS)
622 return status;
625 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
627 status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
628 bufptr, &val_list[i].ve_valuelen);
629 if(status != ERROR_SUCCESS)
631 return status;
634 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
636 bufptr += val_list[i].ve_valuelen;
639 *ldwTotsize += val_list[i].ve_valuelen;
641 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
645 /******************************************************************************
646 * RegQueryMultipleValuesW [ADVAPI32.@]
648 DWORD WINAPI RegQueryMultipleValuesW(HKEY hkey, PVALENTW val_list, DWORD num_vals,
649 LPWSTR lpValueBuf, LPDWORD ldwTotsize)
651 int i;
652 DWORD maxBytes = *ldwTotsize;
653 HRESULT status;
654 LPSTR bufptr = (LPSTR)lpValueBuf;
655 *ldwTotsize = 0;
657 TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
659 for(i=0; i < num_vals; ++i)
661 val_list[i].ve_valuelen=0;
662 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
663 if(status != ERROR_SUCCESS)
665 return status;
668 if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
670 status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
671 bufptr, &val_list[i].ve_valuelen);
672 if(status != ERROR_SUCCESS)
674 return status;
677 val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
679 bufptr += val_list[i].ve_valuelen;
682 *ldwTotsize += val_list[i].ve_valuelen;
684 return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
687 /******************************************************************************
688 * RegQueryInfoKeyA [ADVAPI32.@]
690 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
691 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
692 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
693 LPDWORD security, FILETIME *modif )
695 NTSTATUS status;
696 char buffer[256], *buf_ptr = buffer;
697 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
698 DWORD total_size, len;
700 TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
701 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
703 if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
704 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
706 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
707 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
709 if (class || class_len)
711 /* retry with a dynamically allocated buffer */
712 while (status == STATUS_BUFFER_OVERFLOW)
714 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
715 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
716 return ERROR_NOT_ENOUGH_MEMORY;
717 info = (KEY_FULL_INFORMATION *)buf_ptr;
718 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
721 if (status) goto done;
723 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
724 if (class_len)
726 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
727 *class_len = len;
729 if (class && !status)
731 RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
732 info->ClassLength );
733 class[len] = 0;
736 else status = STATUS_SUCCESS;
738 if (subkeys) *subkeys = info->SubKeys;
739 if (max_subkey) *max_subkey = info->MaxNameLen;
740 if (max_class) *max_class = info->MaxClassLen;
741 if (values) *values = info->Values;
742 if (max_value) *max_value = info->MaxValueNameLen;
743 if (max_data) *max_data = info->MaxValueDataLen;
744 if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
746 done:
747 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
748 return RtlNtStatusToDosError( status );
752 /******************************************************************************
753 * RegCloseKey [ADVAPI32.@]
755 * Releases the handle of the specified key
757 * PARAMS
758 * hkey [I] Handle of key to close
760 * RETURNS
761 * Success: ERROR_SUCCESS
762 * Failure: Error code
764 DWORD WINAPI RegCloseKey( HKEY hkey )
766 if (!hkey || hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
767 return RtlNtStatusToDosError( NtClose( hkey ) );
771 /******************************************************************************
772 * RegDeleteKeyW [ADVAPI32.@]
774 * PARAMS
775 * hkey [I] Handle to open key
776 * name [I] Name of subkey to delete
778 * RETURNS
779 * Success: ERROR_SUCCESS
780 * Failure: Error code
782 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
784 DWORD ret;
785 HKEY tmp;
787 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
789 if (!name || !*name)
791 ret = RtlNtStatusToDosError( NtDeleteKey( hkey ) );
793 else if (!(ret = RegOpenKeyExW( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
795 if (!is_version_nt()) /* win95 does recursive key deletes */
797 WCHAR name[MAX_PATH];
799 while(!RegEnumKeyW(tmp, 0, name, sizeof name))
801 if(RegDeleteKeyW(tmp, name)) /* recurse */
802 break;
805 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
806 RegCloseKey( tmp );
808 TRACE("%s ret=%08lx\n", debugstr_w(name), ret);
809 return ret;
813 /******************************************************************************
814 * RegDeleteKeyA [ADVAPI32.@]
816 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
818 DWORD ret;
819 HKEY tmp;
821 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
823 if (!name || !*name)
825 ret = RtlNtStatusToDosError( NtDeleteKey( hkey ) );
827 else if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
829 if (!is_version_nt()) /* win95 does recursive key deletes */
831 CHAR name[MAX_PATH];
833 while(!RegEnumKeyA(tmp, 0, name, sizeof name))
835 if(RegDeleteKeyA(tmp, name)) /* recurse */
836 break;
839 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
840 RegCloseKey( tmp );
842 TRACE("%s ret=%08lx\n", debugstr_a(name), ret);
843 return ret;
848 /******************************************************************************
849 * RegSetValueExW [ADVAPI32.@]
851 * Sets the data and type of a value under a register key
853 * PARAMS
854 * hkey [I] Handle of key to set value for
855 * name [I] Name of value to set
856 * reserved [I] Reserved - must be zero
857 * type [I] Flag for value type
858 * data [I] Address of value data
859 * count [I] Size of value data
861 * RETURNS
862 * Success: ERROR_SUCCESS
863 * Failure: Error code
865 * NOTES
866 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
867 * NT does definitely care (aj)
869 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
870 DWORD type, CONST BYTE *data, DWORD count )
872 UNICODE_STRING nameW;
874 if (!is_version_nt()) /* win95 */
876 if (type == REG_SZ) count = (strlenW( (WCHAR *)data ) + 1) * sizeof(WCHAR);
878 else if (count && is_string(type))
880 LPCWSTR str = (LPCWSTR)data;
881 /* if user forgot to count terminating null, add it (yes NT does this) */
882 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
883 count += sizeof(WCHAR);
885 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
887 RtlInitUnicodeString( &nameW, name );
888 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
892 /******************************************************************************
893 * RegSetValueExA [ADVAPI32.@]
895 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
896 CONST BYTE *data, DWORD count )
898 ANSI_STRING nameA;
899 WCHAR *dataW = NULL;
900 NTSTATUS status;
902 if (!is_version_nt()) /* win95 */
904 if (type == REG_SZ) count = strlen(data) + 1;
906 else if (count && is_string(type))
908 /* if user forgot to count terminating null, add it (yes NT does this) */
909 if (data[count-1] && !data[count]) count++;
912 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
914 if (is_string( type )) /* need to convert to Unicode */
916 DWORD lenW;
917 RtlMultiByteToUnicodeSize( &lenW, data, count );
918 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
919 RtlMultiByteToUnicodeN( dataW, lenW, NULL, data, count );
920 count = lenW;
921 data = (BYTE *)dataW;
924 RtlInitAnsiString( &nameA, name );
925 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
926 &nameA, FALSE )))
928 status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
930 if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
931 return RtlNtStatusToDosError( status );
935 /******************************************************************************
936 * RegSetValueW [ADVAPI32.@]
938 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
940 HKEY subkey = hkey;
941 DWORD ret;
943 TRACE("(%p,%s,%ld,%s,%ld)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
945 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
947 if (name && name[0]) /* need to create the subkey */
949 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
952 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (LPBYTE)data,
953 (strlenW( data ) + 1) * sizeof(WCHAR) );
954 if (subkey != hkey) RegCloseKey( subkey );
955 return ret;
959 /******************************************************************************
960 * RegSetValueA [ADVAPI32.@]
962 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
964 HKEY subkey = hkey;
965 DWORD ret;
967 TRACE("(%p,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
969 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
971 if (name && name[0]) /* need to create the subkey */
973 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
975 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
976 if (subkey != hkey) RegCloseKey( subkey );
977 return ret;
982 /******************************************************************************
983 * RegQueryValueExW [ADVAPI32.@]
985 * Retrieves type and data for a specified name associated with an open key
987 * PARAMS
988 * hkey [I] Handle of key to query
989 * name [I] Name of value to query
990 * reserved [I] Reserved - must be NULL
991 * type [O] Address of buffer for value type. If NULL, the type
992 * is not required.
993 * data [O] Address of data buffer. If NULL, the actual data is
994 * not required.
995 * count [I/O] Address of data buffer size
997 * RETURNS
998 * ERROR_SUCCESS: Success
999 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
1000 * buffer is left untouched. The MS-documentation is wrong (js) !!!
1002 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1003 LPBYTE data, LPDWORD count )
1005 NTSTATUS status;
1006 UNICODE_STRING name_str;
1007 DWORD total_size;
1008 char buffer[256], *buf_ptr = buffer;
1009 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1010 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1012 TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1013 hkey, debugstr_w(name), reserved, type, data, count, count ? *count : 0 );
1015 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1016 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1018 RtlInitUnicodeString( &name_str, name );
1020 if (data) total_size = min( sizeof(buffer), *count + info_size );
1021 else total_size = info_size;
1023 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1024 buffer, total_size, &total_size );
1025 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1027 if (data)
1029 /* retry with a dynamically allocated buffer */
1030 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1032 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1033 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1034 return ERROR_NOT_ENOUGH_MEMORY;
1035 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1036 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1037 buf_ptr, total_size, &total_size );
1040 if (!status)
1042 memcpy( data, buf_ptr + info_size, total_size - info_size );
1043 /* if the type is REG_SZ and data is not 0-terminated
1044 * and there is enough space in the buffer NT appends a \0 */
1045 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1047 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1048 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1051 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1053 else status = STATUS_SUCCESS;
1055 if (type) *type = info->Type;
1056 if (count) *count = total_size - info_size;
1058 done:
1059 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1060 return RtlNtStatusToDosError(status);
1064 /******************************************************************************
1065 * RegQueryValueExA [ADVAPI32.@]
1067 * NOTES:
1068 * the documentation is wrong: if the buffer is too small it remains untouched
1070 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1071 LPBYTE data, LPDWORD count )
1073 NTSTATUS status;
1074 ANSI_STRING nameA;
1075 DWORD total_size;
1076 char buffer[256], *buf_ptr = buffer;
1077 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1078 static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1080 TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1081 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1083 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1084 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1086 RtlInitAnsiString( &nameA, name );
1087 if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1088 &nameA, FALSE )))
1089 return RtlNtStatusToDosError(status);
1091 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1092 KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
1093 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1095 /* we need to fetch the contents for a string type even if not requested,
1096 * because we need to compute the length of the ASCII string. */
1097 if (data || is_string(info->Type))
1099 /* retry with a dynamically allocated buffer */
1100 while (status == STATUS_BUFFER_OVERFLOW)
1102 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1103 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1105 status = STATUS_NO_MEMORY;
1106 goto done;
1108 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1109 status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1110 KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1113 if (status) goto done;
1115 if (is_string(info->Type))
1117 DWORD len;
1119 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1120 total_size - info_size );
1121 if (data && len)
1123 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1124 else
1126 RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1127 total_size - info_size );
1128 /* if the type is REG_SZ and data is not 0-terminated
1129 * and there is enough space in the buffer NT appends a \0 */
1130 if (len < *count && data[len-1]) data[len] = 0;
1133 total_size = len + info_size;
1135 else if (data)
1137 if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
1138 else memcpy( data, buf_ptr + info_size, total_size - info_size );
1141 else status = STATUS_SUCCESS;
1143 if (type) *type = info->Type;
1144 if (count) *count = total_size - info_size;
1146 done:
1147 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1148 return RtlNtStatusToDosError(status);
1152 /******************************************************************************
1153 * RegQueryValueW [ADVAPI32.@]
1155 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1157 DWORD ret;
1158 HKEY subkey = hkey;
1160 TRACE("(%p,%s,%p,%ld)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1162 if (name && name[0])
1164 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1166 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
1167 if (subkey != hkey) RegCloseKey( subkey );
1168 if (ret == ERROR_FILE_NOT_FOUND)
1170 /* return empty string if default value not found */
1171 if (data) *data = 0;
1172 if (count) *count = 1;
1173 ret = ERROR_SUCCESS;
1175 return ret;
1179 /******************************************************************************
1180 * RegQueryValueA [ADVAPI32.@]
1182 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1184 DWORD ret;
1185 HKEY subkey = hkey;
1187 TRACE("(%p,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1189 if (name && name[0])
1191 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1193 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
1194 if (subkey != hkey) RegCloseKey( subkey );
1195 if (ret == ERROR_FILE_NOT_FOUND)
1197 /* return empty string if default value not found */
1198 if (data) *data = 0;
1199 if (count) *count = 1;
1200 ret = ERROR_SUCCESS;
1202 return ret;
1206 /******************************************************************************
1207 * RegEnumValueW [ADVAPI32.@]
1209 * PARAMS
1210 * hkey [I] Handle to key to query
1211 * index [I] Index of value to query
1212 * value [O] Value string
1213 * val_count [I/O] Size of value buffer (in wchars)
1214 * reserved [I] Reserved
1215 * type [O] Type code
1216 * data [O] Value data
1217 * count [I/O] Size of data buffer (in bytes)
1220 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1221 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1223 NTSTATUS status;
1224 DWORD total_size;
1225 char buffer[256], *buf_ptr = buffer;
1226 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1227 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1229 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1230 hkey, index, value, val_count, reserved, type, data, count );
1232 /* NT only checks count, not val_count */
1233 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1234 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1236 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1237 if (data) total_size += *count;
1238 total_size = min( sizeof(buffer), total_size );
1240 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1241 buffer, total_size, &total_size );
1242 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1244 if (value || data)
1246 /* retry with a dynamically allocated buffer */
1247 while (status == STATUS_BUFFER_OVERFLOW)
1249 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1250 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1251 return ERROR_NOT_ENOUGH_MEMORY;
1252 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1253 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1254 buf_ptr, total_size, &total_size );
1257 if (status) goto done;
1259 if (value)
1261 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1263 status = STATUS_BUFFER_OVERFLOW;
1264 goto overflow;
1266 memcpy( value, info->Name, info->NameLength );
1267 *val_count = info->NameLength / sizeof(WCHAR);
1268 value[*val_count] = 0;
1271 if (data)
1273 if (total_size - info->DataOffset > *count)
1275 status = STATUS_BUFFER_OVERFLOW;
1276 goto overflow;
1278 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1279 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1281 /* if the type is REG_SZ and data is not 0-terminated
1282 * and there is enough space in the buffer NT appends a \0 */
1283 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1284 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1288 else status = STATUS_SUCCESS;
1290 overflow:
1291 if (type) *type = info->Type;
1292 if (count) *count = info->DataLength;
1294 done:
1295 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1296 return RtlNtStatusToDosError(status);
1300 /******************************************************************************
1301 * RegEnumValueA [ADVAPI32.@]
1303 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1304 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1306 NTSTATUS status;
1307 DWORD total_size;
1308 char buffer[256], *buf_ptr = buffer;
1309 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1310 static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1312 TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1313 hkey, index, value, val_count, reserved, type, data, count );
1315 /* NT only checks count, not val_count */
1316 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1317 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1319 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1320 if (data) total_size += *count;
1321 total_size = min( sizeof(buffer), total_size );
1323 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1324 buffer, total_size, &total_size );
1325 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1327 /* we need to fetch the contents for a string type even if not requested,
1328 * because we need to compute the length of the ASCII string. */
1329 if (value || data || is_string(info->Type))
1331 /* retry with a dynamically allocated buffer */
1332 while (status == STATUS_BUFFER_OVERFLOW)
1334 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1335 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1336 return ERROR_NOT_ENOUGH_MEMORY;
1337 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1338 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1339 buf_ptr, total_size, &total_size );
1342 if (status) goto done;
1344 if (is_string(info->Type))
1346 DWORD len;
1347 RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1348 total_size - info->DataOffset );
1349 if (data && len)
1351 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1352 else
1354 RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1355 total_size - info->DataOffset );
1356 /* if the type is REG_SZ and data is not 0-terminated
1357 * and there is enough space in the buffer NT appends a \0 */
1358 if (len < *count && data[len-1]) data[len] = 0;
1361 info->DataLength = len;
1363 else if (data)
1365 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1366 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1369 if (value && !status)
1371 DWORD len;
1373 RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1374 if (len >= *val_count)
1376 status = STATUS_BUFFER_OVERFLOW;
1377 if (*val_count)
1379 len = *val_count - 1;
1380 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1381 value[len] = 0;
1384 else
1386 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1387 value[len] = 0;
1388 *val_count = len;
1392 else status = STATUS_SUCCESS;
1394 if (type) *type = info->Type;
1395 if (count) *count = info->DataLength;
1397 done:
1398 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1399 return RtlNtStatusToDosError(status);
1404 /******************************************************************************
1405 * RegDeleteValueW [ADVAPI32.@]
1407 * PARAMS
1408 * hkey [I] handle to key
1409 * name [I] name of value to delete
1411 * RETURNS
1412 * error status
1414 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1416 UNICODE_STRING nameW;
1418 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1420 RtlInitUnicodeString( &nameW, name );
1421 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1425 /******************************************************************************
1426 * RegDeleteValueA [ADVAPI32.@]
1428 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1430 STRING nameA;
1431 NTSTATUS status;
1433 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1435 RtlInitAnsiString( &nameA, name );
1436 if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1437 &nameA, FALSE )))
1438 status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1439 return RtlNtStatusToDosError( status );
1443 /******************************************************************************
1444 * RegLoadKeyW [ADVAPI32.@]
1446 * PARAMS
1447 * hkey [I] Handle of open key
1448 * subkey [I] Address of name of subkey
1449 * filename [I] Address of filename for registry information
1451 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1453 HANDLE file;
1454 DWORD ret, len, err = GetLastError();
1455 HKEY shkey;
1457 TRACE( "(%p,%s,%s)\n", hkey, debugstr_w(subkey), debugstr_w(filename) );
1459 if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1460 if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1461 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1463 len = strlenW( subkey ) * sizeof(WCHAR);
1464 if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
1466 if ((file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1467 FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
1469 ret = GetLastError();
1470 goto done;
1473 RegCreateKeyW(hkey,subkey,&shkey);
1475 SERVER_START_REQ( load_registry )
1477 req->hkey = shkey;
1478 req->file = file;
1479 wine_server_add_data( req, subkey, len );
1480 ret = RtlNtStatusToDosError( wine_server_call(req) );
1482 SERVER_END_REQ;
1483 CloseHandle( file );
1484 RegCloseKey(shkey);
1486 done:
1487 SetLastError( err ); /* restore the last error code */
1488 return ret;
1492 /******************************************************************************
1493 * RegLoadKeyA [ADVAPI32.@]
1495 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1497 WCHAR buffer[MAX_PATH];
1498 HANDLE file;
1499 DWORD ret, len, err = GetLastError();
1500 HKEY shkey;
1502 TRACE( "(%p,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
1504 if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1505 if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1506 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1508 if (!(len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), buffer, MAX_PATH )))
1509 return ERROR_INVALID_PARAMETER;
1511 if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1512 FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
1514 ret = GetLastError();
1515 goto done;
1518 RegCreateKeyA(hkey,subkey,&shkey);
1520 SERVER_START_REQ( load_registry )
1522 req->hkey = shkey;
1523 req->file = file;
1524 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
1525 ret = RtlNtStatusToDosError( wine_server_call(req) );
1527 SERVER_END_REQ;
1528 CloseHandle( file );
1529 RegCloseKey(shkey);
1531 done:
1532 SetLastError( err ); /* restore the last error code */
1533 return ret;
1537 /******************************************************************************
1538 * RegSaveKeyA [ADVAPI32.@]
1540 * PARAMS
1541 * hkey [I] Handle of key where save begins
1542 * lpFile [I] Address of filename to save to
1543 * sa [I] Address of security structure
1545 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
1547 char buffer[1024];
1548 int count = 0;
1549 LPSTR name;
1550 DWORD ret, err;
1551 HANDLE handle;
1553 TRACE( "(%p,%s,%p)\n", hkey, debugstr_a(file), sa );
1555 if (!file || !*file) return ERROR_INVALID_PARAMETER;
1556 if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1558 err = GetLastError();
1559 GetFullPathNameA( file, sizeof(buffer), buffer, &name );
1560 for (;;)
1562 sprintf( name, "reg%04x.tmp", count++ );
1563 handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
1564 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1565 if (handle != INVALID_HANDLE_VALUE) break;
1566 if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
1568 /* Something gone haywire ? Please report if this happens abnormally */
1569 if (count >= 100)
1570 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", buffer, count);
1573 SERVER_START_REQ( save_registry )
1575 req->hkey = hkey;
1576 req->file = handle;
1577 ret = RtlNtStatusToDosError( wine_server_call( req ) );
1579 SERVER_END_REQ;
1581 CloseHandle( handle );
1582 if (!ret)
1584 if (!MoveFileExA( buffer, file, MOVEFILE_REPLACE_EXISTING ))
1586 ERR( "Failed to move %s to %s\n", buffer, file );
1587 ret = GetLastError();
1590 if (ret) DeleteFileA( buffer );
1592 done:
1593 SetLastError( err ); /* restore last error code */
1594 return ret;
1598 /******************************************************************************
1599 * RegSaveKeyW [ADVAPI32.@]
1601 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1603 LPSTR fileA = HEAP_strdupWtoA( GetProcessHeap(), 0, file );
1604 DWORD ret = RegSaveKeyA( hkey, fileA, sa );
1605 if (fileA) HeapFree( GetProcessHeap(), 0, fileA );
1606 return ret;
1610 /******************************************************************************
1611 * RegRestoreKeyW [ADVAPI32.@]
1613 * PARAMS
1614 * hkey [I] Handle of key where restore begins
1615 * lpFile [I] Address of filename containing saved tree
1616 * dwFlags [I] Optional flags
1618 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1620 TRACE("(%p,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1622 /* It seems to do this check before the hkey check */
1623 if (!lpFile || !*lpFile)
1624 return ERROR_INVALID_PARAMETER;
1626 FIXME("(%p,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1628 /* Check for file existence */
1630 return ERROR_SUCCESS;
1634 /******************************************************************************
1635 * RegRestoreKeyA [ADVAPI32.@]
1637 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1639 LPWSTR lpFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile );
1640 LONG ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1641 HeapFree( GetProcessHeap(), 0, lpFileW );
1642 return ret;
1646 /******************************************************************************
1647 * RegUnLoadKeyW [ADVAPI32.@]
1649 * PARAMS
1650 * hkey [I] Handle of open key
1651 * lpSubKey [I] Address of name of subkey to unload
1653 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1655 FIXME("(%p,%s): stub\n",hkey, debugstr_w(lpSubKey));
1656 return ERROR_SUCCESS;
1660 /******************************************************************************
1661 * RegUnLoadKeyA [ADVAPI32.@]
1663 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1665 LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1666 LONG ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1667 if(lpSubKeyW) HeapFree( GetProcessHeap(), 0, lpSubKeyW);
1668 return ret;
1672 /******************************************************************************
1673 * RegReplaceKeyW [ADVAPI32.@]
1675 * PARAMS
1676 * hkey [I] Handle of open key
1677 * lpSubKey [I] Address of name of subkey
1678 * lpNewFile [I] Address of filename for file with new data
1679 * lpOldFile [I] Address of filename for backup file
1681 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1682 LPCWSTR lpOldFile )
1684 FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1685 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1686 return ERROR_SUCCESS;
1690 /******************************************************************************
1691 * RegReplaceKeyA [ADVAPI32.@]
1693 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1694 LPCSTR lpOldFile )
1696 LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1697 LPWSTR lpNewFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile );
1698 LPWSTR lpOldFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile );
1699 LONG ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1700 HeapFree( GetProcessHeap(), 0, lpOldFileW );
1701 HeapFree( GetProcessHeap(), 0, lpNewFileW );
1702 HeapFree( GetProcessHeap(), 0, lpSubKeyW );
1703 return ret;
1707 /******************************************************************************
1708 * RegSetKeySecurity [ADVAPI32.@]
1710 * PARAMS
1711 * hkey [I] Open handle of key to set
1712 * SecurityInfo [I] Descriptor contents
1713 * pSecurityDesc [I] Address of descriptor for key
1715 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1716 PSECURITY_DESCRIPTOR pSecurityDesc )
1718 TRACE("(%p,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1720 /* It seems to perform this check before the hkey check */
1721 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1722 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1723 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1724 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1725 /* Param OK */
1726 } else
1727 return ERROR_INVALID_PARAMETER;
1729 if (!pSecurityDesc)
1730 return ERROR_INVALID_PARAMETER;
1732 FIXME(":(%p,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1734 return ERROR_SUCCESS;
1738 /******************************************************************************
1739 * RegGetKeySecurity [ADVAPI32.@]
1740 * Retrieves a copy of security descriptor protecting the registry key
1742 * PARAMS
1743 * hkey [I] Open handle of key to set
1744 * SecurityInformation [I] Descriptor contents
1745 * pSecurityDescriptor [O] Address of descriptor for key
1746 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1748 * RETURNS
1749 * Success: ERROR_SUCCESS
1750 * Failure: Error code
1752 LONG WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
1753 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1754 LPDWORD lpcbSecurityDescriptor )
1756 TRACE("(%p,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1757 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1759 /* FIXME: Check for valid SecurityInformation values */
1761 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1762 return ERROR_INSUFFICIENT_BUFFER;
1764 FIXME("(%p,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1765 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1767 /* Do not leave security descriptor filled with garbage */
1768 RtlCreateSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
1770 return ERROR_SUCCESS;
1774 /******************************************************************************
1775 * RegFlushKey [ADVAPI32.@]
1776 * Immediately writes key to registry.
1777 * Only returns after data has been written to disk.
1779 * FIXME: does it really wait until data is written ?
1781 * PARAMS
1782 * hkey [I] Handle of key to write
1784 * RETURNS
1785 * Success: ERROR_SUCCESS
1786 * Failure: Error code
1788 DWORD WINAPI RegFlushKey( HKEY hkey )
1790 FIXME( "(%p): stub\n", hkey );
1791 return ERROR_SUCCESS;
1795 /******************************************************************************
1796 * RegConnectRegistryW [ADVAPI32.@]
1798 * PARAMS
1799 * lpMachineName [I] Address of name of remote computer
1800 * hHey [I] Predefined registry handle
1801 * phkResult [I] Address of buffer for remote registry handle
1803 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1804 PHKEY phkResult )
1806 TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1808 if (!lpMachineName || !*lpMachineName) {
1809 /* Use the local machine name */
1810 return RegOpenKeyA( hKey, "", phkResult );
1813 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1814 return ERROR_BAD_NETPATH;
1818 /******************************************************************************
1819 * RegConnectRegistryA [ADVAPI32.@]
1821 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
1823 LPWSTR machineW = HEAP_strdupAtoW( GetProcessHeap(), 0, machine );
1824 DWORD ret = RegConnectRegistryW( machineW, hkey, reskey );
1825 HeapFree( GetProcessHeap(), 0, machineW );
1826 return ret;
1830 /******************************************************************************
1831 * RegNotifyChangeKeyValue [ADVAPI32.@]
1833 * PARAMS
1834 * hkey [I] Handle of key to watch
1835 * fWatchSubTree [I] Flag for subkey notification
1836 * fdwNotifyFilter [I] Changes to be reported
1837 * hEvent [I] Handle of signaled event
1838 * fAsync [I] Flag for asynchronous reporting
1840 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1841 DWORD fdwNotifyFilter, HANDLE hEvent,
1842 BOOL fAsync )
1844 FIXME("(%p,%i,%ld,%p,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1845 hEvent,fAsync);
1846 return ERROR_SUCCESS;