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.
22 #include "wine/winbase16.h"
23 #include "wine/unicode.h"
26 #include "debugtools.h"
28 DEFAULT_DEBUG_CHANNEL(reg);
31 /* check if value type needs string conversion (Ansi<->Unicode) */
32 static inline int is_string( DWORD type )
34 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
37 /* do a server call without setting the last error code */
38 static inline int reg_server_call( enum request req )
40 unsigned int res = server_call_noerr( req );
41 if (res) res = RtlNtStatusToDosError(res);
45 /******************************************************************************
46 * RegCreateKeyExA [ADVAPI32.130]
48 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
49 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
50 LPHKEY retkey, LPDWORD dispos )
52 OBJECT_ATTRIBUTES attr;
53 UNICODE_STRING nameW, classW;
54 ANSI_STRING nameA, classA;
57 if (reserved) return ERROR_INVALID_PARAMETER;
58 if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
60 attr.Length = sizeof(attr);
61 attr.RootDirectory = hkey;
62 attr.ObjectName = &nameW;
64 attr.SecurityDescriptor = NULL;
65 attr.SecurityQualityOfService = NULL;
66 RtlInitAnsiString( &nameA, name );
67 RtlInitAnsiString( &classA, class );
69 /* FIXME: should use Unicode buffer in TEB */
70 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
72 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
74 status = NtCreateKey( retkey, access, &attr, 0, &classW, options, dispos );
75 RtlFreeUnicodeString( &classW );
77 RtlFreeUnicodeString( &nameW );
79 return RtlNtStatusToDosError( status );
83 /******************************************************************************
84 * RegCreateKeyA [ADVAPI32.129]
86 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
88 return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
89 KEY_ALL_ACCESS, NULL, retkey, NULL );
94 /******************************************************************************
95 * RegOpenKeyExA [ADVAPI32.149]
97 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
99 OBJECT_ATTRIBUTES attr;
100 UNICODE_STRING nameW;
104 attr.Length = sizeof(attr);
105 attr.RootDirectory = hkey;
106 attr.ObjectName = &nameW;
108 attr.SecurityDescriptor = NULL;
109 attr.SecurityQualityOfService = NULL;
111 RtlInitAnsiString( &nameA, name );
112 /* FIXME: should use Unicode buffer in TEB */
113 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
115 status = NtOpenKey( retkey, access, &attr );
116 RtlFreeUnicodeString( &nameW );
118 return RtlNtStatusToDosError( status );
122 /******************************************************************************
123 * RegOpenKeyA [ADVAPI32.148]
125 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
127 return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
131 /******************************************************************************
132 * RegEnumKeyExA [ADVAPI32.138]
134 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
135 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
138 char buffer[256], *buf_ptr = buffer;
139 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
142 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
143 name_len ? *name_len : -1, reserved, class, class_len, ft );
145 if (reserved) return ERROR_INVALID_PARAMETER;
147 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
148 buffer, sizeof(buffer), &total_size );
150 while (status == STATUS_BUFFER_OVERFLOW)
152 /* retry with a dynamically allocated buffer */
153 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
154 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
155 return ERROR_NOT_ENOUGH_MEMORY;
156 info = (KEY_NODE_INFORMATION *)buf_ptr;
157 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
158 buf_ptr, total_size, &total_size );
163 DWORD len = WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
164 NULL, 0, NULL, NULL );
165 DWORD cls_len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset),
166 info->ClassLength / sizeof(WCHAR),
167 NULL, 0, NULL, NULL );
169 if (ft) *ft = info->LastWriteTime;
171 if (len >= *name_len || (class_len && (cls_len >= *class_len)))
172 status = STATUS_BUFFER_OVERFLOW;
176 WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
177 name, len, NULL, NULL );
181 *class_len = cls_len;
184 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset),
185 info->ClassLength / sizeof(WCHAR),
186 class, cls_len, NULL, NULL );
193 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
194 return RtlNtStatusToDosError( status );
198 /******************************************************************************
199 * RegEnumKeyA [ADVAPI32.137]
201 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
203 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
207 /******************************************************************************
208 * RegQueryInfoKeyA [ADVAPI32.152]
210 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
211 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
212 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
213 LPDWORD security, FILETIME *modif )
216 char buffer[256], *buf_ptr = buffer;
217 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
220 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
221 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
223 if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
224 return ERROR_INVALID_PARAMETER;
226 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
228 if (class || class_len)
230 /* retry with a dynamically allocated buffer */
231 while (status == STATUS_BUFFER_OVERFLOW)
233 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
234 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
235 return ERROR_NOT_ENOUGH_MEMORY;
236 info = (KEY_FULL_INFORMATION *)buf_ptr;
237 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
242 DWORD len = WideCharToMultiByte( CP_ACP, 0,
243 (WCHAR *)(buf_ptr + info->ClassOffset),
244 info->ClassLength/sizeof(WCHAR),
245 NULL, 0, NULL, NULL );
248 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
251 if (class && !status)
253 WideCharToMultiByte( CP_ACP, 0,
254 (WCHAR *)(buf_ptr + info->ClassOffset),
255 info->ClassLength/sizeof(WCHAR),
256 class, len, NULL, NULL );
262 if (!status || status == STATUS_BUFFER_OVERFLOW)
264 if (subkeys) *subkeys = info->SubKeys;
265 if (max_subkey) *max_subkey = info->MaxNameLen;
266 if (max_class) *max_class = info->MaxClassLen;
267 if (values) *values = info->Values;
268 if (max_value) *max_value = info->MaxValueNameLen;
269 if (max_data) *max_data = info->MaxValueDataLen;
270 if (modif) *modif = info->LastWriteTime;
273 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
274 return RtlNtStatusToDosError( status );
278 /******************************************************************************
279 * RegCloseKey [ADVAPI32.126]
281 * Releases the handle of the specified key
284 * hkey [I] Handle of key to close
287 * Success: ERROR_SUCCESS
288 * Failure: Error code
290 DWORD WINAPI RegCloseKey( HKEY hkey )
292 if (!hkey || hkey >= 0x80000000) return ERROR_SUCCESS;
293 return RtlNtStatusToDosError( NtClose( hkey ) );
297 /******************************************************************************
298 * RegDeleteKeyA [ADVAPI32.133]
300 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
305 if (!name || !*name) return NtDeleteKey( hkey );
306 if (!(ret = RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
308 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
316 /******************************************************************************
317 * RegSetValueExA [ADVAPI32.169]
319 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
320 CONST BYTE *data, DWORD count )
322 UNICODE_STRING nameW;
327 if (count && is_string(type))
329 /* if user forgot to count terminating null, add it (yes NT does this) */
330 if (data[count-1] && !data[count]) count++;
333 if (is_string( type )) /* need to convert to Unicode */
335 DWORD lenW = MultiByteToWideChar( CP_ACP, 0, data, count, NULL, 0 );
336 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW*sizeof(WCHAR) )))
337 return ERROR_OUTOFMEMORY;
338 MultiByteToWideChar( CP_ACP, 0, data, count, dataW, lenW );
339 count = lenW * sizeof(WCHAR);
340 data = (BYTE *)dataW;
343 RtlInitAnsiString( &nameA, name );
344 /* FIXME: should use Unicode buffer in TEB */
345 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
347 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
348 RtlFreeUnicodeString( &nameW );
350 if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
351 return RtlNtStatusToDosError( status );
355 /******************************************************************************
356 * RegSetValueA [ADVAPI32.168]
358 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
363 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
365 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
367 if (name && name[0]) /* need to create the subkey */
369 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
371 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
372 if (subkey != hkey) RegCloseKey( subkey );
378 /******************************************************************************
379 * RegQueryValueExA [ADVAPI32.157]
382 * the documentation is wrong: if the buffer is too small it remains untouched
384 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
385 LPBYTE data, LPDWORD count )
389 UNICODE_STRING nameW;
391 char buffer[256], *buf_ptr = buffer;
392 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
393 static const int info_size = sizeof(*info) - sizeof(info->Data);
395 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
396 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
398 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
400 RtlInitAnsiString( &nameA, name );
401 /* FIXME: should use Unicode buffer in TEB */
402 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
403 return RtlNtStatusToDosError(status);
405 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
406 buffer, sizeof(buffer), &total_size );
407 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
409 /* we need to fetch the contents for a string type even if not requested,
410 * because we need to compute the length of the ASCII string. */
411 if (data || is_string(info->Type))
413 /* retry with a dynamically allocated buffer */
414 while (status == STATUS_BUFFER_OVERFLOW)
416 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
417 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
419 status = STATUS_NO_MEMORY;
422 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
423 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
424 buf_ptr, total_size, &total_size );
429 if (is_string(info->Type))
431 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
432 (total_size - info_size) /sizeof(WCHAR),
433 NULL, 0, NULL, NULL );
436 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
439 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
440 (total_size - info_size) /sizeof(WCHAR),
441 data, len, NULL, NULL );
442 /* if the type is REG_SZ and data is not 0-terminated
443 * and there is enough space in the buffer NT appends a \0 */
444 if (len < *count && data[len-1]) data[len] = 0;
447 total_size = len + info_size;
451 if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
452 else memcpy( data, buf_ptr + info_size, total_size - info_size );
455 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
458 if (type) *type = info->Type;
459 if (count) *count = total_size - info_size;
462 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
463 RtlFreeUnicodeString( &nameW );
464 return RtlNtStatusToDosError(status);
468 /******************************************************************************
469 * RegQueryValueA [ADVAPI32.156]
471 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
476 TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
480 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
482 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
483 if (subkey != hkey) RegCloseKey( subkey );
484 if (ret == ERROR_FILE_NOT_FOUND)
486 /* return empty string if default value not found */
488 if (count) *count = 1;
495 /******************************************************************************
496 * RegEnumValueA [ADVAPI32.141]
498 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
499 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
503 char buffer[256], *buf_ptr = buffer;
504 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
505 static const int info_size = sizeof(*info) - sizeof(info->Name);
507 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
508 hkey, index, value, val_count, reserved, type, data, count );
510 /* NT only checks count, not val_count */
511 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
513 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
514 if (data) total_size += *count;
515 total_size = min( sizeof(buffer), total_size );
517 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
518 buffer, total_size, &total_size );
519 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
521 /* we need to fetch the contents for a string type even if not requested,
522 * because we need to compute the length of the ASCII string. */
523 if (value || data || is_string(info->Type))
525 /* retry with a dynamically allocated buffer */
526 while (status == STATUS_BUFFER_OVERFLOW)
528 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
529 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
530 return ERROR_NOT_ENOUGH_MEMORY;
531 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
532 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
533 buf_ptr, total_size, &total_size );
536 if (status) goto done;
540 DWORD len = WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
541 NULL, 0, NULL, NULL );
542 if (len >= *val_count)
544 status = STATUS_BUFFER_OVERFLOW;
547 WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
548 value, len, NULL, NULL );
553 if (is_string(info->Type))
555 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->DataOffset),
556 (total_size - info->DataOffset) / sizeof(WCHAR),
557 NULL, 0, NULL, NULL );
562 status = STATUS_BUFFER_OVERFLOW;
565 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->DataOffset),
566 (total_size - info->DataOffset) / sizeof(WCHAR),
567 data, len, NULL, NULL );
568 /* if the type is REG_SZ and data is not 0-terminated
569 * and there is enough space in the buffer NT appends a \0 */
570 if (len < *count && data[len-1]) data[len] = 0;
572 info->DataLength = len;
576 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
577 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
581 if (type) *type = info->Type;
582 if (count) *count = info->DataLength;
585 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
586 return RtlNtStatusToDosError(status);
591 /******************************************************************************
592 * RegDeleteValueA [ADVAPI32.135]
594 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
596 UNICODE_STRING nameW;
600 RtlInitAnsiString( &nameA, name );
601 /* FIXME: should use Unicode buffer in TEB */
602 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
604 status = NtDeleteValueKey( hkey, &nameW );
605 RtlFreeUnicodeString( &nameW );
607 return RtlNtStatusToDosError( status );
611 /******************************************************************************
612 * RegLoadKeyA [ADVAPI32.184]
614 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
617 DWORD ret, len, err = GetLastError();
619 TRACE( "(%x,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
621 if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
622 if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
624 len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), NULL, 0 ) * sizeof(WCHAR);
625 if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
627 if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
628 FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
630 ret = GetLastError();
636 struct load_registry_request *req = server_alloc_req( sizeof(*req), len );
639 MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey),
640 server_data_ptr(req), len/sizeof(WCHAR) );
641 ret = reg_server_call( REQ_LOAD_REGISTRY );
647 SetLastError( err ); /* restore the last error code */
652 /******************************************************************************
653 * RegSaveKeyA [ADVAPI32.165]
656 * hkey [I] Handle of key where save begins
657 * lpFile [I] Address of filename to save to
658 * sa [I] Address of security structure
660 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
668 TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa );
670 if (!file || !*file) return ERROR_INVALID_PARAMETER;
672 err = GetLastError();
673 GetFullPathNameA( file, sizeof(buffer), buffer, &name );
676 sprintf( name, "reg%04x.tmp", count++ );
677 handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
678 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
679 if (handle != INVALID_HANDLE_VALUE) break;
680 if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
682 /* Something gone haywire ? Please report if this happens abnormally */
684 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);
689 struct save_registry_request *req = server_alloc_req( sizeof(*req), 0 );
692 ret = reg_server_call( REQ_SAVE_REGISTRY );
696 CloseHandle( handle );
699 if (!MoveFileExA( buffer, file, MOVEFILE_REPLACE_EXISTING ))
701 ERR( "Failed to move %s to %s\n", buffer, file );
702 ret = GetLastError();
705 if (ret) DeleteFileA( buffer );
708 SetLastError( err ); /* restore last error code */