Moved all the content of the DDK files ntdef.h and ntddk.h to
[wine] / memory / registry.c
1 /*
2  * Registry management
3  *
4  * Copyright (C) 1999 Alexandre Julliard
5  *
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
10  *
11  * This file is concerned about handle management and interaction with the Wine server.
12  * Registry file I/O is in misc/registry.c.
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License as published by the Free Software Foundation; either
17  * version 2.1 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  */
28
29 #include "config.h"
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36
37 #include "winbase.h"
38 #include "winreg.h"
39 #include "winerror.h"
40 #include "wine/winbase16.h"
41 #include "wine/unicode.h"
42 #include "wine/server.h"
43 #include "wine/debug.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(reg);
46
47
48 /* check if value type needs string conversion (Ansi<->Unicode) */
49 inline static int is_string( DWORD type )
50 {
51     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
52 }
53
54 /* check if current version is NT or Win95 */
55 inline static int is_version_nt(void)
56 {
57     return !(GetVersion() & 0x80000000);
58 }
59
60 /******************************************************************************
61  *           RegCreateKeyExA   [ADVAPI32.@]
62  */
63 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
64                               DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
65                               LPHKEY retkey, LPDWORD dispos )
66 {
67     OBJECT_ATTRIBUTES attr;
68     UNICODE_STRING nameW, classW;
69     ANSI_STRING nameA, classA;
70     NTSTATUS status;
71
72     if (reserved) return ERROR_INVALID_PARAMETER;
73     if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
74
75     attr.Length = sizeof(attr);
76     attr.RootDirectory = hkey;
77     attr.ObjectName = &nameW;
78     attr.Attributes = 0;
79     attr.SecurityDescriptor = NULL;
80     attr.SecurityQualityOfService = NULL;
81     RtlInitAnsiString( &nameA, name );
82     RtlInitAnsiString( &classA, class );
83
84     /* FIXME: should use Unicode buffer in TEB */
85     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
86     {
87         if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
88         {
89             status = NtCreateKey( retkey, access, &attr, 0, &classW, options, dispos );
90             RtlFreeUnicodeString( &classW );
91         }
92         RtlFreeUnicodeString( &nameW );
93     }
94     return RtlNtStatusToDosError( status );
95 }
96
97
98 /******************************************************************************
99  *           RegOpenKeyW   [ADVAPI32.@]
100  *
101  * PARAMS
102  *    hkey    [I] Handle of open key
103  *    name    [I] Address of name of subkey to open
104  *    retkey  [O] Handle to open key
105  *
106  * RETURNS
107  *    Success: ERROR_SUCCESS
108  *    Failure: Error code
109  *
110  * NOTES
111  *  in case of failing is retkey = 0
112  */
113 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
114 {
115     return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
116 }
117
118
119 /******************************************************************************
120  *           RegCreateKeyA   [ADVAPI32.@]
121  */
122 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
123 {
124     return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
125                             KEY_ALL_ACCESS, NULL, retkey, NULL );
126 }
127
128
129
130 /******************************************************************************
131  *           RegOpenKeyExW   [ADVAPI32.@]
132  *
133  * Opens the specified key
134  *
135  * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
136  *
137  * PARAMS
138  *    hkey       [I] Handle of open key
139  *    name       [I] Name of subkey to open
140  *    reserved   [I] Reserved - must be zero
141  *    access     [I] Security access mask
142  *    retkey     [O] Handle to open key
143  *
144  * RETURNS
145  *    Success: ERROR_SUCCESS
146  *    Failure: Error code
147  *
148  * NOTES
149  *  in case of failing is retkey = 0
150  */
151 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
152 {
153     OBJECT_ATTRIBUTES attr;
154     UNICODE_STRING nameW;
155
156     attr.Length = sizeof(attr);
157     attr.RootDirectory = hkey;
158     attr.ObjectName = &nameW;
159     attr.Attributes = 0;
160     attr.SecurityDescriptor = NULL;
161     attr.SecurityQualityOfService = NULL;
162     RtlInitUnicodeString( &nameW, name );
163     return RtlNtStatusToDosError( NtOpenKey( retkey, access, &attr ) );
164 }
165
166
167 /******************************************************************************
168  *           RegOpenKeyExA   [ADVAPI32.@]
169  */
170 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
171 {
172     OBJECT_ATTRIBUTES attr;
173     UNICODE_STRING nameW;
174     STRING nameA;
175     NTSTATUS status;
176
177     attr.Length = sizeof(attr);
178     attr.RootDirectory = hkey;
179     attr.ObjectName = &nameW;
180     attr.Attributes = 0;
181     attr.SecurityDescriptor = NULL;
182     attr.SecurityQualityOfService = NULL;
183
184     RtlInitAnsiString( &nameA, name );
185     /* FIXME: should use Unicode buffer in TEB */
186     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
187     {
188         status = NtOpenKey( retkey, access, &attr );
189         RtlFreeUnicodeString( &nameW );
190     }
191     return RtlNtStatusToDosError( status );
192 }
193
194
195 /******************************************************************************
196  *           RegOpenKeyA   [ADVAPI32.@]
197  */
198 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
199 {
200     return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
201 }
202
203
204 /******************************************************************************
205  *           RegEnumKeyExA   [ADVAPI32.@]
206  */
207 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
208                             LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
209 {
210     NTSTATUS status;
211     char buffer[256], *buf_ptr = buffer;
212     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
213     DWORD total_size;
214
215     TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
216            name_len ? *name_len : -1, reserved, class, class_len, ft );
217
218     if (reserved) return ERROR_INVALID_PARAMETER;
219
220     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
221                              buffer, sizeof(buffer), &total_size );
222
223     while (status == STATUS_BUFFER_OVERFLOW)
224     {
225         /* retry with a dynamically allocated buffer */
226         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
227         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
228             return ERROR_NOT_ENOUGH_MEMORY;
229         info = (KEY_NODE_INFORMATION *)buf_ptr;
230         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
231                                  buf_ptr, total_size, &total_size );
232     }
233
234     if (!status)
235     {
236         DWORD len, cls_len;
237
238         RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
239         RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
240                                    info->ClassLength );
241         if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
242
243         if (len >= *name_len || (class_len && (cls_len >= *class_len)))
244             status = STATUS_BUFFER_OVERFLOW;
245         else
246         {
247             *name_len = len;
248             RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
249             name[len] = 0;
250             if (class_len)
251             {
252                 *class_len = cls_len;
253                 if (class)
254                 {
255                     RtlUnicodeToMultiByteN( class, cls_len, NULL,
256                                             (WCHAR *)(buf_ptr + info->ClassOffset),
257                                             info->ClassLength );
258                     class[cls_len] = 0;
259                 }
260             }
261         }
262     }
263
264     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
265     return RtlNtStatusToDosError( status );
266 }
267
268
269 /******************************************************************************
270  *           RegEnumKeyA   [ADVAPI32.@]
271  */
272 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
273 {
274     return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
275 }
276
277
278 /******************************************************************************
279  *           RegQueryInfoKeyA   [ADVAPI32.@]
280  */
281 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
282                                LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
283                                LPDWORD values, LPDWORD max_value, LPDWORD max_data,
284                                LPDWORD security, FILETIME *modif )
285 {
286     NTSTATUS status;
287     char buffer[256], *buf_ptr = buffer;
288     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
289     DWORD total_size, len;
290
291     TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
292            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
293
294     if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
295
296     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
297     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
298
299     if (class || class_len)
300     {
301         /* retry with a dynamically allocated buffer */
302         while (status == STATUS_BUFFER_OVERFLOW)
303         {
304             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
305             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
306                 return ERROR_NOT_ENOUGH_MEMORY;
307             info = (KEY_FULL_INFORMATION *)buf_ptr;
308             status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
309         }
310
311         if (status) goto done;
312
313         RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
314         if (class_len)
315         {
316             if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
317             *class_len = len;
318         }
319         if (class && !status)
320         {
321             RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
322                                     info->ClassLength );
323             class[len] = 0;
324         }
325     }
326     else status = STATUS_SUCCESS;
327
328     if (subkeys) *subkeys = info->SubKeys;
329     if (max_subkey) *max_subkey = info->MaxNameLen;
330     if (max_class) *max_class = info->MaxClassLen;
331     if (values) *values = info->Values;
332     if (max_value) *max_value = info->MaxValueNameLen;
333     if (max_data) *max_data = info->MaxValueDataLen;
334     if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
335
336  done:
337     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
338     return RtlNtStatusToDosError( status );
339 }
340
341
342 /******************************************************************************
343  *           RegCloseKey   [ADVAPI32.@]
344  *
345  * Releases the handle of the specified key
346  *
347  * PARAMS
348  *    hkey [I] Handle of key to close
349  *
350  * RETURNS
351  *    Success: ERROR_SUCCESS
352  *    Failure: Error code
353  */
354 DWORD WINAPI RegCloseKey( HKEY hkey )
355 {
356     if (!hkey || hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
357     return RtlNtStatusToDosError( NtClose( hkey ) );
358 }
359
360
361 /******************************************************************************
362  *           RegDeleteKeyA   [ADVAPI32.@]
363  */
364 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
365 {
366     DWORD ret;
367     HKEY tmp;
368
369     if (!name || !*name) return NtDeleteKey( hkey );
370     if (!(ret = RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
371     {
372         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
373         RegCloseKey( tmp );
374     }
375     return ret;
376 }
377
378
379 /******************************************************************************
380  *           RegSetValueExW   [ADVAPI32.@]
381  *
382  * Sets the data and type of a value under a register key
383  *
384  * PARAMS
385  *    hkey       [I] Handle of key to set value for
386  *    name       [I] Name of value to set
387  *    reserved   [I] Reserved - must be zero
388  *    type       [I] Flag for value type
389  *    data       [I] Address of value data
390  *    count      [I] Size of value data
391  *
392  * RETURNS
393  *    Success: ERROR_SUCCESS
394  *    Failure: Error code
395  *
396  * NOTES
397  *   win95 does not care about count for REG_SZ and finds out the len by itself (js)
398  *   NT does definitely care (aj)
399  */
400 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
401                              DWORD type, CONST BYTE *data, DWORD count )
402 {
403     UNICODE_STRING nameW;
404
405     if (!is_version_nt())  /* win95 */
406     {
407         if (type == REG_SZ) count = (strlenW( (WCHAR *)data ) + 1) * sizeof(WCHAR);
408     }
409     else if (count && is_string(type))
410     {
411         LPCWSTR str = (LPCWSTR)data;
412         /* if user forgot to count terminating null, add it (yes NT does this) */
413         if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
414             count += sizeof(WCHAR);
415     }
416
417     RtlInitUnicodeString( &nameW, name );
418     return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
419 }
420
421
422 /******************************************************************************
423  *           RegSetValueExA   [ADVAPI32.@]
424  */
425 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
426                              CONST BYTE *data, DWORD count )
427 {
428     UNICODE_STRING nameW;
429     ANSI_STRING nameA;
430     WCHAR *dataW = NULL;
431     NTSTATUS status;
432
433     if (count && is_string(type))
434     {
435         /* if user forgot to count terminating null, add it (yes NT does this) */
436         if (data[count-1] && !data[count]) count++;
437     }
438
439     if (is_string( type )) /* need to convert to Unicode */
440     {
441         DWORD lenW;
442         RtlMultiByteToUnicodeSize( &lenW, data, count );
443         if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
444         RtlMultiByteToUnicodeN( dataW, lenW, NULL, data, count );
445         count = lenW;
446         data = (BYTE *)dataW;
447     }
448
449     RtlInitAnsiString( &nameA, name );
450     /* FIXME: should use Unicode buffer in TEB */
451     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
452     {
453         status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
454         RtlFreeUnicodeString( &nameW );
455     }
456     if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
457     return RtlNtStatusToDosError( status );
458 }
459
460
461 /******************************************************************************
462  *           RegSetValueA   [ADVAPI32.@]
463  */
464 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
465 {
466     HKEY subkey = hkey;
467     DWORD ret;
468
469     TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
470
471     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
472
473     if (name && name[0])  /* need to create the subkey */
474     {
475         if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
476     }
477     ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
478     if (subkey != hkey) RegCloseKey( subkey );
479     return ret;
480 }
481
482
483 /******************************************************************************
484  *           RegQueryValueExW   [ADVAPI32.@]
485  *
486  * Retrieves type and data for a specified name associated with an open key
487  *
488  * PARAMS
489  *    hkey      [I]   Handle of key to query
490  *    name      [I]   Name of value to query
491  *    reserved  [I]   Reserved - must be NULL
492  *    type      [O]   Address of buffer for value type.  If NULL, the type
493  *                        is not required.
494  *    data      [O]   Address of data buffer.  If NULL, the actual data is
495  *                        not required.
496  *    count     [I/O] Address of data buffer size
497  *
498  * RETURNS
499  *    ERROR_SUCCESS:   Success
500  *    ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
501  *                     buffer is left untouched. The MS-documentation is wrong (js) !!!
502  */
503 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
504                                LPBYTE data, LPDWORD count )
505 {
506     NTSTATUS status;
507     UNICODE_STRING name_str;
508     DWORD total_size;
509     char buffer[256], *buf_ptr = buffer;
510     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
511     static const int info_size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
512
513     TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
514           hkey, debugstr_w(name), reserved, type, data, count, count ? *count : 0 );
515
516     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
517
518     RtlInitUnicodeString( &name_str, name );
519
520     if (data) total_size = min( sizeof(buffer), *count + info_size );
521     else total_size = info_size;
522
523     status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
524                               buffer, total_size, &total_size );
525     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
526
527     if (data)
528     {
529         /* retry with a dynamically allocated buffer */
530         while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
531         {
532             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
533             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
534                 return ERROR_NOT_ENOUGH_MEMORY;
535             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
536             status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
537                                       buf_ptr, total_size, &total_size );
538         }
539
540         if (!status)
541         {
542             memcpy( data, buf_ptr + info_size, total_size - info_size );
543             /* if the type is REG_SZ and data is not 0-terminated
544              * and there is enough space in the buffer NT appends a \0 */
545             if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
546             {
547                 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
548                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
549             }
550         }
551         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
552     }
553     else status = STATUS_SUCCESS;
554
555     if (type) *type = info->Type;
556     if (count) *count = total_size - info_size;
557
558  done:
559     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
560     return RtlNtStatusToDosError(status);
561 }
562
563
564 /******************************************************************************
565  *           RegQueryValueExA   [ADVAPI32.@]
566  *
567  * NOTES:
568  * the documentation is wrong: if the buffer is too small it remains untouched
569  */
570 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
571                                LPBYTE data, LPDWORD count )
572 {
573     NTSTATUS status;
574     ANSI_STRING nameA;
575     UNICODE_STRING nameW;
576     DWORD total_size;
577     char buffer[256], *buf_ptr = buffer;
578     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
579     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
580
581     TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
582           hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
583
584     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
585
586     RtlInitAnsiString( &nameA, name );
587     /* FIXME: should use Unicode buffer in TEB */
588     if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
589         return RtlNtStatusToDosError(status);
590
591     status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
592                               buffer, sizeof(buffer), &total_size );
593     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
594
595     /* we need to fetch the contents for a string type even if not requested,
596      * because we need to compute the length of the ASCII string. */
597     if (data || is_string(info->Type))
598     {
599         /* retry with a dynamically allocated buffer */
600         while (status == STATUS_BUFFER_OVERFLOW)
601         {
602             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
603             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
604             {
605                 status = STATUS_NO_MEMORY;
606                 goto done;
607             }
608             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
609             status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
610                                       buf_ptr, total_size, &total_size );
611         }
612
613         if (!status)
614         {
615             if (is_string(info->Type))
616             {
617                 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
618                                                  (total_size - info_size) /sizeof(WCHAR),
619                                                  NULL, 0, NULL, NULL );
620                 if (data && len)
621                 {
622                     if (len > *count) status = STATUS_BUFFER_OVERFLOW;
623                     else
624                     {
625                         WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
626                                              (total_size - info_size) /sizeof(WCHAR),
627                                              data, len, NULL, NULL );
628                         /* if the type is REG_SZ and data is not 0-terminated
629                          * and there is enough space in the buffer NT appends a \0 */
630                         if (len < *count && data[len-1]) data[len] = 0;
631                     }
632                 }
633                 total_size = len + info_size;
634             }
635             else if (data)
636             {
637                 if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
638                 else memcpy( data, buf_ptr + info_size, total_size - info_size );
639             }
640         }
641         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
642     }
643
644     if (type) *type = info->Type;
645     if (count) *count = total_size - info_size;
646
647  done:
648     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
649     RtlFreeUnicodeString( &nameW );
650     return RtlNtStatusToDosError(status);
651 }
652
653
654 /******************************************************************************
655  *           RegQueryValueA   [ADVAPI32.@]
656  */
657 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
658 {
659     DWORD ret;
660     HKEY subkey = hkey;
661
662     TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
663
664     if (name && name[0])
665     {
666         if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
667     }
668     ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
669     if (subkey != hkey) RegCloseKey( subkey );
670     if (ret == ERROR_FILE_NOT_FOUND)
671     {
672         /* return empty string if default value not found */
673         if (data) *data = 0;
674         if (count) *count = 1;
675         ret = ERROR_SUCCESS;
676     }
677     return ret;
678 }
679
680
681 /******************************************************************************
682  *           RegEnumValueA   [ADVAPI32.@]
683  */
684 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
685                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
686 {
687     NTSTATUS status;
688     DWORD total_size;
689     char buffer[256], *buf_ptr = buffer;
690     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
691     static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
692
693     TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
694           hkey, index, value, val_count, reserved, type, data, count );
695
696     /* NT only checks count, not val_count */
697     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
698
699     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
700     if (data) total_size += *count;
701     total_size = min( sizeof(buffer), total_size );
702
703     status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
704                                   buffer, total_size, &total_size );
705     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
706
707     /* we need to fetch the contents for a string type even if not requested,
708      * because we need to compute the length of the ASCII string. */
709     if (value || data || is_string(info->Type))
710     {
711         /* retry with a dynamically allocated buffer */
712         while (status == STATUS_BUFFER_OVERFLOW)
713         {
714             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
715             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
716                 return ERROR_NOT_ENOUGH_MEMORY;
717             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
718             status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
719                                           buf_ptr, total_size, &total_size );
720         }
721
722         if (status) goto done;
723
724         if (is_string(info->Type))
725         {
726             DWORD len;
727             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
728                                        total_size - info->DataOffset );
729             if (data && len)
730             {
731                 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
732                 else
733                 {
734                     RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
735                                             total_size - info->DataOffset );
736                     /* if the type is REG_SZ and data is not 0-terminated
737                      * and there is enough space in the buffer NT appends a \0 */
738                     if (len < *count && data[len-1]) data[len] = 0;
739                 }
740             }
741             info->DataLength = len;
742         }
743         else if (data)
744         {
745             if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
746             else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
747         }
748
749         if (value && !status)
750         {
751             DWORD len;
752
753             RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
754             if (len >= *val_count)
755             {
756                 status = STATUS_BUFFER_OVERFLOW;
757                 if (*val_count)
758                 {
759                     len = *val_count - 1;
760                     RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
761                     value[len] = 0;
762                 }
763             }
764             else
765             {
766                 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
767                 value[len] = 0;
768                 *val_count = len;
769             }
770         }
771     }
772     else status = STATUS_SUCCESS;
773
774     if (type) *type = info->Type;
775     if (count) *count = info->DataLength;
776
777  done:
778     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
779     return RtlNtStatusToDosError(status);
780 }
781
782
783
784 /******************************************************************************
785  *           RegDeleteValueA   [ADVAPI32.@]
786  */
787 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
788 {
789     UNICODE_STRING nameW;
790     STRING nameA;
791     NTSTATUS status;
792
793     RtlInitAnsiString( &nameA, name );
794     /* FIXME: should use Unicode buffer in TEB */
795     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
796     {
797         status = NtDeleteValueKey( hkey, &nameW );
798         RtlFreeUnicodeString( &nameW );
799     }
800     return RtlNtStatusToDosError( status );
801 }
802
803
804 /******************************************************************************
805  *           RegLoadKeyA   [ADVAPI32.@]
806  */
807 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
808 {
809     HANDLE file;
810     WCHAR buffer[MAX_PATH];
811     DWORD ret, len, err = GetLastError();
812
813     TRACE( "(%x,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
814
815     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
816     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
817
818     if (!(len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), buffer, MAX_PATH )))
819         return ERROR_INVALID_PARAMETER;
820
821     if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
822                              FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
823     {
824         ret = GetLastError();
825         goto done;
826     }
827
828     SERVER_START_REQ( load_registry )
829     {
830         req->hkey  = hkey;
831         req->file  = file;
832         wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
833         ret = RtlNtStatusToDosError( wine_server_call(req) );
834     }
835     SERVER_END_REQ;
836     CloseHandle( file );
837
838  done:
839     SetLastError( err );  /* restore the last error code */
840     return ret;
841 }
842
843
844 /******************************************************************************
845  *           RegSaveKeyA   [ADVAPI32.@]
846  *
847  * PARAMS
848  *    hkey   [I] Handle of key where save begins
849  *    lpFile [I] Address of filename to save to
850  *    sa     [I] Address of security structure
851  */
852 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
853 {
854     char buffer[1024];
855     int count = 0;
856     LPSTR name;
857     DWORD ret, err;
858     HANDLE handle;
859
860     TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa );
861
862     if (!file || !*file) return ERROR_INVALID_PARAMETER;
863
864     err = GetLastError();
865     GetFullPathNameA( file, sizeof(buffer), buffer, &name );
866     for (;;)
867     {
868         sprintf( name, "reg%04x.tmp", count++ );
869         handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
870                             CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
871         if (handle != INVALID_HANDLE_VALUE) break;
872         if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
873
874         /* Something gone haywire ? Please report if this happens abnormally */
875         if (count >= 100)
876             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);
877     }
878
879     SERVER_START_REQ( save_registry )
880     {
881         req->hkey = hkey;
882         req->file = handle;
883         ret = RtlNtStatusToDosError( wine_server_call( req ) );
884     }
885     SERVER_END_REQ;
886
887     CloseHandle( handle );
888     if (!ret)
889     {
890         if (!MoveFileExA( buffer, file, MOVEFILE_REPLACE_EXISTING ))
891         {
892             ERR( "Failed to move %s to %s\n", buffer, file );
893             ret = GetLastError();
894         }
895     }
896     if (ret) DeleteFileA( buffer );
897
898 done:
899     SetLastError( err );  /* restore last error code */
900     return ret;
901 }
902
903
904 /******************************************************************************
905  * RegUnLoadKeyA [ADVAPI32.@]
906  *
907  * PARAMS
908  *    hkey     [I] Handle of open key
909  *    lpSubKey [I] Address of name of subkey to unload
910  */
911 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
912 {
913     FIXME("(%x,%s): stub\n",hkey, debugstr_a(lpSubKey));
914     return ERROR_SUCCESS;
915 }
916
917
918 /******************************************************************************
919  * RegReplaceKeyA [ADVAPI32.@]
920  *
921  * PARAMS
922  *    hkey      [I] Handle of open key
923  *    lpSubKey  [I] Address of name of subkey
924  *    lpNewFile [I] Address of filename for file with new data
925  *    lpOldFile [I] Address of filename for backup file
926  */
927 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
928                               LPCSTR lpOldFile )
929 {
930     FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_a(lpSubKey),
931           debugstr_a(lpNewFile),debugstr_a(lpOldFile));
932     return ERROR_SUCCESS;
933 }
934
935
936 /******************************************************************************
937  * RegFlushKey [ADVAPI32.@]
938  * Immediately writes key to registry.
939  * Only returns after data has been written to disk.
940  *
941  * FIXME: does it really wait until data is written ?
942  *
943  * PARAMS
944  *    hkey [I] Handle of key to write
945  *
946  * RETURNS
947  *    Success: ERROR_SUCCESS
948  *    Failure: Error code
949  */
950 DWORD WINAPI RegFlushKey( HKEY hkey )
951 {
952     FIXME( "(%x): stub\n", hkey );
953     return ERROR_SUCCESS;
954 }