Include config.h.
[wine/gsoc_dplay.git] / memory / registry.c
blob6cc1023ab39830845ff1386cafc7b60df43035ad
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 "heap.h"
25 #include "server.h"
26 #include "debugtools.h"
28 DEFAULT_DEBUG_CHANNEL(reg);
31 /* Unicode->Ansi conversion without string delimiters */
32 static LPSTR memcpyWtoA( LPSTR dst, LPCWSTR src, INT n )
34 LPSTR p = dst;
35 while (n-- > 0) *p++ = (CHAR)*src++;
36 return dst;
39 /* check if value type needs string conversion (Ansi<->Unicode) */
40 static inline int is_string( DWORD type )
42 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
45 /* do a server call without setting the last error code */
46 static inline int reg_server_call( enum request req )
48 unsigned int res = server_call_noerr( req );
49 if (res) res = RtlNtStatusToDosError(res);
50 return res;
53 /******************************************************************************
54 * RegCreateKeyExW [ADVAPI32.131]
56 * PARAMS
57 * hkey [I] Handle of an open key
58 * name [I] Address of subkey name
59 * reserved [I] Reserved - must be 0
60 * class [I] Address of class string
61 * options [I] Special options flag
62 * access [I] Desired security access
63 * sa [I] Address of key security structure
64 * retkey [O] Address of buffer for opened handle
65 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
67 * NOTES
68 * in case of failing retkey remains untouched
70 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
71 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
72 LPHKEY retkey, LPDWORD dispos )
74 OBJECT_ATTRIBUTES attr;
75 UNICODE_STRING nameW, classW;
77 if (reserved) return ERROR_INVALID_PARAMETER;
78 if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
80 attr.Length = sizeof(attr);
81 attr.RootDirectory = hkey;
82 attr.ObjectName = &nameW;
83 attr.Attributes = 0;
84 attr.SecurityDescriptor = NULL;
85 attr.SecurityQualityOfService = NULL;
86 RtlInitUnicodeString( &nameW, name );
87 RtlInitUnicodeString( &classW, class );
89 return RtlNtStatusToDosError( NtCreateKey( retkey, access, &attr, 0,
90 &classW, options, dispos ) );
94 /******************************************************************************
95 * RegCreateKeyExA [ADVAPI32.130]
97 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
98 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
99 LPHKEY retkey, LPDWORD dispos )
101 OBJECT_ATTRIBUTES attr;
102 UNICODE_STRING nameW, classW;
103 ANSI_STRING nameA, classA;
104 NTSTATUS status;
106 if (reserved) return ERROR_INVALID_PARAMETER;
107 if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
109 attr.Length = sizeof(attr);
110 attr.RootDirectory = hkey;
111 attr.ObjectName = &nameW;
112 attr.Attributes = 0;
113 attr.SecurityDescriptor = NULL;
114 attr.SecurityQualityOfService = NULL;
115 RtlInitAnsiString( &nameA, name );
116 RtlInitAnsiString( &classA, class );
118 /* FIXME: should use Unicode buffer in TEB */
119 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
121 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
123 status = NtCreateKey( retkey, access, &attr, 0, &classW, options, dispos );
124 RtlFreeUnicodeString( &classW );
126 RtlFreeUnicodeString( &nameW );
128 return RtlNtStatusToDosError( status );
132 /******************************************************************************
133 * RegCreateKeyW [ADVAPI32.132]
135 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
137 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
138 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
139 return RegCreateKeyExW( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
140 KEY_ALL_ACCESS, NULL, retkey, NULL );
144 /******************************************************************************
145 * RegCreateKeyA [ADVAPI32.129]
147 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
149 return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
150 KEY_ALL_ACCESS, NULL, retkey, NULL );
155 /******************************************************************************
156 * RegOpenKeyExW [ADVAPI32.150]
158 * Opens the specified key
160 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
162 * PARAMS
163 * hkey [I] Handle of open key
164 * name [I] Name of subkey to open
165 * reserved [I] Reserved - must be zero
166 * access [I] Security access mask
167 * retkey [O] Handle to open key
169 * RETURNS
170 * Success: ERROR_SUCCESS
171 * Failure: Error code
173 * NOTES
174 * in case of failing is retkey = 0
176 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
178 OBJECT_ATTRIBUTES attr;
179 UNICODE_STRING nameW;
181 attr.Length = sizeof(attr);
182 attr.RootDirectory = hkey;
183 attr.ObjectName = &nameW;
184 attr.Attributes = 0;
185 attr.SecurityDescriptor = NULL;
186 attr.SecurityQualityOfService = NULL;
187 RtlInitUnicodeString( &nameW, name );
188 return RtlNtStatusToDosError( NtOpenKey( retkey, access, &attr ) );
192 /******************************************************************************
193 * RegOpenKeyExA [ADVAPI32.149]
195 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
197 OBJECT_ATTRIBUTES attr;
198 UNICODE_STRING nameW;
199 STRING nameA;
200 NTSTATUS status;
202 attr.Length = sizeof(attr);
203 attr.RootDirectory = hkey;
204 attr.ObjectName = &nameW;
205 attr.Attributes = 0;
206 attr.SecurityDescriptor = NULL;
207 attr.SecurityQualityOfService = NULL;
209 RtlInitAnsiString( &nameA, name );
210 /* FIXME: should use Unicode buffer in TEB */
211 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
213 status = NtOpenKey( retkey, access, &attr );
214 RtlFreeUnicodeString( &nameW );
216 return RtlNtStatusToDosError( status );
220 /******************************************************************************
221 * RegOpenKeyW [ADVAPI32.151]
223 * PARAMS
224 * hkey [I] Handle of open key
225 * name [I] Address of name of subkey to open
226 * retkey [O] Handle to open key
228 * RETURNS
229 * Success: ERROR_SUCCESS
230 * Failure: Error code
232 * NOTES
233 * in case of failing is retkey = 0
235 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
237 return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
241 /******************************************************************************
242 * RegOpenKeyA [ADVAPI32.148]
244 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
246 return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
250 /******************************************************************************
251 * RegOpenCurrentUser [ADVAPI32]
252 * FIXME: This function is supposed to retrieve a handle to the
253 * HKEY_CURRENT_USER for the user the current thread is impersonating.
254 * Since Wine does not currently allow threads to impersonate other users,
255 * this stub should work fine.
257 DWORD WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
259 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
264 /******************************************************************************
265 * RegEnumKeyExW [ADVAPI32.139]
267 * PARAMS
268 * hkey [I] Handle to key to enumerate
269 * index [I] Index of subkey to enumerate
270 * name [O] Buffer for subkey name
271 * name_len [O] Size of subkey buffer
272 * reserved [I] Reserved
273 * class [O] Buffer for class string
274 * class_len [O] Size of class buffer
275 * ft [O] Time key last written to
277 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
278 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
280 NTSTATUS status;
281 char buffer[256], *buf_ptr = buffer;
282 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
283 DWORD total_size;
285 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
286 name_len ? *name_len : -1, reserved, class, class_len, ft );
288 if (reserved) return ERROR_INVALID_PARAMETER;
290 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
291 buffer, sizeof(buffer), &total_size );
293 while (status == STATUS_BUFFER_OVERFLOW)
295 /* retry with a dynamically allocated buffer */
296 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
297 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
298 return ERROR_NOT_ENOUGH_MEMORY;
299 info = (KEY_NODE_INFORMATION *)buf_ptr;
300 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
301 buf_ptr, total_size, &total_size );
304 if (!status)
306 DWORD len = info->NameLength / sizeof(WCHAR);
307 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
309 if (ft) *ft = info->LastWriteTime;
311 if (len >= *name_len || (class_len && (cls_len >= *class_len)))
312 status = STATUS_BUFFER_OVERFLOW;
313 else
315 *name_len = len;
316 memcpy( name, info->Name, info->NameLength );
317 name[len] = 0;
318 if (class_len)
320 *class_len = cls_len;
321 if (class)
323 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
324 class[cls_len] = 0;
330 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
331 return RtlNtStatusToDosError( status );
335 /******************************************************************************
336 * RegEnumKeyExA [ADVAPI32.138]
338 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
339 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
341 NTSTATUS status;
342 char buffer[256], *buf_ptr = buffer;
343 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
344 DWORD total_size;
346 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
347 name_len ? *name_len : -1, reserved, class, class_len, ft );
349 if (reserved) return ERROR_INVALID_PARAMETER;
351 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
352 buffer, sizeof(buffer), &total_size );
354 while (status == STATUS_BUFFER_OVERFLOW)
356 /* retry with a dynamically allocated buffer */
357 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
358 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
359 return ERROR_NOT_ENOUGH_MEMORY;
360 info = (KEY_NODE_INFORMATION *)buf_ptr;
361 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
362 buf_ptr, total_size, &total_size );
365 if (!status)
367 DWORD len = WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
368 NULL, 0, NULL, NULL );
369 DWORD cls_len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset),
370 info->ClassLength / sizeof(WCHAR),
371 NULL, 0, NULL, NULL );
373 if (ft) *ft = info->LastWriteTime;
375 if (len >= *name_len || (class_len && (cls_len >= *class_len)))
376 status = STATUS_BUFFER_OVERFLOW;
377 else
379 *name_len = len;
380 WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
381 name, len, NULL, NULL );
382 name[len] = 0;
383 if (class_len)
385 *class_len = cls_len;
386 if (class)
388 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset),
389 info->ClassLength / sizeof(WCHAR),
390 class, cls_len, NULL, NULL );
391 class[cls_len] = 0;
397 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
398 return RtlNtStatusToDosError( status );
402 /******************************************************************************
403 * RegEnumKeyW [ADVAPI32.140]
405 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
407 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
411 /******************************************************************************
412 * RegEnumKeyA [ADVAPI32.137]
414 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
416 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
420 /******************************************************************************
421 * RegQueryInfoKeyW [ADVAPI32.153]
423 * PARAMS
424 * hkey [I] Handle to key to query
425 * class [O] Buffer for class string
426 * class_len [O] Size of class string buffer
427 * reserved [I] Reserved
428 * subkeys [O] Buffer for number of subkeys
429 * max_subkey [O] Buffer for longest subkey name length
430 * max_class [O] Buffer for longest class string length
431 * values [O] Buffer for number of value entries
432 * max_value [O] Buffer for longest value name length
433 * max_data [O] Buffer for longest value data length
434 * security [O] Buffer for security descriptor length
435 * modif [O] Modification time
437 * - win95 allows class to be valid and class_len to be NULL
438 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
439 * - both allow class to be NULL and class_len to be NULL
440 * (it's hard to test validity, so test !NULL instead)
442 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
443 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
444 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
445 LPDWORD security, FILETIME *modif )
447 NTSTATUS status;
448 char buffer[256], *buf_ptr = buffer;
449 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
450 DWORD total_size;
452 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
453 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
455 if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
456 return ERROR_INVALID_PARAMETER;
458 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
460 if (class)
462 /* retry with a dynamically allocated buffer */
463 while (status == STATUS_BUFFER_OVERFLOW)
465 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
466 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
467 return ERROR_NOT_ENOUGH_MEMORY;
468 info = (KEY_FULL_INFORMATION *)buf_ptr;
469 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
472 if (!status)
474 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
476 status = STATUS_BUFFER_OVERFLOW;
478 else
480 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
481 class[info->ClassLength/sizeof(WCHAR)] = 0;
486 if (!status || status == STATUS_BUFFER_OVERFLOW)
488 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
489 if (subkeys) *subkeys = info->SubKeys;
490 if (max_subkey) *max_subkey = info->MaxNameLen;
491 if (max_class) *max_class = info->MaxClassLen;
492 if (values) *values = info->Values;
493 if (max_value) *max_value = info->MaxValueNameLen;
494 if (max_data) *max_data = info->MaxValueDataLen;
495 if (modif) *modif = info->LastWriteTime;
498 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
499 return RtlNtStatusToDosError( status );
503 /******************************************************************************
504 * RegQueryInfoKeyA [ADVAPI32.152]
506 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
507 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
508 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
509 LPDWORD security, FILETIME *modif )
511 NTSTATUS status;
512 char buffer[256], *buf_ptr = buffer;
513 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
514 DWORD total_size;
516 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
517 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
519 if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
520 return ERROR_INVALID_PARAMETER;
522 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
524 if (class || class_len)
526 /* retry with a dynamically allocated buffer */
527 while (status == STATUS_BUFFER_OVERFLOW)
529 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
530 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
531 return ERROR_NOT_ENOUGH_MEMORY;
532 info = (KEY_FULL_INFORMATION *)buf_ptr;
533 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
536 if (!status)
538 DWORD len = WideCharToMultiByte( CP_ACP, 0,
539 (WCHAR *)(buf_ptr + info->ClassOffset),
540 info->ClassLength/sizeof(WCHAR),
541 NULL, 0, NULL, NULL );
542 if (class_len)
544 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
545 *class_len = len;
547 if (class && !status)
549 WideCharToMultiByte( CP_ACP, 0,
550 (WCHAR *)(buf_ptr + info->ClassOffset),
551 info->ClassLength/sizeof(WCHAR),
552 class, len, NULL, NULL );
553 class[len] = 0;
558 if (!status || status == STATUS_BUFFER_OVERFLOW)
560 if (subkeys) *subkeys = info->SubKeys;
561 if (max_subkey) *max_subkey = info->MaxNameLen;
562 if (max_class) *max_class = info->MaxClassLen;
563 if (values) *values = info->Values;
564 if (max_value) *max_value = info->MaxValueNameLen;
565 if (max_data) *max_data = info->MaxValueDataLen;
566 if (modif) *modif = info->LastWriteTime;
569 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
570 return RtlNtStatusToDosError( status );
574 /******************************************************************************
575 * RegCloseKey [ADVAPI32.126]
577 * Releases the handle of the specified key
579 * PARAMS
580 * hkey [I] Handle of key to close
582 * RETURNS
583 * Success: ERROR_SUCCESS
584 * Failure: Error code
586 DWORD WINAPI RegCloseKey( HKEY hkey )
588 if (!hkey || hkey >= 0x80000000) return ERROR_SUCCESS;
589 return RtlNtStatusToDosError( NtClose( hkey ) );
593 /******************************************************************************
594 * RegDeleteKeyW [ADVAPI32.134]
596 * PARAMS
597 * hkey [I] Handle to open key
598 * name [I] Name of subkey to delete
600 * RETURNS
601 * Success: ERROR_SUCCESS
602 * Failure: Error code
604 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
606 DWORD ret;
607 HKEY tmp;
609 if (!name || !*name) return NtDeleteKey( hkey );
610 if (!(ret = RegOpenKeyExW( hkey, name, 0, 0, &tmp )))
612 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
613 RegCloseKey( tmp );
615 return ret;
619 /******************************************************************************
620 * RegDeleteKeyA [ADVAPI32.133]
622 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
624 DWORD ret;
625 HKEY tmp;
627 if (!name || !*name) return NtDeleteKey( hkey );
628 if (!(ret = RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
630 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
631 RegCloseKey( tmp );
633 return ret;
638 /******************************************************************************
639 * RegSetValueExW [ADVAPI32.170]
641 * Sets the data and type of a value under a register key
643 * PARAMS
644 * hkey [I] Handle of key to set value for
645 * name [I] Name of value to set
646 * reserved [I] Reserved - must be zero
647 * type [I] Flag for value type
648 * data [I] Address of value data
649 * count [I] Size of value data
651 * RETURNS
652 * Success: ERROR_SUCCESS
653 * Failure: Error code
655 * NOTES
656 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
657 * NT does definitely care (aj)
659 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
660 DWORD type, CONST BYTE *data, DWORD count )
662 UNICODE_STRING nameW;
664 if (count && is_string(type))
666 LPCWSTR str = (LPCWSTR)data;
667 /* if user forgot to count terminating null, add it (yes NT does this) */
668 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
669 count += sizeof(WCHAR);
672 RtlInitUnicodeString( &nameW, name );
673 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
677 /******************************************************************************
678 * RegSetValueExA [ADVAPI32.169]
680 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
681 CONST BYTE *data, DWORD count )
683 UNICODE_STRING nameW;
684 ANSI_STRING nameA;
685 WCHAR *dataW = NULL;
686 NTSTATUS status;
688 if (count && is_string(type))
690 /* if user forgot to count terminating null, add it (yes NT does this) */
691 if (data[count-1] && !data[count]) count++;
694 if (is_string( type )) /* need to convert to Unicode */
696 DWORD lenW = MultiByteToWideChar( CP_ACP, 0, data, count, NULL, 0 );
697 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW*sizeof(WCHAR) )))
698 return ERROR_OUTOFMEMORY;
699 MultiByteToWideChar( CP_ACP, 0, data, count, dataW, lenW );
700 count = lenW * sizeof(WCHAR);
701 data = (BYTE *)dataW;
704 RtlInitAnsiString( &nameA, name );
705 /* FIXME: should use Unicode buffer in TEB */
706 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
708 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
709 RtlFreeUnicodeString( &nameW );
711 if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
712 return RtlNtStatusToDosError( status );
716 /******************************************************************************
717 * RegSetValueW [ADVAPI32.171]
719 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
721 HKEY subkey = hkey;
722 DWORD ret;
724 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
726 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
728 if (name && name[0]) /* need to create the subkey */
730 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
733 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (LPBYTE)data,
734 (strlenW( data ) + 1) * sizeof(WCHAR) );
735 if (subkey != hkey) RegCloseKey( subkey );
736 return ret;
740 /******************************************************************************
741 * RegSetValueA [ADVAPI32.168]
743 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
745 HKEY subkey = hkey;
746 DWORD ret;
748 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
750 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
752 if (name && name[0]) /* need to create the subkey */
754 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
756 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
757 if (subkey != hkey) RegCloseKey( subkey );
758 return ret;
763 /******************************************************************************
764 * RegQueryValueExW [ADVAPI32.158]
766 * Retrieves type and data for a specified name associated with an open key
768 * PARAMS
769 * hkey [I] Handle of key to query
770 * name [I] Name of value to query
771 * reserved [I] Reserved - must be NULL
772 * type [O] Address of buffer for value type. If NULL, the type
773 * is not required.
774 * data [O] Address of data buffer. If NULL, the actual data is
775 * not required.
776 * count [I/O] Address of data buffer size
778 * RETURNS
779 * ERROR_SUCCESS: Success
780 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
781 * buffer is left untouched. The MS-documentation is wrong (js) !!!
783 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
784 LPBYTE data, LPDWORD count )
786 NTSTATUS status;
787 UNICODE_STRING name_str;
788 DWORD total_size;
789 char buffer[256], *buf_ptr = buffer;
790 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
791 static const int info_size = sizeof(*info) - sizeof(info->Data);
793 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
794 hkey, debugstr_w(name), reserved, type, data, count, count ? *count : 0 );
796 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
798 RtlInitUnicodeString( &name_str, name );
800 if (data) total_size = min( sizeof(buffer), *count + info_size );
801 else total_size = info_size;
803 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
804 buffer, total_size, &total_size );
805 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
807 if (data)
809 /* retry with a dynamically allocated buffer */
810 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
812 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
813 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
814 return ERROR_NOT_ENOUGH_MEMORY;
815 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
816 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
817 buf_ptr, total_size, &total_size );
820 if (!status)
822 memcpy( data, buf_ptr + info_size, total_size - info_size );
823 /* if the type is REG_SZ and data is not 0-terminated
824 * and there is enough space in the buffer NT appends a \0 */
825 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
827 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
828 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
831 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
834 if (type) *type = info->Type;
835 if (count) *count = total_size - info_size;
837 done:
838 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
839 return RtlNtStatusToDosError(status);
843 /******************************************************************************
844 * RegQueryValueExA [ADVAPI32.157]
846 * NOTES:
847 * the documentation is wrong: if the buffer is too small it remains untouched
849 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
850 LPBYTE data, LPDWORD count )
852 NTSTATUS status;
853 ANSI_STRING nameA;
854 UNICODE_STRING nameW;
855 DWORD total_size;
856 char buffer[256], *buf_ptr = buffer;
857 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
858 static const int info_size = sizeof(*info) - sizeof(info->Data);
860 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
861 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
863 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
865 RtlInitAnsiString( &nameA, name );
866 /* FIXME: should use Unicode buffer in TEB */
867 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
868 return RtlNtStatusToDosError(status);
870 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
871 buffer, sizeof(buffer), &total_size );
872 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
874 /* we need to fetch the contents for a string type even if not requested,
875 * because we need to compute the length of the ASCII string. */
876 if (data || is_string(info->Type))
878 /* retry with a dynamically allocated buffer */
879 while (status == STATUS_BUFFER_OVERFLOW)
881 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
882 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
884 status = STATUS_NO_MEMORY;
885 goto done;
887 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
888 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
889 buf_ptr, total_size, &total_size );
892 if (!status)
894 if (is_string(info->Type))
896 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
897 (total_size - info_size) /sizeof(WCHAR),
898 NULL, 0, NULL, NULL );
899 if (data && len)
901 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
902 else
904 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
905 (total_size - info_size) /sizeof(WCHAR),
906 data, len, NULL, NULL );
907 /* if the type is REG_SZ and data is not 0-terminated
908 * and there is enough space in the buffer NT appends a \0 */
909 if (len < *count && data[len-1]) data[len] = 0;
912 total_size = len + info_size;
914 else if (data)
916 if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
917 else memcpy( data, buf_ptr + info_size, total_size - info_size );
920 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
923 if (type) *type = info->Type;
924 if (count) *count = total_size - info_size;
926 done:
927 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
928 RtlFreeUnicodeString( &nameW );
929 return RtlNtStatusToDosError(status);
933 /******************************************************************************
934 * RegQueryValueW [ADVAPI32.159]
936 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
938 DWORD ret;
939 HKEY subkey = hkey;
941 TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
943 if (name && name[0])
945 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
947 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
948 if (subkey != hkey) RegCloseKey( subkey );
949 if (ret == ERROR_FILE_NOT_FOUND)
951 /* return empty string if default value not found */
952 if (data) *data = 0;
953 if (count) *count = 1;
954 ret = ERROR_SUCCESS;
956 return ret;
960 /******************************************************************************
961 * RegQueryValueA [ADVAPI32.156]
963 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
965 DWORD ret;
966 HKEY subkey = hkey;
968 TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
970 if (name && name[0])
972 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
974 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
975 if (subkey != hkey) RegCloseKey( subkey );
976 if (ret == ERROR_FILE_NOT_FOUND)
978 /* return empty string if default value not found */
979 if (data) *data = 0;
980 if (count) *count = 1;
981 ret = ERROR_SUCCESS;
983 return ret;
987 /******************************************************************************
988 * RegEnumValueW [ADVAPI32.142]
990 * PARAMS
991 * hkey [I] Handle to key to query
992 * index [I] Index of value to query
993 * value [O] Value string
994 * val_count [I/O] Size of value buffer (in wchars)
995 * reserved [I] Reserved
996 * type [O] Type code
997 * data [O] Value data
998 * count [I/O] Size of data buffer (in bytes)
1001 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1002 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1004 DWORD ret, len;
1005 struct enum_key_value_request *req = get_req_buffer();
1007 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1008 hkey, index, value, val_count, reserved, type, data, count );
1010 /* NT only checks count, not val_count */
1011 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1013 req->hkey = hkey;
1014 req->index = index;
1015 req->offset = 0;
1016 if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
1018 len = strlenW( req->name ) + 1;
1019 if (len > *val_count) return ERROR_MORE_DATA;
1020 memcpy( value, req->name, len * sizeof(WCHAR) );
1021 *val_count = len - 1;
1023 if (data)
1025 if (*count < req->len) ret = ERROR_MORE_DATA;
1026 else
1028 /* copy the data */
1029 unsigned int max = server_remaining( req->data );
1030 unsigned int pos = 0;
1031 while (pos < req->len)
1033 unsigned int len = min( req->len - pos, max );
1034 memcpy( data + pos, req->data, len );
1035 if ((pos += len) >= req->len) break;
1036 req->offset = pos;
1037 if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
1040 /* if the type is REG_SZ and data is not 0-terminated
1041 * and there is enough space in the buffer NT appends a \0 */
1042 if (req->len && is_string(req->type) &&
1043 (req->len < *count) && ((WCHAR *)data)[req->len-1]) ((WCHAR *)data)[req->len] = 0;
1045 if (type) *type = req->type;
1046 if (count) *count = req->len;
1047 return ret;
1051 /******************************************************************************
1052 * RegEnumValueA [ADVAPI32.141]
1054 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1055 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1057 DWORD ret, len, total_len;
1058 struct enum_key_value_request *req = get_req_buffer();
1060 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1061 hkey, index, value, val_count, reserved, type, data, count );
1063 /* NT only checks count, not val_count */
1064 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1066 req->hkey = hkey;
1067 req->index = index;
1068 req->offset = 0;
1069 if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
1071 len = strlenW( req->name ) + 1;
1072 if (len > *val_count) return ERROR_MORE_DATA;
1073 memcpyWtoA( value, req->name, len );
1074 *val_count = len - 1;
1076 total_len = is_string( req->type ) ? req->len/sizeof(WCHAR) : req->len;
1078 if (data)
1080 if (*count < total_len) ret = ERROR_MORE_DATA;
1081 else
1083 /* copy the data */
1084 unsigned int max = server_remaining( req->data );
1085 unsigned int pos = 0;
1086 while (pos < req->len)
1088 unsigned int len = min( req->len - pos, max );
1089 if (is_string( req->type ))
1090 memcpyWtoA( data + pos/sizeof(WCHAR), (WCHAR *)req->data, len/sizeof(WCHAR) );
1091 else
1092 memcpy( data + pos, req->data, len );
1093 if ((pos += len) >= req->len) break;
1094 req->offset = pos;
1095 if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
1098 /* if the type is REG_SZ and data is not 0-terminated
1099 * and there is enough space in the buffer NT appends a \0 */
1100 if (total_len && is_string(req->type) && (total_len < *count) && data[total_len-1])
1101 data[total_len] = 0;
1104 if (count) *count = total_len;
1105 if (type) *type = req->type;
1106 return ret;
1111 /******************************************************************************
1112 * RegDeleteValueW [ADVAPI32.136]
1114 * PARAMS
1115 * hkey [I] handle to key
1116 * name [I] name of value to delete
1118 * RETURNS
1119 * error status
1121 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1123 UNICODE_STRING nameW;
1124 RtlInitUnicodeString( &nameW, name );
1125 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1129 /******************************************************************************
1130 * RegDeleteValueA [ADVAPI32.135]
1132 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1134 UNICODE_STRING nameW;
1135 STRING nameA;
1136 NTSTATUS status;
1138 RtlInitAnsiString( &nameA, name );
1139 /* FIXME: should use Unicode buffer in TEB */
1140 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1142 status = NtDeleteValueKey( hkey, &nameW );
1143 RtlFreeUnicodeString( &nameW );
1145 return RtlNtStatusToDosError( status );
1149 /******************************************************************************
1150 * RegLoadKeyW [ADVAPI32.185]
1152 * PARAMS
1153 * hkey [I] Handle of open key
1154 * subkey [I] Address of name of subkey
1155 * filename [I] Address of filename for registry information
1157 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1159 HANDLE file;
1160 DWORD ret, len, err = GetLastError();
1162 TRACE( "(%x,%s,%s)\n", hkey, debugstr_w(subkey), debugstr_w(filename) );
1164 if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1165 if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1167 len = strlenW( subkey ) * sizeof(WCHAR);
1168 if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
1170 if ((file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1171 FILE_ATTRIBUTE_NORMAL, -1 )) == INVALID_HANDLE_VALUE)
1173 ret = GetLastError();
1174 goto done;
1177 SERVER_START_REQ
1179 struct load_registry_request *req = server_alloc_req( sizeof(*req), len );
1180 req->hkey = hkey;
1181 req->file = file;
1182 memcpy( server_data_ptr(req), subkey, len );
1183 ret = reg_server_call( REQ_LOAD_REGISTRY );
1185 SERVER_END_REQ;
1186 CloseHandle( file );
1188 done:
1189 SetLastError( err ); /* restore the last error code */
1190 return ret;
1194 /******************************************************************************
1195 * RegLoadKeyA [ADVAPI32.184]
1197 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1199 HANDLE file;
1200 DWORD ret, len, err = GetLastError();
1202 TRACE( "(%x,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
1204 if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1205 if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1207 len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), NULL, 0 ) * sizeof(WCHAR);
1208 if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
1210 if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1211 FILE_ATTRIBUTE_NORMAL, -1 )) == INVALID_HANDLE_VALUE)
1213 ret = GetLastError();
1214 goto done;
1217 SERVER_START_REQ
1219 struct load_registry_request *req = server_alloc_req( sizeof(*req), len );
1220 req->hkey = hkey;
1221 req->file = file;
1222 MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey),
1223 server_data_ptr(req), len/sizeof(WCHAR) );
1224 ret = reg_server_call( REQ_LOAD_REGISTRY );
1226 SERVER_END_REQ;
1227 CloseHandle( file );
1229 done:
1230 SetLastError( err ); /* restore the last error code */
1231 return ret;
1235 /******************************************************************************
1236 * RegSaveKeyA [ADVAPI32.165]
1238 * PARAMS
1239 * hkey [I] Handle of key where save begins
1240 * lpFile [I] Address of filename to save to
1241 * sa [I] Address of security structure
1243 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
1245 char buffer[1024];
1246 int count = 0;
1247 LPSTR name;
1248 DWORD ret, err;
1249 HFILE handle;
1251 TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa );
1253 if (!file || !*file) return ERROR_INVALID_PARAMETER;
1255 err = GetLastError();
1256 GetFullPathNameA( file, sizeof(buffer), buffer, &name );
1257 for (;;)
1259 sprintf( name, "reg%04x.tmp", count++ );
1260 handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
1261 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1 );
1262 if (handle != INVALID_HANDLE_VALUE) break;
1263 if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
1265 /* Something gone haywire ? Please report if this happens abnormally */
1266 if (count >= 100)
1267 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);
1270 SERVER_START_REQ
1272 struct save_registry_request *req = server_alloc_req( sizeof(*req), 0 );
1273 req->hkey = hkey;
1274 req->file = handle;
1275 ret = reg_server_call( REQ_SAVE_REGISTRY );
1277 SERVER_END_REQ;
1279 CloseHandle( handle );
1280 if (!ret)
1282 if (!MoveFileExA( buffer, file, MOVEFILE_REPLACE_EXISTING ))
1284 ERR( "Failed to move %s to %s\n", buffer, file );
1285 ret = GetLastError();
1288 if (ret) DeleteFileA( buffer );
1290 done:
1291 SetLastError( err ); /* restore last error code */
1292 return ret;
1296 /******************************************************************************
1297 * RegSaveKeyW [ADVAPI32.166]
1299 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1301 LPSTR fileA = HEAP_strdupWtoA( GetProcessHeap(), 0, file );
1302 DWORD ret = RegSaveKeyA( hkey, fileA, sa );
1303 if (fileA) HeapFree( GetProcessHeap(), 0, fileA );
1304 return ret;