Documentation ordinal fixes.
[wine/multimedia.git] / dlls / advapi32 / registry.c
blobbfb764dc74f9ce656ba2cb255091cb2530bb81f9
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/unicode.h"
23 #include "heap.h"
24 #include "server.h"
25 #include "debugtools.h"
27 DEFAULT_DEBUG_CHANNEL(reg);
30 /* check if value type needs string conversion (Ansi<->Unicode) */
31 static inline int is_string( DWORD type )
33 return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
36 /* do a server call without setting the last error code */
37 static inline int reg_server_call( enum request req )
39 unsigned int res = server_call_noerr( req );
40 if (res) res = RtlNtStatusToDosError(res);
41 return res;
44 /******************************************************************************
45 * RegCreateKeyExW [ADVAPI32.@]
47 * PARAMS
48 * hkey [I] Handle of an open key
49 * name [I] Address of subkey name
50 * reserved [I] Reserved - must be 0
51 * class [I] Address of class string
52 * options [I] Special options flag
53 * access [I] Desired security access
54 * sa [I] Address of key security structure
55 * retkey [O] Address of buffer for opened handle
56 * dispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
58 * NOTES
59 * in case of failing retkey remains untouched
61 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
62 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
63 LPHKEY retkey, LPDWORD dispos )
65 OBJECT_ATTRIBUTES attr;
66 UNICODE_STRING nameW, classW;
68 if (reserved) return ERROR_INVALID_PARAMETER;
69 if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
71 attr.Length = sizeof(attr);
72 attr.RootDirectory = hkey;
73 attr.ObjectName = &nameW;
74 attr.Attributes = 0;
75 attr.SecurityDescriptor = NULL;
76 attr.SecurityQualityOfService = NULL;
77 RtlInitUnicodeString( &nameW, name );
78 RtlInitUnicodeString( &classW, class );
80 return RtlNtStatusToDosError( NtCreateKey( retkey, access, &attr, 0,
81 &classW, options, dispos ) );
85 /******************************************************************************
86 * RegCreateKeyExA [ADVAPI32.@]
88 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
89 DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
90 LPHKEY retkey, LPDWORD dispos )
92 OBJECT_ATTRIBUTES attr;
93 UNICODE_STRING nameW, classW;
94 ANSI_STRING nameA, classA;
95 NTSTATUS status;
97 if (reserved) return ERROR_INVALID_PARAMETER;
98 if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
100 attr.Length = sizeof(attr);
101 attr.RootDirectory = hkey;
102 attr.ObjectName = &nameW;
103 attr.Attributes = 0;
104 attr.SecurityDescriptor = NULL;
105 attr.SecurityQualityOfService = NULL;
106 RtlInitAnsiString( &nameA, name );
107 RtlInitAnsiString( &classA, class );
109 /* FIXME: should use Unicode buffer in TEB */
110 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
112 if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
114 status = NtCreateKey( retkey, access, &attr, 0, &classW, options, dispos );
115 RtlFreeUnicodeString( &classW );
117 RtlFreeUnicodeString( &nameW );
119 return RtlNtStatusToDosError( status );
123 /******************************************************************************
124 * RegCreateKeyW [ADVAPI32.@]
126 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
128 /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
129 /* but at least my version of NT (4.0 SP5) doesn't do this. -- AJ */
130 return RegCreateKeyExW( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
131 KEY_ALL_ACCESS, NULL, retkey, NULL );
135 /******************************************************************************
136 * RegCreateKeyA [ADVAPI32.@]
138 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
140 return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
141 KEY_ALL_ACCESS, NULL, retkey, NULL );
146 /******************************************************************************
147 * RegOpenKeyExW [ADVAPI32.@]
149 * Opens the specified key
151 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
153 * PARAMS
154 * hkey [I] Handle of open key
155 * name [I] Name of subkey to open
156 * reserved [I] Reserved - must be zero
157 * access [I] Security access mask
158 * retkey [O] Handle to open key
160 * RETURNS
161 * Success: ERROR_SUCCESS
162 * Failure: Error code
164 * NOTES
165 * in case of failing is retkey = 0
167 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
169 OBJECT_ATTRIBUTES attr;
170 UNICODE_STRING nameW;
172 attr.Length = sizeof(attr);
173 attr.RootDirectory = hkey;
174 attr.ObjectName = &nameW;
175 attr.Attributes = 0;
176 attr.SecurityDescriptor = NULL;
177 attr.SecurityQualityOfService = NULL;
178 RtlInitUnicodeString( &nameW, name );
179 return RtlNtStatusToDosError( NtOpenKey( retkey, access, &attr ) );
183 /******************************************************************************
184 * RegOpenKeyExA [ADVAPI32.@]
186 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
188 OBJECT_ATTRIBUTES attr;
189 UNICODE_STRING nameW;
190 STRING nameA;
191 NTSTATUS status;
193 attr.Length = sizeof(attr);
194 attr.RootDirectory = hkey;
195 attr.ObjectName = &nameW;
196 attr.Attributes = 0;
197 attr.SecurityDescriptor = NULL;
198 attr.SecurityQualityOfService = NULL;
200 RtlInitAnsiString( &nameA, name );
201 /* FIXME: should use Unicode buffer in TEB */
202 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
204 status = NtOpenKey( retkey, access, &attr );
205 RtlFreeUnicodeString( &nameW );
207 return RtlNtStatusToDosError( status );
211 /******************************************************************************
212 * RegOpenKeyW [ADVAPI32.@]
214 * PARAMS
215 * hkey [I] Handle of open key
216 * name [I] Address of name of subkey to open
217 * retkey [O] Handle to open key
219 * RETURNS
220 * Success: ERROR_SUCCESS
221 * Failure: Error code
223 * NOTES
224 * in case of failing is retkey = 0
226 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
228 return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
232 /******************************************************************************
233 * RegOpenKeyA [ADVAPI32.@]
235 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
237 return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
241 /******************************************************************************
242 * RegOpenCurrentUser [ADVAPI32.@]
243 * FIXME: This function is supposed to retrieve a handle to the
244 * HKEY_CURRENT_USER for the user the current thread is impersonating.
245 * Since Wine does not currently allow threads to impersonate other users,
246 * this stub should work fine.
248 DWORD WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
250 return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
255 /******************************************************************************
256 * RegEnumKeyExW [ADVAPI32.@]
258 * PARAMS
259 * hkey [I] Handle to key to enumerate
260 * index [I] Index of subkey to enumerate
261 * name [O] Buffer for subkey name
262 * name_len [O] Size of subkey buffer
263 * reserved [I] Reserved
264 * class [O] Buffer for class string
265 * class_len [O] Size of class buffer
266 * ft [O] Time key last written to
268 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
269 LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
271 NTSTATUS status;
272 char buffer[256], *buf_ptr = buffer;
273 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
274 DWORD total_size;
276 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
277 name_len ? *name_len : -1, reserved, class, class_len, ft );
279 if (reserved) return ERROR_INVALID_PARAMETER;
281 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
282 buffer, sizeof(buffer), &total_size );
284 while (status == STATUS_BUFFER_OVERFLOW)
286 /* retry with a dynamically allocated buffer */
287 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
288 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
289 return ERROR_NOT_ENOUGH_MEMORY;
290 info = (KEY_NODE_INFORMATION *)buf_ptr;
291 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
292 buf_ptr, total_size, &total_size );
295 if (!status)
297 DWORD len = info->NameLength / sizeof(WCHAR);
298 DWORD cls_len = info->ClassLength / sizeof(WCHAR);
300 if (ft) *ft = info->LastWriteTime;
302 if (len >= *name_len || (class_len && (cls_len >= *class_len)))
303 status = STATUS_BUFFER_OVERFLOW;
304 else
306 *name_len = len;
307 memcpy( name, info->Name, info->NameLength );
308 name[len] = 0;
309 if (class_len)
311 *class_len = cls_len;
312 if (class)
314 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
315 class[cls_len] = 0;
321 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
322 return RtlNtStatusToDosError( status );
326 /******************************************************************************
327 * RegEnumKeyExA [ADVAPI32.@]
329 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
330 LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
332 NTSTATUS status;
333 char buffer[256], *buf_ptr = buffer;
334 KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
335 DWORD total_size;
337 TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
338 name_len ? *name_len : -1, reserved, class, class_len, ft );
340 if (reserved) return ERROR_INVALID_PARAMETER;
342 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
343 buffer, sizeof(buffer), &total_size );
345 while (status == STATUS_BUFFER_OVERFLOW)
347 /* retry with a dynamically allocated buffer */
348 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
349 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
350 return ERROR_NOT_ENOUGH_MEMORY;
351 info = (KEY_NODE_INFORMATION *)buf_ptr;
352 status = NtEnumerateKey( hkey, index, KeyNodeInformation,
353 buf_ptr, total_size, &total_size );
356 if (!status)
358 DWORD len = WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
359 NULL, 0, NULL, NULL );
360 DWORD cls_len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset),
361 info->ClassLength / sizeof(WCHAR),
362 NULL, 0, NULL, NULL );
364 if (ft) *ft = info->LastWriteTime;
366 if (len >= *name_len || (class_len && (cls_len >= *class_len)))
367 status = STATUS_BUFFER_OVERFLOW;
368 else
370 *name_len = len;
371 WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
372 name, len, NULL, NULL );
373 name[len] = 0;
374 if (class_len)
376 *class_len = cls_len;
377 if (class)
379 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset),
380 info->ClassLength / sizeof(WCHAR),
381 class, cls_len, NULL, NULL );
382 class[cls_len] = 0;
388 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
389 return RtlNtStatusToDosError( status );
393 /******************************************************************************
394 * RegEnumKeyW [ADVAPI32.@]
396 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
398 return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
402 /******************************************************************************
403 * RegEnumKeyA [ADVAPI32.@]
405 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
407 return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
411 /******************************************************************************
412 * RegQueryInfoKeyW [ADVAPI32.@]
414 * PARAMS
415 * hkey [I] Handle to key to query
416 * class [O] Buffer for class string
417 * class_len [O] Size of class string buffer
418 * reserved [I] Reserved
419 * subkeys [O] Buffer for number of subkeys
420 * max_subkey [O] Buffer for longest subkey name length
421 * max_class [O] Buffer for longest class string length
422 * values [O] Buffer for number of value entries
423 * max_value [O] Buffer for longest value name length
424 * max_data [O] Buffer for longest value data length
425 * security [O] Buffer for security descriptor length
426 * modif [O] Modification time
428 * - win95 allows class to be valid and class_len to be NULL
429 * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
430 * - both allow class to be NULL and class_len to be NULL
431 * (it's hard to test validity, so test !NULL instead)
433 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
434 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
435 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
436 LPDWORD security, FILETIME *modif )
438 NTSTATUS status;
439 char buffer[256], *buf_ptr = buffer;
440 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
441 DWORD total_size;
443 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
444 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
446 if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
447 return ERROR_INVALID_PARAMETER;
449 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
450 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
452 if (class)
454 /* retry with a dynamically allocated buffer */
455 while (status == STATUS_BUFFER_OVERFLOW)
457 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
458 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
459 return ERROR_NOT_ENOUGH_MEMORY;
460 info = (KEY_FULL_INFORMATION *)buf_ptr;
461 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
464 if (status) goto done;
466 if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
468 status = STATUS_BUFFER_OVERFLOW;
470 else
472 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
473 class[info->ClassLength/sizeof(WCHAR)] = 0;
476 else status = STATUS_SUCCESS;
478 if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
479 if (subkeys) *subkeys = info->SubKeys;
480 if (max_subkey) *max_subkey = info->MaxNameLen;
481 if (max_class) *max_class = info->MaxClassLen;
482 if (values) *values = info->Values;
483 if (max_value) *max_value = info->MaxValueNameLen;
484 if (max_data) *max_data = info->MaxValueDataLen;
485 if (modif) *modif = info->LastWriteTime;
487 done:
488 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
489 return RtlNtStatusToDosError( status );
493 /******************************************************************************
494 * RegQueryInfoKeyA [ADVAPI32.@]
496 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
497 LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
498 LPDWORD values, LPDWORD max_value, LPDWORD max_data,
499 LPDWORD security, FILETIME *modif )
501 NTSTATUS status;
502 char buffer[256], *buf_ptr = buffer;
503 KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
504 DWORD total_size, len;
506 TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
507 reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
509 if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
510 return ERROR_INVALID_PARAMETER;
512 status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
513 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
515 if (class || class_len)
517 /* retry with a dynamically allocated buffer */
518 while (status == STATUS_BUFFER_OVERFLOW)
520 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
521 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
522 return ERROR_NOT_ENOUGH_MEMORY;
523 info = (KEY_FULL_INFORMATION *)buf_ptr;
524 status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
527 if (status) goto done;
529 len = WideCharToMultiByte( CP_ACP, 0,
530 (WCHAR *)(buf_ptr + info->ClassOffset),
531 info->ClassLength/sizeof(WCHAR),
532 NULL, 0, NULL, NULL );
533 if (class_len)
535 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
536 *class_len = len;
538 if (class && !status)
540 WideCharToMultiByte( CP_ACP, 0,
541 (WCHAR *)(buf_ptr + info->ClassOffset),
542 info->ClassLength/sizeof(WCHAR),
543 class, len, NULL, NULL );
544 class[len] = 0;
547 else status = STATUS_SUCCESS;
549 if (subkeys) *subkeys = info->SubKeys;
550 if (max_subkey) *max_subkey = info->MaxNameLen;
551 if (max_class) *max_class = info->MaxClassLen;
552 if (values) *values = info->Values;
553 if (max_value) *max_value = info->MaxValueNameLen;
554 if (max_data) *max_data = info->MaxValueDataLen;
555 if (modif) *modif = info->LastWriteTime;
557 done:
558 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
559 return RtlNtStatusToDosError( status );
563 /******************************************************************************
564 * RegCloseKey [ADVAPI32.@]
566 * Releases the handle of the specified key
568 * PARAMS
569 * hkey [I] Handle of key to close
571 * RETURNS
572 * Success: ERROR_SUCCESS
573 * Failure: Error code
575 DWORD WINAPI RegCloseKey( HKEY hkey )
577 if (!hkey || hkey >= 0x80000000) return ERROR_SUCCESS;
578 return RtlNtStatusToDosError( NtClose( hkey ) );
582 /******************************************************************************
583 * RegDeleteKeyW [ADVAPI32.@]
585 * PARAMS
586 * hkey [I] Handle to open key
587 * name [I] Name of subkey to delete
589 * RETURNS
590 * Success: ERROR_SUCCESS
591 * Failure: Error code
593 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
595 DWORD ret;
596 HKEY tmp;
598 if (!name || !*name) return NtDeleteKey( hkey );
599 if (!(ret = RegOpenKeyExW( hkey, name, 0, 0, &tmp )))
601 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
602 RegCloseKey( tmp );
604 return ret;
608 /******************************************************************************
609 * RegDeleteKeyA [ADVAPI32.@]
611 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
613 DWORD ret;
614 HKEY tmp;
616 if (!name || !*name) return NtDeleteKey( hkey );
617 if (!(ret = RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
619 ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
620 RegCloseKey( tmp );
622 return ret;
627 /******************************************************************************
628 * RegSetValueExW [ADVAPI32.@]
630 * Sets the data and type of a value under a register key
632 * PARAMS
633 * hkey [I] Handle of key to set value for
634 * name [I] Name of value to set
635 * reserved [I] Reserved - must be zero
636 * type [I] Flag for value type
637 * data [I] Address of value data
638 * count [I] Size of value data
640 * RETURNS
641 * Success: ERROR_SUCCESS
642 * Failure: Error code
644 * NOTES
645 * win95 does not care about count for REG_SZ and finds out the len by itself (js)
646 * NT does definitely care (aj)
648 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
649 DWORD type, CONST BYTE *data, DWORD count )
651 UNICODE_STRING nameW;
653 if (count && is_string(type))
655 LPCWSTR str = (LPCWSTR)data;
656 /* if user forgot to count terminating null, add it (yes NT does this) */
657 if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
658 count += sizeof(WCHAR);
661 RtlInitUnicodeString( &nameW, name );
662 return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
666 /******************************************************************************
667 * RegSetValueExA [ADVAPI32.@]
669 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
670 CONST BYTE *data, DWORD count )
672 UNICODE_STRING nameW;
673 ANSI_STRING nameA;
674 WCHAR *dataW = NULL;
675 NTSTATUS status;
677 if (count && is_string(type))
679 /* if user forgot to count terminating null, add it (yes NT does this) */
680 if (data[count-1] && !data[count]) count++;
683 if (is_string( type )) /* need to convert to Unicode */
685 DWORD lenW = MultiByteToWideChar( CP_ACP, 0, data, count, NULL, 0 );
686 if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW*sizeof(WCHAR) )))
687 return ERROR_OUTOFMEMORY;
688 MultiByteToWideChar( CP_ACP, 0, data, count, dataW, lenW );
689 count = lenW * sizeof(WCHAR);
690 data = (BYTE *)dataW;
693 RtlInitAnsiString( &nameA, name );
694 /* FIXME: should use Unicode buffer in TEB */
695 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
697 status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
698 RtlFreeUnicodeString( &nameW );
700 if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
701 return RtlNtStatusToDosError( status );
705 /******************************************************************************
706 * RegSetValueW [ADVAPI32.@]
708 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
710 HKEY subkey = hkey;
711 DWORD ret;
713 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
715 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
717 if (name && name[0]) /* need to create the subkey */
719 if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
722 ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (LPBYTE)data,
723 (strlenW( data ) + 1) * sizeof(WCHAR) );
724 if (subkey != hkey) RegCloseKey( subkey );
725 return ret;
729 /******************************************************************************
730 * RegSetValueA [ADVAPI32.@]
732 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
734 HKEY subkey = hkey;
735 DWORD ret;
737 TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
739 if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
741 if (name && name[0]) /* need to create the subkey */
743 if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
745 ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
746 if (subkey != hkey) RegCloseKey( subkey );
747 return ret;
752 /******************************************************************************
753 * RegQueryValueExW [ADVAPI32.@]
755 * Retrieves type and data for a specified name associated with an open key
757 * PARAMS
758 * hkey [I] Handle of key to query
759 * name [I] Name of value to query
760 * reserved [I] Reserved - must be NULL
761 * type [O] Address of buffer for value type. If NULL, the type
762 * is not required.
763 * data [O] Address of data buffer. If NULL, the actual data is
764 * not required.
765 * count [I/O] Address of data buffer size
767 * RETURNS
768 * ERROR_SUCCESS: Success
769 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
770 * buffer is left untouched. The MS-documentation is wrong (js) !!!
772 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
773 LPBYTE data, LPDWORD count )
775 NTSTATUS status;
776 UNICODE_STRING name_str;
777 DWORD total_size;
778 char buffer[256], *buf_ptr = buffer;
779 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
780 static const int info_size = sizeof(*info) - sizeof(info->Data);
782 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
783 hkey, debugstr_w(name), reserved, type, data, count, count ? *count : 0 );
785 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
787 RtlInitUnicodeString( &name_str, name );
789 if (data) total_size = min( sizeof(buffer), *count + info_size );
790 else total_size = info_size;
792 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
793 buffer, total_size, &total_size );
794 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
796 if (data)
798 /* retry with a dynamically allocated buffer */
799 while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
801 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
802 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
803 return ERROR_NOT_ENOUGH_MEMORY;
804 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
805 status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
806 buf_ptr, total_size, &total_size );
809 if (!status)
811 memcpy( data, buf_ptr + info_size, total_size - info_size );
812 /* if the type is REG_SZ and data is not 0-terminated
813 * and there is enough space in the buffer NT appends a \0 */
814 if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
816 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
817 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
820 else if (status != STATUS_BUFFER_OVERFLOW) goto done;
822 else status = STATUS_SUCCESS;
824 if (type) *type = info->Type;
825 if (count) *count = total_size - info_size;
827 done:
828 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
829 return RtlNtStatusToDosError(status);
833 /******************************************************************************
834 * RegQueryValueExA [ADVAPI32.@]
836 * NOTES:
837 * the documentation is wrong: if the buffer is too small it remains untouched
839 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
840 LPBYTE data, LPDWORD count )
842 NTSTATUS status;
843 ANSI_STRING nameA;
844 UNICODE_STRING nameW;
845 DWORD total_size;
846 char buffer[256], *buf_ptr = buffer;
847 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
848 static const int info_size = sizeof(*info) - sizeof(info->Data);
850 TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
851 hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
853 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
855 RtlInitAnsiString( &nameA, name );
856 /* FIXME: should use Unicode buffer in TEB */
857 if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
858 return RtlNtStatusToDosError(status);
860 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
861 buffer, sizeof(buffer), &total_size );
862 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
864 /* we need to fetch the contents for a string type even if not requested,
865 * because we need to compute the length of the ASCII string. */
866 if (data || is_string(info->Type))
868 /* retry with a dynamically allocated buffer */
869 while (status == STATUS_BUFFER_OVERFLOW)
871 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
872 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
874 status = STATUS_NO_MEMORY;
875 goto done;
877 info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
878 status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
879 buf_ptr, total_size, &total_size );
882 if (status) goto done;
884 if (is_string(info->Type))
886 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
887 (total_size - info_size) /sizeof(WCHAR),
888 NULL, 0, NULL, NULL );
889 if (data && len)
891 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
892 else
894 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
895 (total_size - info_size) /sizeof(WCHAR),
896 data, len, NULL, NULL );
897 /* if the type is REG_SZ and data is not 0-terminated
898 * and there is enough space in the buffer NT appends a \0 */
899 if (len < *count && data[len-1]) data[len] = 0;
902 total_size = len + info_size;
904 else if (data)
906 if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
907 else memcpy( data, buf_ptr + info_size, total_size - info_size );
910 else status = STATUS_SUCCESS;
912 if (type) *type = info->Type;
913 if (count) *count = total_size - info_size;
915 done:
916 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
917 RtlFreeUnicodeString( &nameW );
918 return RtlNtStatusToDosError(status);
922 /******************************************************************************
923 * RegQueryValueW [ADVAPI32.@]
925 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
927 DWORD ret;
928 HKEY subkey = hkey;
930 TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
932 if (name && name[0])
934 if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
936 ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
937 if (subkey != hkey) RegCloseKey( subkey );
938 if (ret == ERROR_FILE_NOT_FOUND)
940 /* return empty string if default value not found */
941 if (data) *data = 0;
942 if (count) *count = 1;
943 ret = ERROR_SUCCESS;
945 return ret;
949 /******************************************************************************
950 * RegQueryValueA [ADVAPI32.@]
952 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
954 DWORD ret;
955 HKEY subkey = hkey;
957 TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
959 if (name && name[0])
961 if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
963 ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
964 if (subkey != hkey) RegCloseKey( subkey );
965 if (ret == ERROR_FILE_NOT_FOUND)
967 /* return empty string if default value not found */
968 if (data) *data = 0;
969 if (count) *count = 1;
970 ret = ERROR_SUCCESS;
972 return ret;
976 /******************************************************************************
977 * RegEnumValueW [ADVAPI32.@]
979 * PARAMS
980 * hkey [I] Handle to key to query
981 * index [I] Index of value to query
982 * value [O] Value string
983 * val_count [I/O] Size of value buffer (in wchars)
984 * reserved [I] Reserved
985 * type [O] Type code
986 * data [O] Value data
987 * count [I/O] Size of data buffer (in bytes)
990 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
991 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
993 NTSTATUS status;
994 DWORD total_size;
995 char buffer[256], *buf_ptr = buffer;
996 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
997 static const int info_size = sizeof(*info) - sizeof(info->Name);
999 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1000 hkey, index, value, val_count, reserved, type, data, count );
1002 /* NT only checks count, not val_count */
1003 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1005 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1006 if (data) total_size += *count;
1007 total_size = min( sizeof(buffer), total_size );
1009 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1010 buffer, total_size, &total_size );
1011 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1013 if (value || data)
1015 /* retry with a dynamically allocated buffer */
1016 while (status == STATUS_BUFFER_OVERFLOW)
1018 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1019 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1020 return ERROR_NOT_ENOUGH_MEMORY;
1021 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1022 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1023 buf_ptr, total_size, &total_size );
1026 if (status) goto done;
1028 if (value)
1030 if (info->NameLength/sizeof(WCHAR) >= *val_count)
1032 status = STATUS_BUFFER_OVERFLOW;
1033 goto done;
1035 memcpy( value, info->Name, info->NameLength );
1036 *val_count = info->NameLength / sizeof(WCHAR);
1037 value[*val_count] = 0;
1040 if (data)
1042 if (total_size - info->DataOffset > *count)
1044 status = STATUS_BUFFER_OVERFLOW;
1045 goto done;
1047 memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1048 if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1050 /* if the type is REG_SZ and data is not 0-terminated
1051 * and there is enough space in the buffer NT appends a \0 */
1052 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1053 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1057 else status = STATUS_SUCCESS;
1059 if (type) *type = info->Type;
1060 if (count) *count = info->DataLength;
1062 done:
1063 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1064 return RtlNtStatusToDosError(status);
1068 /******************************************************************************
1069 * RegEnumValueA [ADVAPI32.@]
1071 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1072 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1074 NTSTATUS status;
1075 DWORD total_size;
1076 char buffer[256], *buf_ptr = buffer;
1077 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1078 static const int info_size = sizeof(*info) - sizeof(info->Name);
1080 TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1081 hkey, index, value, val_count, reserved, type, data, count );
1083 /* NT only checks count, not val_count */
1084 if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1086 total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1087 if (data) total_size += *count;
1088 total_size = min( sizeof(buffer), total_size );
1090 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1091 buffer, total_size, &total_size );
1092 if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1094 /* we need to fetch the contents for a string type even if not requested,
1095 * because we need to compute the length of the ASCII string. */
1096 if (value || data || is_string(info->Type))
1098 /* retry with a dynamically allocated buffer */
1099 while (status == STATUS_BUFFER_OVERFLOW)
1101 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1102 if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1103 return ERROR_NOT_ENOUGH_MEMORY;
1104 info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1105 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1106 buf_ptr, total_size, &total_size );
1109 if (status) goto done;
1111 if (value)
1113 DWORD len = WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
1114 NULL, 0, NULL, NULL );
1115 if (len >= *val_count)
1117 status = STATUS_BUFFER_OVERFLOW;
1118 goto done;
1120 WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
1121 value, len, NULL, NULL );
1122 value[len] = 0;
1123 *val_count = len;
1126 if (is_string(info->Type))
1128 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->DataOffset),
1129 (total_size - info->DataOffset) / sizeof(WCHAR),
1130 NULL, 0, NULL, NULL );
1131 if (data && len)
1133 if (len > *count)
1135 status = STATUS_BUFFER_OVERFLOW;
1136 goto done;
1138 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->DataOffset),
1139 (total_size - info->DataOffset) / sizeof(WCHAR),
1140 data, len, NULL, NULL );
1141 /* if the type is REG_SZ and data is not 0-terminated
1142 * and there is enough space in the buffer NT appends a \0 */
1143 if (len < *count && data[len-1]) data[len] = 0;
1145 info->DataLength = len;
1147 else if (data)
1149 if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1150 else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1153 else status = STATUS_SUCCESS;
1155 if (type) *type = info->Type;
1156 if (count) *count = info->DataLength;
1158 done:
1159 if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1160 return RtlNtStatusToDosError(status);
1165 /******************************************************************************
1166 * RegDeleteValueW [ADVAPI32.@]
1168 * PARAMS
1169 * hkey [I] handle to key
1170 * name [I] name of value to delete
1172 * RETURNS
1173 * error status
1175 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1177 UNICODE_STRING nameW;
1178 RtlInitUnicodeString( &nameW, name );
1179 return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1183 /******************************************************************************
1184 * RegDeleteValueA [ADVAPI32.@]
1186 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1188 UNICODE_STRING nameW;
1189 STRING nameA;
1190 NTSTATUS status;
1192 RtlInitAnsiString( &nameA, name );
1193 /* FIXME: should use Unicode buffer in TEB */
1194 if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1196 status = NtDeleteValueKey( hkey, &nameW );
1197 RtlFreeUnicodeString( &nameW );
1199 return RtlNtStatusToDosError( status );
1203 /******************************************************************************
1204 * RegLoadKeyW [ADVAPI32.@]
1206 * PARAMS
1207 * hkey [I] Handle of open key
1208 * subkey [I] Address of name of subkey
1209 * filename [I] Address of filename for registry information
1211 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1213 HANDLE file;
1214 DWORD ret, len, err = GetLastError();
1216 TRACE( "(%x,%s,%s)\n", hkey, debugstr_w(subkey), debugstr_w(filename) );
1218 if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1219 if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1221 len = strlenW( subkey ) * sizeof(WCHAR);
1222 if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
1224 if ((file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1225 FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
1227 ret = GetLastError();
1228 goto done;
1231 SERVER_START_REQ
1233 struct load_registry_request *req = server_alloc_req( sizeof(*req), len );
1234 req->hkey = hkey;
1235 req->file = file;
1236 memcpy( server_data_ptr(req), subkey, len );
1237 ret = reg_server_call( REQ_LOAD_REGISTRY );
1239 SERVER_END_REQ;
1240 CloseHandle( file );
1242 done:
1243 SetLastError( err ); /* restore the last error code */
1244 return ret;
1248 /******************************************************************************
1249 * RegLoadKeyA [ADVAPI32.@]
1251 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1253 HANDLE file;
1254 DWORD ret, len, err = GetLastError();
1256 TRACE( "(%x,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
1258 if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1259 if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1261 len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), NULL, 0 ) * sizeof(WCHAR);
1262 if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
1264 if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1265 FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
1267 ret = GetLastError();
1268 goto done;
1271 SERVER_START_REQ
1273 struct load_registry_request *req = server_alloc_req( sizeof(*req), len );
1274 req->hkey = hkey;
1275 req->file = file;
1276 MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey),
1277 server_data_ptr(req), len/sizeof(WCHAR) );
1278 ret = reg_server_call( REQ_LOAD_REGISTRY );
1280 SERVER_END_REQ;
1281 CloseHandle( file );
1283 done:
1284 SetLastError( err ); /* restore the last error code */
1285 return ret;
1289 /******************************************************************************
1290 * RegSaveKeyA [ADVAPI32.@]
1292 * PARAMS
1293 * hkey [I] Handle of key where save begins
1294 * lpFile [I] Address of filename to save to
1295 * sa [I] Address of security structure
1297 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
1299 char buffer[1024];
1300 int count = 0;
1301 LPSTR name;
1302 DWORD ret, err;
1303 HFILE handle;
1305 TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa );
1307 if (!file || !*file) return ERROR_INVALID_PARAMETER;
1309 err = GetLastError();
1310 GetFullPathNameA( file, sizeof(buffer), buffer, &name );
1311 for (;;)
1313 sprintf( name, "reg%04x.tmp", count++ );
1314 handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
1315 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1316 if (handle != INVALID_HANDLE_VALUE) break;
1317 if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
1319 /* Something gone haywire ? Please report if this happens abnormally */
1320 if (count >= 100)
1321 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);
1324 SERVER_START_REQ
1326 struct save_registry_request *req = server_alloc_req( sizeof(*req), 0 );
1327 req->hkey = hkey;
1328 req->file = handle;
1329 ret = reg_server_call( REQ_SAVE_REGISTRY );
1331 SERVER_END_REQ;
1333 CloseHandle( handle );
1334 if (!ret)
1336 if (!MoveFileExA( buffer, file, MOVEFILE_REPLACE_EXISTING ))
1338 ERR( "Failed to move %s to %s\n", buffer, file );
1339 ret = GetLastError();
1342 if (ret) DeleteFileA( buffer );
1344 done:
1345 SetLastError( err ); /* restore last error code */
1346 return ret;
1350 /******************************************************************************
1351 * RegSaveKeyW [ADVAPI32.@]
1353 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1355 LPSTR fileA = HEAP_strdupWtoA( GetProcessHeap(), 0, file );
1356 DWORD ret = RegSaveKeyA( hkey, fileA, sa );
1357 if (fileA) HeapFree( GetProcessHeap(), 0, fileA );
1358 return ret;
1362 /******************************************************************************
1363 * RegRestoreKeyW [ADVAPI32.@]
1365 * PARAMS
1366 * hkey [I] Handle of key where restore begins
1367 * lpFile [I] Address of filename containing saved tree
1368 * dwFlags [I] Optional flags
1370 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1372 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1374 /* It seems to do this check before the hkey check */
1375 if (!lpFile || !*lpFile)
1376 return ERROR_INVALID_PARAMETER;
1378 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1380 /* Check for file existence */
1382 return ERROR_SUCCESS;
1386 /******************************************************************************
1387 * RegRestoreKeyA [ADVAPI32.@]
1389 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1391 LPWSTR lpFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile );
1392 LONG ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1393 HeapFree( GetProcessHeap(), 0, lpFileW );
1394 return ret;
1398 /******************************************************************************
1399 * RegUnLoadKeyW [ADVAPI32.@]
1401 * PARAMS
1402 * hkey [I] Handle of open key
1403 * lpSubKey [I] Address of name of subkey to unload
1405 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1407 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1408 return ERROR_SUCCESS;
1412 /******************************************************************************
1413 * RegUnLoadKeyA [ADVAPI32.@]
1415 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1417 LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1418 LONG ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1419 if(lpSubKeyW) HeapFree( GetProcessHeap(), 0, lpSubKeyW);
1420 return ret;
1424 /******************************************************************************
1425 * RegReplaceKeyW [ADVAPI32.@]
1427 * PARAMS
1428 * hkey [I] Handle of open key
1429 * lpSubKey [I] Address of name of subkey
1430 * lpNewFile [I] Address of filename for file with new data
1431 * lpOldFile [I] Address of filename for backup file
1433 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1434 LPCWSTR lpOldFile )
1436 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1437 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1438 return ERROR_SUCCESS;
1442 /******************************************************************************
1443 * RegReplaceKeyA [ADVAPI32.@]
1445 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1446 LPCSTR lpOldFile )
1448 LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1449 LPWSTR lpNewFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile );
1450 LPWSTR lpOldFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile );
1451 LONG ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1452 HeapFree( GetProcessHeap(), 0, lpOldFileW );
1453 HeapFree( GetProcessHeap(), 0, lpNewFileW );
1454 HeapFree( GetProcessHeap(), 0, lpSubKeyW );
1455 return ret;
1459 /******************************************************************************
1460 * RegSetKeySecurity [ADVAPI32.@]
1462 * PARAMS
1463 * hkey [I] Open handle of key to set
1464 * SecurityInfo [I] Descriptor contents
1465 * pSecurityDesc [I] Address of descriptor for key
1467 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1468 PSECURITY_DESCRIPTOR pSecurityDesc )
1470 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1472 /* It seems to perform this check before the hkey check */
1473 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1474 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1475 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1476 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1477 /* Param OK */
1478 } else
1479 return ERROR_INVALID_PARAMETER;
1481 if (!pSecurityDesc)
1482 return ERROR_INVALID_PARAMETER;
1484 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1486 return ERROR_SUCCESS;
1490 /******************************************************************************
1491 * RegGetKeySecurity [ADVAPI32.@]
1492 * Retrieves a copy of security descriptor protecting the registry key
1494 * PARAMS
1495 * hkey [I] Open handle of key to set
1496 * SecurityInformation [I] Descriptor contents
1497 * pSecurityDescriptor [O] Address of descriptor for key
1498 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1500 * RETURNS
1501 * Success: ERROR_SUCCESS
1502 * Failure: Error code
1504 LONG WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
1505 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1506 LPDWORD lpcbSecurityDescriptor )
1508 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1509 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1511 /* FIXME: Check for valid SecurityInformation values */
1513 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1514 return ERROR_INSUFFICIENT_BUFFER;
1516 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1517 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1519 return ERROR_SUCCESS;
1523 /******************************************************************************
1524 * RegFlushKey [ADVAPI32.@]
1525 * Immediately writes key to registry.
1526 * Only returns after data has been written to disk.
1528 * FIXME: does it really wait until data is written ?
1530 * PARAMS
1531 * hkey [I] Handle of key to write
1533 * RETURNS
1534 * Success: ERROR_SUCCESS
1535 * Failure: Error code
1537 DWORD WINAPI RegFlushKey( HKEY hkey )
1539 FIXME( "(%x): stub\n", hkey );
1540 return ERROR_SUCCESS;
1544 /******************************************************************************
1545 * RegConnectRegistryW [ADVAPI32.@]
1547 * PARAMS
1548 * lpMachineName [I] Address of name of remote computer
1549 * hHey [I] Predefined registry handle
1550 * phkResult [I] Address of buffer for remote registry handle
1552 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1553 LPHKEY phkResult )
1555 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1557 if (!lpMachineName || !*lpMachineName) {
1558 /* Use the local machine name */
1559 return RegOpenKeyA( hKey, "", phkResult );
1562 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1563 return ERROR_BAD_NETPATH;
1567 /******************************************************************************
1568 * RegConnectRegistryA [ADVAPI32.@]
1570 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1572 LPWSTR machineW = HEAP_strdupAtoW( GetProcessHeap(), 0, machine );
1573 DWORD ret = RegConnectRegistryW( machineW, hkey, reskey );
1574 HeapFree( GetProcessHeap(), 0, machineW );
1575 return ret;
1579 /******************************************************************************
1580 * RegNotifyChangeKeyValue [ADVAPI32.@]
1582 * PARAMS
1583 * hkey [I] Handle of key to watch
1584 * fWatchSubTree [I] Flag for subkey notification
1585 * fdwNotifyFilter [I] Changes to be reported
1586 * hEvent [I] Handle of signaled event
1587 * fAsync [I] Flag for asynchronous reporting
1589 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1590 DWORD fdwNotifyFilter, HANDLE hEvent,
1591 BOOL fAsync )
1593 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1594 hEvent,fAsync);
1595 return ERROR_SUCCESS;