Check for buffer overflows on data returns from RegQueryValueExA.
[wine/multimedia.git] / memory / registry.c
blob22c6919a7bc47d7c0db9f7ef8a750f4209509c9b
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.
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <unistd.h>
19 #include "winbase.h"
20 #include "winreg.h"
21 #include "winerror.h"
22 #include "wine/winbase16.h"
23 #include "wine/unicode.h"
24 #include "wine/winestring.h"
25 #include "heap.h"
26 #include "server.h"
27 #include "debugtools.h"
29 DEFAULT_DEBUG_CHANNEL(reg);
32 /* Unicode->Ansi conversion without string delimiters */
33 static LPSTR memcpyWtoA( LPSTR dst, LPCWSTR src, INT n )
35 LPSTR p = dst;
36 while (n-- > 0) *p++ = (CHAR)*src++;
37 return dst;
40 /* check if value type needs string conversion (Ansi<->Unicode) */
41 static inline int is_string( DWORD type )
43 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
46 /* copy a key name into the request buffer */
47 static inline DWORD copy_nameW( LPWSTR dest, LPCWSTR name )
49 if (name)
51 if (strlenW(name) > MAX_PATH) return ERROR_MORE_DATA;
52 strcpyW( dest, name );
54 else dest[0] = 0;
55 return ERROR_SUCCESS;
58 /* copy a key name into the request buffer */
59 static inline DWORD copy_nameAtoW( LPWSTR dest, LPCSTR name )
61 if (name)
63 if (strlen(name) > MAX_PATH) return ERROR_MORE_DATA;
64 lstrcpyAtoW( dest, name );
66 else dest[0] = 0;
67 return ERROR_SUCCESS;
70 /* do a server call without setting the last error code */
71 static inline int reg_server_call( enum request req )
73 unsigned int res = server_call_noerr( req );
74 if (res) res = RtlNtStatusToDosError(res);
75 return res;
78 /******************************************************************************
79 * RegCreateKeyExW [ADVAPI32.131]
81 * PARAMS
82 * hkey [I] Handle of an open key
83 * name [I] Address of subkey name
84 * reserved [I] Reserved - must be 0
85 * class [I] Address of class string
86 * options [I] Special options flag
87 * access [I] Desired security access
88 * sa [I] Address of key security structure
89 * retkey [O] Address of buffer for opened handle
90 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
92 * NOTES
93 * in case of failing retkey remains untouched
95 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
96 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
97 LPHKEY retkey, LPDWORD dispos )
99 OBJECT_ATTRIBUTES attr;
100 UNICODE_STRING nameW, classW;
102 if (reserved) return ERROR_INVALID_PARAMETER;
103 if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
105 attr.Length = sizeof(attr);
106 attr.RootDirectory = hkey;
107 attr.ObjectName = &nameW;
108 attr.Attributes = 0;
109 attr.SecurityDescriptor = NULL;
110 attr.SecurityQualityOfService = NULL;
111 RtlInitUnicodeString( &nameW, name );
112 RtlInitUnicodeString( &classW, class );
114 return RtlNtStatusToDosError( NtCreateKey( retkey, access, &attr, 0,
115 &classW, options, dispos ) );
119 /******************************************************************************
120 * RegCreateKeyExA [ADVAPI32.130]
122 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
123 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
124 LPHKEY retkey, LPDWORD dispos )
126 OBJECT_ATTRIBUTES attr;
127 UNICODE_STRING nameW, classW;
128 ANSI_STRING nameA, classA;
129 NTSTATUS status;
131 if (reserved) return ERROR_INVALID_PARAMETER;
132 if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
134 attr.Length = sizeof(attr);
135 attr.RootDirectory = hkey;
136 attr.ObjectName = &nameW;
137 attr.Attributes = 0;
138 attr.SecurityDescriptor = NULL;
139 attr.SecurityQualityOfService = NULL;
140 RtlInitAnsiString( &nameA, name );
141 RtlInitAnsiString( &classA, class );
143 /* FIXME: should use Unicode buffer in TEB */
144 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
146 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
148 status = NtCreateKey( retkey, access, &attr, 0, &classW, options, dispos );
149 RtlFreeUnicodeString( &classW );
151 RtlFreeUnicodeString( &nameW );
153 return RtlNtStatusToDosError( status );
157 /******************************************************************************
158 * RegCreateKeyW [ADVAPI32.132]
160 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
162 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
163 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
164 return RegCreateKeyExW( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
165 KEY_ALL_ACCESS, NULL, retkey, NULL );
169 /******************************************************************************
170 * RegCreateKeyA [ADVAPI32.129]
172 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
174 return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
175 KEY_ALL_ACCESS, NULL, retkey, NULL );
180 /******************************************************************************
181 * RegOpenKeyExW [ADVAPI32.150]
183 * Opens the specified key
185 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
187 * PARAMS
188 * hkey [I] Handle of open key
189 * name [I] Name of subkey to open
190 * reserved [I] Reserved - must be zero
191 * access [I] Security access mask
192 * retkey [O] Handle to open key
194 * RETURNS
195 * Success: ERROR_SUCCESS
196 * Failure: Error code
198 * NOTES
199 * in case of failing is retkey = 0
201 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
203 OBJECT_ATTRIBUTES attr;
204 UNICODE_STRING nameW;
206 attr.Length = sizeof(attr);
207 attr.RootDirectory = hkey;
208 attr.ObjectName = &nameW;
209 attr.Attributes = 0;
210 attr.SecurityDescriptor = NULL;
211 attr.SecurityQualityOfService = NULL;
212 RtlInitUnicodeString( &nameW, name );
213 return RtlNtStatusToDosError( NtOpenKey( retkey, access, &attr ) );
217 /******************************************************************************
218 * RegOpenKeyExA [ADVAPI32.149]
220 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
222 OBJECT_ATTRIBUTES attr;
223 UNICODE_STRING nameW;
224 STRING nameA;
225 NTSTATUS status;
227 attr.Length = sizeof(attr);
228 attr.RootDirectory = hkey;
229 attr.ObjectName = &nameW;
230 attr.Attributes = 0;
231 attr.SecurityDescriptor = NULL;
232 attr.SecurityQualityOfService = NULL;
234 RtlInitAnsiString( &nameA, name );
235 /* FIXME: should use Unicode buffer in TEB */
236 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
238 status = NtOpenKey( retkey, access, &attr );
239 RtlFreeUnicodeString( &nameW );
241 return RtlNtStatusToDosError( status );
245 /******************************************************************************
246 * RegOpenKeyW [ADVAPI32.151]
248 * PARAMS
249 * hkey [I] Handle of open key
250 * name [I] Address of name of subkey to open
251 * retkey [O] Handle to open key
253 * RETURNS
254 * Success: ERROR_SUCCESS
255 * Failure: Error code
257 * NOTES
258 * in case of failing is retkey = 0
260 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
262 return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
266 /******************************************************************************
267 * RegOpenKeyA [ADVAPI32.148]
269 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
271 return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
276 /******************************************************************************
277 * RegEnumKeyExW [ADVAPI32.139]
279 * PARAMS
280 * hkey [I] Handle to key to enumerate
281 * index [I] Index of subkey to enumerate
282 * name [O] Buffer for subkey name
283 * name_len [O] Size of subkey buffer
284 * reserved [I] Reserved
285 * class [O] Buffer for class string
286 * class_len [O] Size of class buffer
287 * ft [O] Time key last written to
289 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
290 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
292 NTSTATUS status;
293 char buffer[256], *buf_ptr = buffer;
294 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
295 DWORD total_size;
297 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
298 name_len ? *name_len : -1, reserved, class, class_len, ft );
300 if (reserved) return ERROR_INVALID_PARAMETER;
302 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
303 buffer, sizeof(buffer), &total_size );
305 while (status == STATUS_BUFFER_OVERFLOW)
307 /* retry with a dynamically allocated buffer */
308 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
309 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
310 return ERROR_NOT_ENOUGH_MEMORY;
311 info = (KEY_NODE_INFORMATION *)buf_ptr;
312 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
313 buf_ptr, total_size, &total_size );
316 if (!status)
318 DWORD len = info->NameLength / sizeof(WCHAR);
319 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
321 if (ft) *ft = info->LastWriteTime;
323 if (len >= *name_len || (class_len && (cls_len >= *class_len)))
324 status = STATUS_BUFFER_OVERFLOW;
325 else
327 *name_len = len;
328 memcpy( name, info->Name, info->NameLength );
329 name[len] = 0;
330 if (class_len)
332 *class_len = cls_len;
333 if (class)
335 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
336 class[cls_len] = 0;
342 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
343 return RtlNtStatusToDosError( status );
347 /******************************************************************************
348 * RegEnumKeyExA [ADVAPI32.138]
350 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
351 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
353 NTSTATUS status;
354 char buffer[256], *buf_ptr = buffer;
355 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
356 DWORD total_size;
358 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
359 name_len ? *name_len : -1, reserved, class, class_len, ft );
361 if (reserved) return ERROR_INVALID_PARAMETER;
363 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
364 buffer, sizeof(buffer), &total_size );
366 while (status == STATUS_BUFFER_OVERFLOW)
368 /* retry with a dynamically allocated buffer */
369 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
370 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
371 return ERROR_NOT_ENOUGH_MEMORY;
372 info = (KEY_NODE_INFORMATION *)buf_ptr;
373 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
374 buf_ptr, total_size, &total_size );
377 if (!status)
379 DWORD len = WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
380 NULL, 0, NULL, NULL );
381 DWORD cls_len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset),
382 info->ClassLength / sizeof(WCHAR),
383 NULL, 0, NULL, NULL );
385 if (ft) *ft = info->LastWriteTime;
387 if (len >= *name_len || (class_len && (cls_len >= *class_len)))
388 status = STATUS_BUFFER_OVERFLOW;
389 else
391 *name_len = len;
392 WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
393 name, len, NULL, NULL );
394 name[len] = 0;
395 if (class_len)
397 *class_len = cls_len;
398 if (class)
400 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset),
401 info->ClassLength / sizeof(WCHAR),
402 class, cls_len, NULL, NULL );
403 class[cls_len] = 0;
409 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
410 return RtlNtStatusToDosError( status );
414 /******************************************************************************
415 * RegEnumKeyW [ADVAPI32.140]
417 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
419 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
423 /******************************************************************************
424 * RegEnumKeyA [ADVAPI32.137]
426 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
428 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
432 /******************************************************************************
433 * RegQueryInfoKeyW [ADVAPI32.153]
435 * PARAMS
436 * hkey [I] Handle to key to query
437 * class [O] Buffer for class string
438 * class_len [O] Size of class string buffer
439 * reserved [I] Reserved
440 * subkeys [O] Buffer for number of subkeys
441 * max_subkey [O] Buffer for longest subkey name length
442 * max_class [O] Buffer for longest class string length
443 * values [O] Buffer for number of value entries
444 * max_value [O] Buffer for longest value name length
445 * max_data [O] Buffer for longest value data length
446 * security [O] Buffer for security descriptor length
447 * modif [O] Modification time
449 * - win95 allows class to be valid and class_len to be NULL
450 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
451 * - both allow class to be NULL and class_len to be NULL
452 * (it's hard to test validity, so test !NULL instead)
454 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
455 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
456 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
457 LPDWORD security, FILETIME *modif )
459 NTSTATUS status;
460 char buffer[256], *buf_ptr = buffer;
461 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
462 DWORD total_size;
464 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
465 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
467 if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
468 return ERROR_INVALID_PARAMETER;
470 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
472 if (class)
474 /* retry with a dynamically allocated buffer */
475 while (status == STATUS_BUFFER_OVERFLOW)
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_FULL_INFORMATION *)buf_ptr;
481 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
484 if (!status)
486 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
488 status = STATUS_BUFFER_OVERFLOW;
490 else
492 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
493 class[info->ClassLength/sizeof(WCHAR)] = 0;
498 if (!status || status == STATUS_BUFFER_OVERFLOW)
500 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
501 if (subkeys) *subkeys = info->SubKeys;
502 if (max_subkey) *max_subkey = info->MaxNameLen;
503 if (max_class) *max_class = info->MaxClassLen;
504 if (values) *values = info->Values;
505 if (max_value) *max_value = info->MaxValueNameLen;
506 if (max_data) *max_data = info->MaxValueDataLen;
507 if (modif) *modif = info->LastWriteTime;
510 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
511 return RtlNtStatusToDosError( status );
515 /******************************************************************************
516 * RegQueryInfoKeyA [ADVAPI32.152]
518 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
519 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
520 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
521 LPDWORD security, FILETIME *modif )
523 NTSTATUS status;
524 char buffer[256], *buf_ptr = buffer;
525 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
526 DWORD total_size;
528 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
529 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
531 if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
532 return ERROR_INVALID_PARAMETER;
534 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
536 if (class || class_len)
538 /* retry with a dynamically allocated buffer */
539 while (status == STATUS_BUFFER_OVERFLOW)
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_FULL_INFORMATION *)buf_ptr;
545 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
548 if (!status)
550 DWORD len = WideCharToMultiByte( CP_ACP, 0,
551 (WCHAR *)(buf_ptr + info->ClassOffset),
552 info->ClassLength/sizeof(WCHAR),
553 NULL, 0, NULL, NULL );
554 if (class_len)
556 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
557 *class_len = len;
559 if (class && !status)
561 WideCharToMultiByte( CP_ACP, 0,
562 (WCHAR *)(buf_ptr + info->ClassOffset),
563 info->ClassLength/sizeof(WCHAR),
564 class, len, NULL, NULL );
565 class[len] = 0;
570 if (!status || status == STATUS_BUFFER_OVERFLOW)
572 if (subkeys) *subkeys = info->SubKeys;
573 if (max_subkey) *max_subkey = info->MaxNameLen;
574 if (max_class) *max_class = info->MaxClassLen;
575 if (values) *values = info->Values;
576 if (max_value) *max_value = info->MaxValueNameLen;
577 if (max_data) *max_data = info->MaxValueDataLen;
578 if (modif) *modif = info->LastWriteTime;
581 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
582 return RtlNtStatusToDosError( status );
586 /******************************************************************************
587 * RegCloseKey [ADVAPI32.126]
589 * Releases the handle of the specified key
591 * PARAMS
592 * hkey [I] Handle of key to close
594 * RETURNS
595 * Success: ERROR_SUCCESS
596 * Failure: Error code
598 DWORD WINAPI RegCloseKey( HKEY hkey )
600 if (!hkey || hkey >= 0x80000000) return ERROR_SUCCESS;
601 return RtlNtStatusToDosError( NtClose( hkey ) );
605 /******************************************************************************
606 * RegDeleteKeyW [ADVAPI32.134]
608 * PARAMS
609 * hkey [I] Handle to open key
610 * name [I] Name of subkey to delete
612 * RETURNS
613 * Success: ERROR_SUCCESS
614 * Failure: Error code
616 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
618 DWORD ret;
619 HKEY tmp;
621 if (!name || !*name) return NtDeleteKey( hkey );
622 if (!(ret = RegOpenKeyExW( hkey, name, 0, 0, &tmp )))
624 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
625 RegCloseKey( tmp );
627 return ret;
631 /******************************************************************************
632 * RegDeleteKeyA [ADVAPI32.133]
634 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
636 DWORD ret;
637 HKEY tmp;
639 if (!name || !*name) return NtDeleteKey( hkey );
640 if (!(ret = RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
642 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
643 RegCloseKey( tmp );
645 return ret;
650 /******************************************************************************
651 * RegSetValueExW [ADVAPI32.170]
653 * Sets the data and type of a value under a register key
655 * PARAMS
656 * hkey [I] Handle of key to set value for
657 * name [I] Name of value to set
658 * reserved [I] Reserved - must be zero
659 * type [I] Flag for value type
660 * data [I] Address of value data
661 * count [I] Size of value data
663 * RETURNS
664 * Success: ERROR_SUCCESS
665 * Failure: Error code
667 * NOTES
668 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
669 * NT does definitely care (aj)
671 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
672 DWORD type, CONST BYTE *data, DWORD count )
674 UNICODE_STRING nameW;
676 if (count && is_string(type))
678 LPCWSTR str = (LPCWSTR)data;
679 /* if user forgot to count terminating null, add it (yes NT does this) */
680 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
681 count += sizeof(WCHAR);
684 RtlInitUnicodeString( &nameW, name );
685 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
689 /******************************************************************************
690 * RegSetValueExA [ADVAPI32.169]
692 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
693 CONST BYTE *data, DWORD count )
695 UNICODE_STRING nameW;
696 ANSI_STRING nameA;
697 WCHAR *dataW = NULL;
698 NTSTATUS status;
700 if (count && is_string(type))
702 /* if user forgot to count terminating null, add it (yes NT does this) */
703 if (data[count-1] && !data[count]) count++;
706 if (is_string( type )) /* need to convert to Unicode */
708 DWORD lenW = MultiByteToWideChar( CP_ACP, 0, data, count, NULL, 0 );
709 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW*sizeof(WCHAR) )))
710 return ERROR_OUTOFMEMORY;
711 MultiByteToWideChar( CP_ACP, 0, data, count, dataW, lenW );
712 count = lenW * sizeof(WCHAR);
713 data = (BYTE *)dataW;
716 RtlInitAnsiString( &nameA, name );
717 /* FIXME: should use Unicode buffer in TEB */
718 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
720 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
721 RtlFreeUnicodeString( &nameW );
723 if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
724 return RtlNtStatusToDosError( status );
728 /******************************************************************************
729 * RegSetValueW [ADVAPI32.171]
731 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
733 HKEY subkey = hkey;
734 DWORD ret;
736 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
738 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
740 if (name && name[0]) /* need to create the subkey */
742 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
745 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (LPBYTE)data,
746 (strlenW( data ) + 1) * sizeof(WCHAR) );
747 if (subkey != hkey) RegCloseKey( subkey );
748 return ret;
752 /******************************************************************************
753 * RegSetValueA [ADVAPI32.168]
755 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
757 HKEY subkey = hkey;
758 DWORD ret;
760 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
762 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
764 if (name && name[0]) /* need to create the subkey */
766 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
768 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
769 if (subkey != hkey) RegCloseKey( subkey );
770 return ret;
775 /******************************************************************************
776 * RegQueryValueExW [ADVAPI32.158]
778 * Retrieves type and data for a specified name associated with an open key
780 * PARAMS
781 * hkey [I] Handle of key to query
782 * name [I] Name of value to query
783 * reserved [I] Reserved - must be NULL
784 * type [O] Address of buffer for value type. If NULL, the type
785 * is not required.
786 * data [O] Address of data buffer. If NULL, the actual data is
787 * not required.
788 * count [I/O] Address of data buffer size
790 * RETURNS
791 * ERROR_SUCCESS: Success
792 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
793 * buffer is left untouched. The MS-documentation is wrong (js) !!!
795 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
796 LPBYTE data, LPDWORD count )
798 NTSTATUS status;
799 UNICODE_STRING name_str;
800 DWORD total_size;
801 char buffer[256], *buf_ptr = buffer;
802 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
803 static const int info_size = sizeof(*info) - sizeof(info->Data);
805 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
806 hkey, debugstr_w(name), reserved, type, data, count, count ? *count : 0 );
808 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
810 RtlInitUnicodeString( &name_str, name );
812 if (data) total_size = min( sizeof(buffer), *count + info_size );
813 else total_size = info_size;
815 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
816 buffer, total_size, &total_size );
817 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
819 if (data)
821 /* retry with a dynamically allocated buffer */
822 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
824 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
825 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
826 return ERROR_NOT_ENOUGH_MEMORY;
827 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
828 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
829 buf_ptr, total_size, &total_size );
832 if (!status)
834 memcpy( data, buf_ptr + info_size, total_size - info_size );
835 /* if the type is REG_SZ and data is not 0-terminated
836 * and there is enough space in the buffer NT appends a \0 */
837 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
839 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
840 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
843 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
846 if (type) *type = info->Type;
847 if (count) *count = total_size - info_size;
849 done:
850 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
851 return RtlNtStatusToDosError(status);
855 /******************************************************************************
856 * RegQueryValueExA [ADVAPI32.157]
858 * NOTES:
859 * the documentation is wrong: if the buffer is to small it remains untouched
861 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
862 LPBYTE data, LPDWORD count )
864 NTSTATUS status;
865 ANSI_STRING nameA;
866 UNICODE_STRING nameW;
867 DWORD total_size;
868 char buffer[256], *buf_ptr = buffer;
869 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
870 static const int info_size = sizeof(*info) - sizeof(info->Data);
872 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
873 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
875 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
877 RtlInitAnsiString( &nameA, name );
878 /* FIXME: should use Unicode buffer in TEB */
879 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
880 return RtlNtStatusToDosError(status);
882 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
883 buffer, sizeof(buffer), &total_size );
884 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
886 /* we need to fetch the contents for a string type even if not requested,
887 * because we need to compute the length of the ASCII string. */
888 if (data || is_string(info->Type))
890 /* retry with a dynamically allocated buffer */
891 while (status == STATUS_BUFFER_OVERFLOW)
893 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
894 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
896 status = STATUS_NO_MEMORY;
897 goto done;
899 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
900 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
901 buf_ptr, total_size, &total_size );
904 if (!status)
906 if (is_string(info->Type))
908 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
909 (total_size - info_size) /sizeof(WCHAR),
910 NULL, 0, NULL, NULL );
911 if (data && len)
913 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
914 else
916 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
917 (total_size - info_size) /sizeof(WCHAR),
918 data, len, NULL, NULL );
919 /* if the type is REG_SZ and data is not 0-terminated
920 * and there is enough space in the buffer NT appends a \0 */
921 if (len < *count && data[len-1]) data[len] = 0;
924 total_size = len + info_size;
926 else if (data)
928 if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
929 else memcpy( data, buf_ptr + info_size, total_size - info_size );
932 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
935 if (type) *type = info->Type;
936 if (count) *count = total_size - info_size;
938 done:
939 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
940 RtlFreeUnicodeString( &nameW );
941 return RtlNtStatusToDosError(status);
945 /******************************************************************************
946 * RegQueryValueW [ADVAPI32.159]
948 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
950 DWORD ret;
951 HKEY subkey = hkey;
953 TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
955 if (name && name[0])
957 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
959 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
960 if (subkey != hkey) RegCloseKey( subkey );
961 if (ret == ERROR_FILE_NOT_FOUND)
963 /* return empty string if default value not found */
964 if (data) *data = 0;
965 if (count) *count = 1;
966 ret = ERROR_SUCCESS;
968 return ret;
972 /******************************************************************************
973 * RegQueryValueA [ADVAPI32.156]
975 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
977 DWORD ret;
978 HKEY subkey = hkey;
980 TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
982 if (name && name[0])
984 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
986 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
987 if (subkey != hkey) RegCloseKey( subkey );
988 if (ret == ERROR_FILE_NOT_FOUND)
990 /* return empty string if default value not found */
991 if (data) *data = 0;
992 if (count) *count = 1;
993 ret = ERROR_SUCCESS;
995 return ret;
999 /******************************************************************************
1000 * RegEnumValueW [ADVAPI32.142]
1002 * PARAMS
1003 * hkey [I] Handle to key to query
1004 * index [I] Index of value to query
1005 * value [O] Value string
1006 * val_count [I/O] Size of value buffer (in wchars)
1007 * reserved [I] Reserved
1008 * type [O] Type code
1009 * data [O] Value data
1010 * count [I/O] Size of data buffer (in bytes)
1013 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1014 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1016 DWORD ret, len;
1017 struct enum_key_value_request *req = get_req_buffer();
1019 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1020 hkey, index, value, val_count, reserved, type, data, count );
1022 /* NT only checks count, not val_count */
1023 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1025 req->hkey = hkey;
1026 req->index = index;
1027 req->offset = 0;
1028 if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
1030 len = strlenW( req->name ) + 1;
1031 if (len > *val_count) return ERROR_MORE_DATA;
1032 memcpy( value, req->name, len * sizeof(WCHAR) );
1033 *val_count = len - 1;
1035 if (data)
1037 if (*count < req->len) ret = ERROR_MORE_DATA;
1038 else
1040 /* copy the data */
1041 unsigned int max = server_remaining( req->data );
1042 unsigned int pos = 0;
1043 while (pos < req->len)
1045 unsigned int len = min( req->len - pos, max );
1046 memcpy( data + pos, req->data, len );
1047 if ((pos += len) >= req->len) break;
1048 req->offset = pos;
1049 if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
1052 /* if the type is REG_SZ and data is not 0-terminated
1053 * and there is enough space in the buffer NT appends a \0 */
1054 if (req->len && is_string(req->type) &&
1055 (req->len < *count) && ((WCHAR *)data)[req->len-1]) ((WCHAR *)data)[req->len] = 0;
1057 if (type) *type = req->type;
1058 if (count) *count = req->len;
1059 return ret;
1063 /******************************************************************************
1064 * RegEnumValueA [ADVAPI32.141]
1066 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1067 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1069 DWORD ret, len, total_len;
1070 struct enum_key_value_request *req = get_req_buffer();
1072 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1073 hkey, index, value, val_count, reserved, type, data, count );
1075 /* NT only checks count, not val_count */
1076 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1078 req->hkey = hkey;
1079 req->index = index;
1080 req->offset = 0;
1081 if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
1083 len = strlenW( req->name ) + 1;
1084 if (len > *val_count) return ERROR_MORE_DATA;
1085 memcpyWtoA( value, req->name, len );
1086 *val_count = len - 1;
1088 total_len = is_string( req->type ) ? req->len/sizeof(WCHAR) : req->len;
1090 if (data)
1092 if (*count < total_len) ret = ERROR_MORE_DATA;
1093 else
1095 /* copy the data */
1096 unsigned int max = server_remaining( req->data );
1097 unsigned int pos = 0;
1098 while (pos < req->len)
1100 unsigned int len = min( req->len - pos, max );
1101 if (is_string( req->type ))
1102 memcpyWtoA( data + pos/sizeof(WCHAR), (WCHAR *)req->data, len/sizeof(WCHAR) );
1103 else
1104 memcpy( data + pos, req->data, len );
1105 if ((pos += len) >= req->len) break;
1106 req->offset = pos;
1107 if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
1110 /* if the type is REG_SZ and data is not 0-terminated
1111 * and there is enough space in the buffer NT appends a \0 */
1112 if (total_len && is_string(req->type) && (total_len < *count) && data[total_len-1])
1113 data[total_len] = 0;
1116 if (count) *count = total_len;
1117 if (type) *type = req->type;
1118 return ret;
1123 /******************************************************************************
1124 * RegDeleteValueW [ADVAPI32.136]
1126 * PARAMS
1127 * hkey [I] handle to key
1128 * name [I] name of value to delete
1130 * RETURNS
1131 * error status
1133 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1135 UNICODE_STRING nameW;
1136 RtlInitUnicodeString( &nameW, name );
1137 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1141 /******************************************************************************
1142 * RegDeleteValueA [ADVAPI32.135]
1144 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1146 UNICODE_STRING nameW;
1147 STRING nameA;
1148 NTSTATUS status;
1150 RtlInitAnsiString( &nameA, name );
1151 /* FIXME: should use Unicode buffer in TEB */
1152 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1154 status = NtDeleteValueKey( hkey, &nameW );
1155 RtlFreeUnicodeString( &nameW );
1157 return RtlNtStatusToDosError( status );
1161 /******************************************************************************
1162 * RegLoadKeyW [ADVAPI32.185]
1164 * PARAMS
1165 * hkey [I] Handle of open key
1166 * subkey [I] Address of name of subkey
1167 * filename [I] Address of filename for registry information
1169 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1171 struct load_registry_request *req = get_req_buffer();
1172 HANDLE file;
1173 DWORD ret, err = GetLastError();
1175 TRACE( "(%x,%s,%s)\n", hkey, debugstr_w(subkey), debugstr_w(filename) );
1177 if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1178 if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1180 if ((file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1181 FILE_ATTRIBUTE_NORMAL, -1 )) == INVALID_HANDLE_VALUE)
1183 ret = GetLastError();
1184 goto done;
1186 req->hkey = hkey;
1187 req->file = file;
1188 if ((ret = copy_nameW( req->name, subkey )) != ERROR_SUCCESS) goto done;
1189 ret = reg_server_call( REQ_LOAD_REGISTRY );
1190 CloseHandle( file );
1192 done:
1193 SetLastError( err ); /* restore the last error code */
1194 return ret;
1198 /******************************************************************************
1199 * RegLoadKeyA [ADVAPI32.184]
1201 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1203 struct load_registry_request *req = get_req_buffer();
1204 HANDLE file;
1205 DWORD ret, err = GetLastError();
1207 TRACE( "(%x,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
1209 if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1210 if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1212 if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1213 FILE_ATTRIBUTE_NORMAL, -1 )) == INVALID_HANDLE_VALUE)
1215 ret = GetLastError();
1216 goto done;
1218 req->hkey = hkey;
1219 req->file = file;
1220 if ((ret = copy_nameAtoW( req->name, subkey )) != ERROR_SUCCESS) goto done;
1221 ret = reg_server_call( REQ_LOAD_REGISTRY );
1222 CloseHandle( file );
1224 done:
1225 SetLastError( err ); /* restore the last error code */
1226 return ret;
1230 /******************************************************************************
1231 * RegSaveKeyA [ADVAPI32.165]
1233 * PARAMS
1234 * hkey [I] Handle of key where save begins
1235 * lpFile [I] Address of filename to save to
1236 * sa [I] Address of security structure
1238 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
1240 struct save_registry_request *req = get_req_buffer();
1241 char buffer[1024];
1242 int count = 0;
1243 LPSTR name;
1244 DWORD ret, err;
1245 HFILE handle;
1247 TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa );
1249 if (!file || !*file) return ERROR_INVALID_PARAMETER;
1251 err = GetLastError();
1252 GetFullPathNameA( file, sizeof(buffer), buffer, &name );
1253 for (;;)
1255 sprintf( name, "reg%04x.tmp", count++ );
1256 handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
1257 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1 );
1258 if (handle != INVALID_HANDLE_VALUE) break;
1259 if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
1261 /* Something gone haywire ? Please report if this happens abnormally */
1262 if (count >= 100)
1263 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);
1266 req->hkey = hkey;
1267 req->file = handle;
1268 ret = reg_server_call( REQ_SAVE_REGISTRY );
1269 CloseHandle( handle );
1270 if (!ret)
1272 if (!MoveFileExA( buffer, file, MOVEFILE_REPLACE_EXISTING ))
1274 ERR( "Failed to move %s to %s\n", buffer, file );
1275 ret = GetLastError();
1278 if (ret) DeleteFileA( buffer );
1280 done:
1281 SetLastError( err ); /* restore last error code */
1282 return ret;
1286 /******************************************************************************
1287 * RegSaveKeyW [ADVAPI32.166]
1289 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1291 LPSTR fileA = HEAP_strdupWtoA( GetProcessHeap(), 0, file );
1292 DWORD ret = RegSaveKeyA( hkey, fileA, sa );
1293 if (fileA) HeapFree( GetProcessHeap(), 0, fileA );
1294 return ret;