Fixed some issues found by winapi_check.
[wine] / dlls / advapi32 / 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
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <unistd.h>
18
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"
26
27 DEFAULT_DEBUG_CHANNEL(reg);
28
29
30 /* check if value type needs string conversion (Ansi<->Unicode) */
31 static inline int is_string( DWORD type )
32 {
33     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
34 }
35
36 /* do a server call without setting the last error code */
37 static inline int reg_server_call( enum request req )
38 {
39     unsigned int res = server_call_noerr( req );
40     if (res) res = RtlNtStatusToDosError(res);
41     return res;
42 }
43
44 /******************************************************************************
45  *           RegCreateKeyExW   [ADVAPI32.131]
46  *
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
57  *
58  * NOTES
59  *  in case of failing retkey remains untouched
60  */
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 )
64 {
65     OBJECT_ATTRIBUTES attr;
66     UNICODE_STRING nameW, classW;
67
68     if (reserved) return ERROR_INVALID_PARAMETER;
69     if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
70
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 );
79
80     return RtlNtStatusToDosError( NtCreateKey( retkey, access, &attr, 0,
81                                                &classW, options, dispos ) );
82 }
83
84
85 /******************************************************************************
86  *           RegCreateKeyExA   [ADVAPI32.130]
87  */
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 )
91 {
92     OBJECT_ATTRIBUTES attr;
93     UNICODE_STRING nameW, classW;
94     ANSI_STRING nameA, classA;
95     NTSTATUS status;
96
97     if (reserved) return ERROR_INVALID_PARAMETER;
98     if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
99
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 );
108
109     /* FIXME: should use Unicode buffer in TEB */
110     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
111     {
112         if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
113         {
114             status = NtCreateKey( retkey, access, &attr, 0, &classW, options, dispos );
115             RtlFreeUnicodeString( &classW );
116         }
117         RtlFreeUnicodeString( &nameW );
118     }
119     return RtlNtStatusToDosError( status );
120 }
121
122
123 /******************************************************************************
124  *           RegCreateKeyW   [ADVAPI32.132]
125  */
126 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
127 {
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 );
132 }
133
134
135 /******************************************************************************
136  *           RegCreateKeyA   [ADVAPI32.129]
137  */
138 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
139 {
140     return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
141                             KEY_ALL_ACCESS, NULL, retkey, NULL );
142 }
143
144
145
146 /******************************************************************************
147  *           RegOpenKeyExW   [ADVAPI32.150]
148  *
149  * Opens the specified key
150  *
151  * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
152  *
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
159  *
160  * RETURNS
161  *    Success: ERROR_SUCCESS
162  *    Failure: Error code
163  *
164  * NOTES
165  *  in case of failing is retkey = 0
166  */
167 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
168 {
169     OBJECT_ATTRIBUTES attr;
170     UNICODE_STRING nameW;
171
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 ) );
180 }
181
182
183 /******************************************************************************
184  *           RegOpenKeyExA   [ADVAPI32.149]
185  */
186 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
187 {
188     OBJECT_ATTRIBUTES attr;
189     UNICODE_STRING nameW;
190     STRING nameA;
191     NTSTATUS status;
192
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;
199
200     RtlInitAnsiString( &nameA, name );
201     /* FIXME: should use Unicode buffer in TEB */
202     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
203     {
204         status = NtOpenKey( retkey, access, &attr );
205         RtlFreeUnicodeString( &nameW );
206     }
207     return RtlNtStatusToDosError( status );
208 }
209
210
211 /******************************************************************************
212  *           RegOpenKeyW   [ADVAPI32.151]
213  *
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
218  *
219  * RETURNS
220  *    Success: ERROR_SUCCESS
221  *    Failure: Error code
222  *
223  * NOTES
224  *  in case of failing is retkey = 0
225  */
226 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
227 {
228     return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
229 }
230
231
232 /******************************************************************************
233  *           RegOpenKeyA   [ADVAPI32.148]
234  */
235 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
236 {
237     return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
238 }
239
240
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.
247  */
248 DWORD WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
249 {
250     return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
251 }
252
253
254
255 /******************************************************************************
256  *           RegEnumKeyExW   [ADVAPI32.139]
257  *
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
267  */
268 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
269                             LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
270 {
271     NTSTATUS status;
272     char buffer[256], *buf_ptr = buffer;
273     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
274     DWORD total_size;
275
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 );
278
279     if (reserved) return ERROR_INVALID_PARAMETER;
280
281     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
282                              buffer, sizeof(buffer), &total_size );
283
284     while (status == STATUS_BUFFER_OVERFLOW)
285     {
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 );
293     }
294
295     if (!status)
296     {
297         DWORD len = info->NameLength / sizeof(WCHAR);
298         DWORD cls_len = info->ClassLength / sizeof(WCHAR);
299
300         if (ft) *ft = info->LastWriteTime;
301
302         if (len >= *name_len || (class_len && (cls_len >= *class_len)))
303             status = STATUS_BUFFER_OVERFLOW;
304         else
305         {
306             *name_len = len;
307             memcpy( name, info->Name, info->NameLength );
308             name[len] = 0;
309             if (class_len)
310             {
311                 *class_len = cls_len;
312                 if (class)
313                 {
314                     memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
315                     class[cls_len] = 0;
316                 }
317             }
318         }
319     }
320
321     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
322     return RtlNtStatusToDosError( status );
323 }
324
325
326 /******************************************************************************
327  *           RegEnumKeyExA   [ADVAPI32.138]
328  */
329 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
330                             LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
331 {
332     NTSTATUS status;
333     char buffer[256], *buf_ptr = buffer;
334     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
335     DWORD total_size;
336
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 );
339
340     if (reserved) return ERROR_INVALID_PARAMETER;
341
342     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
343                              buffer, sizeof(buffer), &total_size );
344
345     while (status == STATUS_BUFFER_OVERFLOW)
346     {
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 );
354     }
355
356     if (!status)
357     {
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 );
363
364         if (ft) *ft = info->LastWriteTime;
365
366         if (len >= *name_len || (class_len && (cls_len >= *class_len)))
367             status = STATUS_BUFFER_OVERFLOW;
368         else
369         {
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)
375             {
376                 *class_len = cls_len;
377                 if (class)
378                 {
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;
383                 }
384             }
385         }
386     }
387
388     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
389     return RtlNtStatusToDosError( status );
390 }
391
392
393 /******************************************************************************
394  *           RegEnumKeyW   [ADVAPI32.140]
395  */
396 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
397 {
398     return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
399 }
400
401
402 /******************************************************************************
403  *           RegEnumKeyA   [ADVAPI32.137]
404  */
405 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
406 {
407     return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
408 }
409
410
411 /******************************************************************************
412  *           RegQueryInfoKeyW   [ADVAPI32.153]
413  *
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
427  *
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)
432  */
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 )
437 {
438     NTSTATUS status;
439     char buffer[256], *buf_ptr = buffer;
440     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
441     DWORD total_size;
442
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 );
445
446     if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
447         return ERROR_INVALID_PARAMETER;
448
449     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
450
451     if (class)
452     {
453         /* retry with a dynamically allocated buffer */
454         while (status == STATUS_BUFFER_OVERFLOW)
455         {
456             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
457             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
458                 return ERROR_NOT_ENOUGH_MEMORY;
459             info = (KEY_FULL_INFORMATION *)buf_ptr;
460             status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
461         }
462
463         if (!status)
464         {
465             if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
466             {
467                 status = STATUS_BUFFER_OVERFLOW;
468             }
469             else
470             {
471                 memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
472                 class[info->ClassLength/sizeof(WCHAR)] = 0;
473             }
474         }
475     }
476
477     if (!status || status == STATUS_BUFFER_OVERFLOW)
478     {
479         if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
480         if (subkeys) *subkeys = info->SubKeys;
481         if (max_subkey) *max_subkey = info->MaxNameLen;
482         if (max_class) *max_class = info->MaxClassLen;
483         if (values) *values = info->Values;
484         if (max_value) *max_value = info->MaxValueNameLen;
485         if (max_data) *max_data = info->MaxValueDataLen;
486         if (modif) *modif = info->LastWriteTime;
487     }
488
489     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
490     return RtlNtStatusToDosError( status );
491 }
492
493
494 /******************************************************************************
495  *           RegQueryInfoKeyA   [ADVAPI32.152]
496  */
497 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
498                                LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
499                                LPDWORD values, LPDWORD max_value, LPDWORD max_data,
500                                LPDWORD security, FILETIME *modif )
501 {
502     NTSTATUS status;
503     char buffer[256], *buf_ptr = buffer;
504     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
505     DWORD total_size;
506
507     TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
508            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
509
510     if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
511         return ERROR_INVALID_PARAMETER;
512
513     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
514
515     if (class || class_len)
516     {
517         /* retry with a dynamically allocated buffer */
518         while (status == STATUS_BUFFER_OVERFLOW)
519         {
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 );
525         }
526
527         if (!status)
528         {
529             DWORD 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)
534             {
535                 if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
536                 *class_len = len;
537             }
538             if (class && !status)
539             {
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;
545             }
546         }
547     }
548
549     if (!status || status == STATUS_BUFFER_OVERFLOW)
550     {
551         if (subkeys) *subkeys = info->SubKeys;
552         if (max_subkey) *max_subkey = info->MaxNameLen;
553         if (max_class) *max_class = info->MaxClassLen;
554         if (values) *values = info->Values;
555         if (max_value) *max_value = info->MaxValueNameLen;
556         if (max_data) *max_data = info->MaxValueDataLen;
557         if (modif) *modif = info->LastWriteTime;
558     }
559
560     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
561     return RtlNtStatusToDosError( status );
562 }
563
564
565 /******************************************************************************
566  *           RegCloseKey   [ADVAPI32.126]
567  *
568  * Releases the handle of the specified key
569  *
570  * PARAMS
571  *    hkey [I] Handle of key to close
572  *
573  * RETURNS
574  *    Success: ERROR_SUCCESS
575  *    Failure: Error code
576  */
577 DWORD WINAPI RegCloseKey( HKEY hkey )
578 {
579     if (!hkey || hkey >= 0x80000000) return ERROR_SUCCESS;
580     return RtlNtStatusToDosError( NtClose( hkey ) );
581 }
582
583
584 /******************************************************************************
585  *           RegDeleteKeyW   [ADVAPI32.134]
586  *
587  * PARAMS
588  *    hkey   [I] Handle to open key
589  *    name   [I] Name of subkey to delete
590  *
591  * RETURNS
592  *    Success: ERROR_SUCCESS
593  *    Failure: Error code
594  */
595 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
596 {
597     DWORD ret;
598     HKEY tmp;
599
600     if (!name || !*name) return NtDeleteKey( hkey );
601     if (!(ret = RegOpenKeyExW( hkey, name, 0, 0, &tmp )))
602     {
603         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
604         RegCloseKey( tmp );
605     }
606     return ret;
607 }
608
609
610 /******************************************************************************
611  *           RegDeleteKeyA   [ADVAPI32.133]
612  */
613 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
614 {
615     DWORD ret;
616     HKEY tmp;
617
618     if (!name || !*name) return NtDeleteKey( hkey );
619     if (!(ret = RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
620     {
621         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
622         RegCloseKey( tmp );
623     }
624     return ret;
625 }
626
627
628
629 /******************************************************************************
630  *           RegSetValueExW   [ADVAPI32.170]
631  *
632  * Sets the data and type of a value under a register key
633  *
634  * PARAMS
635  *    hkey       [I] Handle of key to set value for
636  *    name       [I] Name of value to set
637  *    reserved   [I] Reserved - must be zero
638  *    type       [I] Flag for value type
639  *    data       [I] Address of value data
640  *    count      [I] Size of value data
641  *
642  * RETURNS
643  *    Success: ERROR_SUCCESS
644  *    Failure: Error code
645  *
646  * NOTES
647  *   win95 does not care about count for REG_SZ and finds out the len by itself (js) 
648  *   NT does definitely care (aj)
649  */
650 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
651                              DWORD type, CONST BYTE *data, DWORD count )
652 {
653     UNICODE_STRING nameW;
654
655     if (count && is_string(type))
656     {
657         LPCWSTR str = (LPCWSTR)data;
658         /* if user forgot to count terminating null, add it (yes NT does this) */
659         if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
660             count += sizeof(WCHAR);
661     }
662
663     RtlInitUnicodeString( &nameW, name );
664     return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
665 }
666
667
668 /******************************************************************************
669  *           RegSetValueExA   [ADVAPI32.169]
670  */
671 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
672                              CONST BYTE *data, DWORD count )
673 {
674     UNICODE_STRING nameW;
675     ANSI_STRING nameA;
676     WCHAR *dataW = NULL;
677     NTSTATUS status;
678
679     if (count && is_string(type))
680     {
681         /* if user forgot to count terminating null, add it (yes NT does this) */
682         if (data[count-1] && !data[count]) count++;
683     }
684
685     if (is_string( type )) /* need to convert to Unicode */
686     {
687         DWORD lenW = MultiByteToWideChar( CP_ACP, 0, data, count, NULL, 0 );
688         if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW*sizeof(WCHAR) )))
689             return ERROR_OUTOFMEMORY;
690         MultiByteToWideChar( CP_ACP, 0, data, count, dataW, lenW );
691         count = lenW * sizeof(WCHAR);
692         data = (BYTE *)dataW;
693     }
694
695     RtlInitAnsiString( &nameA, name );
696     /* FIXME: should use Unicode buffer in TEB */
697     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
698     {
699         status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
700         RtlFreeUnicodeString( &nameW );
701     }
702     if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
703     return RtlNtStatusToDosError( status );
704 }
705
706
707 /******************************************************************************
708  *           RegSetValueW   [ADVAPI32.171]
709  */
710 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
711 {
712     HKEY subkey = hkey;
713     DWORD ret;
714
715     TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
716
717     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
718
719     if (name && name[0])  /* need to create the subkey */
720     {
721         if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
722     }
723
724     ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (LPBYTE)data,
725                           (strlenW( data ) + 1) * sizeof(WCHAR) );
726     if (subkey != hkey) RegCloseKey( subkey );
727     return ret;
728 }
729
730
731 /******************************************************************************
732  *           RegSetValueA   [ADVAPI32.168]
733  */
734 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
735 {
736     HKEY subkey = hkey;
737     DWORD ret;
738
739     TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
740
741     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
742
743     if (name && name[0])  /* need to create the subkey */
744     {
745         if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
746     }
747     ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
748     if (subkey != hkey) RegCloseKey( subkey );
749     return ret;
750 }
751
752
753
754 /******************************************************************************
755  *           RegQueryValueExW   [ADVAPI32.158]
756  *
757  * Retrieves type and data for a specified name associated with an open key
758  *
759  * PARAMS
760  *    hkey      [I]   Handle of key to query
761  *    name      [I]   Name of value to query
762  *    reserved  [I]   Reserved - must be NULL
763  *    type      [O]   Address of buffer for value type.  If NULL, the type
764  *                        is not required.
765  *    data      [O]   Address of data buffer.  If NULL, the actual data is
766  *                        not required.
767  *    count     [I/O] Address of data buffer size
768  *
769  * RETURNS 
770  *    ERROR_SUCCESS:   Success
771  *    ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
772  *                     buffer is left untouched. The MS-documentation is wrong (js) !!!
773  */
774 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
775                                LPBYTE data, LPDWORD count )
776 {
777     NTSTATUS status;
778     UNICODE_STRING name_str;
779     DWORD total_size;
780     char buffer[256], *buf_ptr = buffer;
781     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
782     static const int info_size = sizeof(*info) - sizeof(info->Data);
783
784     TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
785           hkey, debugstr_w(name), reserved, type, data, count, count ? *count : 0 );
786
787     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
788
789     RtlInitUnicodeString( &name_str, name );
790
791     if (data) total_size = min( sizeof(buffer), *count + info_size );
792     else total_size = info_size;
793
794     status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
795                               buffer, total_size, &total_size );
796     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
797
798     if (data)
799     {
800         /* retry with a dynamically allocated buffer */
801         while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
802         {
803             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
804             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
805                 return ERROR_NOT_ENOUGH_MEMORY;
806             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
807             status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
808                                       buf_ptr, total_size, &total_size );
809         }
810
811         if (!status)
812         {
813             memcpy( data, buf_ptr + info_size, total_size - info_size );
814             /* if the type is REG_SZ and data is not 0-terminated
815              * and there is enough space in the buffer NT appends a \0 */
816             if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
817             {
818                 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
819                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
820             }
821         }
822         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
823     }
824
825     if (type) *type = info->Type;
826     if (count) *count = total_size - info_size;
827
828  done:
829     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
830     return RtlNtStatusToDosError(status);
831 }
832
833
834 /******************************************************************************
835  *           RegQueryValueExA   [ADVAPI32.157]
836  *
837  * NOTES:
838  * the documentation is wrong: if the buffer is too small it remains untouched 
839  */
840 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
841                                LPBYTE data, LPDWORD count )
842 {
843     NTSTATUS status;
844     ANSI_STRING nameA;
845     UNICODE_STRING nameW;
846     DWORD total_size;
847     char buffer[256], *buf_ptr = buffer;
848     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
849     static const int info_size = sizeof(*info) - sizeof(info->Data);
850
851     TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
852           hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
853
854     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
855
856     RtlInitAnsiString( &nameA, name );
857     /* FIXME: should use Unicode buffer in TEB */
858     if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
859         return RtlNtStatusToDosError(status);
860
861     status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
862                               buffer, sizeof(buffer), &total_size );
863     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
864
865     /* we need to fetch the contents for a string type even if not requested,
866      * because we need to compute the length of the ASCII string. */
867     if (data || is_string(info->Type))
868     {
869         /* retry with a dynamically allocated buffer */
870         while (status == STATUS_BUFFER_OVERFLOW)
871         {
872             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
873             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
874             {
875                 status = STATUS_NO_MEMORY;
876                 goto done;
877             }
878             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
879             status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
880                                       buf_ptr, total_size, &total_size );
881         }
882
883         if (!status)
884         {
885             if (is_string(info->Type))
886             {
887                 DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
888                                                  (total_size - info_size) /sizeof(WCHAR),
889                                                  NULL, 0, NULL, NULL );
890                 if (data && len)
891                 {
892                     if (len > *count) status = STATUS_BUFFER_OVERFLOW;
893                     else
894                     {
895                         WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
896                                              (total_size - info_size) /sizeof(WCHAR),
897                                              data, len, NULL, NULL );
898                         /* if the type is REG_SZ and data is not 0-terminated
899                          * and there is enough space in the buffer NT appends a \0 */
900                         if (len < *count && data[len-1]) data[len] = 0;
901                     }
902                 }
903                 total_size = len + info_size;
904             }
905             else if (data)
906             {
907                 if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
908                 else memcpy( data, buf_ptr + info_size, total_size - info_size );
909             }
910         }
911         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
912     }
913
914     if (type) *type = info->Type;
915     if (count) *count = total_size - info_size;
916
917  done:
918     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
919     RtlFreeUnicodeString( &nameW );
920     return RtlNtStatusToDosError(status);
921 }
922
923
924 /******************************************************************************
925  *           RegQueryValueW   [ADVAPI32.159]
926  */
927 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
928 {
929     DWORD ret;
930     HKEY subkey = hkey;
931
932     TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
933
934     if (name && name[0])
935     {
936         if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
937     }
938     ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
939     if (subkey != hkey) RegCloseKey( subkey );
940     if (ret == ERROR_FILE_NOT_FOUND)
941     {
942         /* return empty string if default value not found */
943         if (data) *data = 0;
944         if (count) *count = 1;
945         ret = ERROR_SUCCESS;
946     }
947     return ret;
948 }
949
950
951 /******************************************************************************
952  *           RegQueryValueA   [ADVAPI32.156]
953  */
954 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
955 {
956     DWORD ret;
957     HKEY subkey = hkey;
958
959     TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
960
961     if (name && name[0])
962     {
963         if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
964     }
965     ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
966     if (subkey != hkey) RegCloseKey( subkey );
967     if (ret == ERROR_FILE_NOT_FOUND)
968     {
969         /* return empty string if default value not found */
970         if (data) *data = 0;
971         if (count) *count = 1;
972         ret = ERROR_SUCCESS;
973     }
974     return ret;
975 }
976
977
978 /******************************************************************************
979  *           RegEnumValueW   [ADVAPI32.142]
980  *
981  * PARAMS
982  *    hkey       [I] Handle to key to query
983  *    index      [I] Index of value to query
984  *    value      [O] Value string
985  *    val_count  [I/O] Size of value buffer (in wchars)
986  *    reserved   [I] Reserved
987  *    type       [O] Type code
988  *    data       [O] Value data
989  *    count      [I/O] Size of data buffer (in bytes)
990  */
991
992 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
993                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
994 {
995     NTSTATUS status;
996     DWORD total_size;
997     char buffer[256], *buf_ptr = buffer;
998     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
999     static const int info_size = sizeof(*info) - sizeof(info->Name);
1000
1001     TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1002           hkey, index, value, val_count, reserved, type, data, count );
1003
1004     /* NT only checks count, not val_count */
1005     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1006
1007     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1008     if (data) total_size += *count;
1009     total_size = min( sizeof(buffer), total_size );
1010
1011     status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1012                                   buffer, total_size, &total_size );
1013     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1014
1015     if (value || data)
1016     {
1017         /* retry with a dynamically allocated buffer */
1018         while (status == STATUS_BUFFER_OVERFLOW)
1019         {
1020             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1021             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1022                 return ERROR_NOT_ENOUGH_MEMORY;
1023             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1024             status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1025                                           buf_ptr, total_size, &total_size );
1026         }
1027
1028         if (status) goto done;
1029
1030         if (value)
1031         {
1032             if (info->NameLength/sizeof(WCHAR) >= *val_count)
1033             {
1034                 status = STATUS_BUFFER_OVERFLOW;
1035                 goto done;
1036             }
1037             memcpy( value, info->Name, info->NameLength );
1038             *val_count = info->NameLength / sizeof(WCHAR);
1039             value[*val_count] = 0;
1040         }
1041
1042         if (data)
1043         {
1044             if (total_size - info->DataOffset > *count)
1045             {
1046                 status = STATUS_BUFFER_OVERFLOW;
1047                 goto done;
1048             }
1049             memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1050             if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1051             {
1052                 /* if the type is REG_SZ and data is not 0-terminated
1053                  * and there is enough space in the buffer NT appends a \0 */
1054                 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1055                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1056             }
1057         }
1058     }
1059
1060     if (type) *type = info->Type;
1061     if (count) *count = info->DataLength;
1062
1063  done:
1064     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1065     return RtlNtStatusToDosError(status);
1066 }
1067
1068
1069 /******************************************************************************
1070  *           RegEnumValueA   [ADVAPI32.141]
1071  */
1072 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1073                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1074 {
1075     NTSTATUS status;
1076     DWORD total_size;
1077     char buffer[256], *buf_ptr = buffer;
1078     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1079     static const int info_size = sizeof(*info) - sizeof(info->Name);
1080
1081     TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1082           hkey, index, value, val_count, reserved, type, data, count );
1083
1084     /* NT only checks count, not val_count */
1085     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1086
1087     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1088     if (data) total_size += *count;
1089     total_size = min( sizeof(buffer), total_size );
1090
1091     status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1092                                   buffer, total_size, &total_size );
1093     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1094
1095     /* we need to fetch the contents for a string type even if not requested,
1096      * because we need to compute the length of the ASCII string. */
1097     if (value || data || is_string(info->Type))
1098     {
1099         /* retry with a dynamically allocated buffer */
1100         while (status == STATUS_BUFFER_OVERFLOW)
1101         {
1102             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1103             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1104                 return ERROR_NOT_ENOUGH_MEMORY;
1105             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1106             status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1107                                           buf_ptr, total_size, &total_size );
1108         }
1109
1110         if (status) goto done;
1111
1112         if (value)
1113         {
1114             DWORD len = WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
1115                                              NULL, 0, NULL, NULL );
1116             if (len >= *val_count)
1117             {
1118                 status = STATUS_BUFFER_OVERFLOW;
1119                 goto done;
1120             }
1121             WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR),
1122                                  value, len, NULL, NULL );
1123             value[len] = 0;
1124             *val_count = len;
1125         }
1126
1127         if (is_string(info->Type))
1128         {
1129             DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->DataOffset),
1130                                              (total_size - info->DataOffset) / sizeof(WCHAR),
1131                                              NULL, 0, NULL, NULL );
1132             if (data && len)
1133             {
1134                 if (len > *count)
1135                 {
1136                     status = STATUS_BUFFER_OVERFLOW;
1137                     goto done;
1138                 }
1139                 WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->DataOffset),
1140                                      (total_size - info->DataOffset) / sizeof(WCHAR),
1141                                      data, len, NULL, NULL );
1142                 /* if the type is REG_SZ and data is not 0-terminated
1143                  * and there is enough space in the buffer NT appends a \0 */
1144                 if (len < *count && data[len-1]) data[len] = 0;
1145             }
1146             info->DataLength = len;
1147         }
1148         else if (data)
1149         {
1150             if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1151             else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1152         }
1153     }
1154
1155     if (type) *type = info->Type;
1156     if (count) *count = info->DataLength;
1157
1158  done:
1159     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1160     return RtlNtStatusToDosError(status);
1161 }
1162
1163
1164
1165 /******************************************************************************
1166  *           RegDeleteValueW   [ADVAPI32.136]
1167  *
1168  * PARAMS
1169  *    hkey   [I] handle to key
1170  *    name   [I] name of value to delete
1171  *
1172  * RETURNS
1173  *    error status
1174  */
1175 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1176 {
1177     UNICODE_STRING nameW;
1178     RtlInitUnicodeString( &nameW, name );
1179     return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1180 }
1181
1182
1183 /******************************************************************************
1184  *           RegDeleteValueA   [ADVAPI32.135]
1185  */
1186 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1187 {
1188     UNICODE_STRING nameW;
1189     STRING nameA;
1190     NTSTATUS status;
1191
1192     RtlInitAnsiString( &nameA, name );
1193     /* FIXME: should use Unicode buffer in TEB */
1194     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
1195     {
1196         status = NtDeleteValueKey( hkey, &nameW );
1197         RtlFreeUnicodeString( &nameW );
1198     }
1199     return RtlNtStatusToDosError( status );
1200 }
1201
1202
1203 /******************************************************************************
1204  *           RegLoadKeyW   [ADVAPI32.185]
1205  *
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
1210  */
1211 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1212 {
1213     HANDLE file;
1214     DWORD ret, len, err = GetLastError();
1215
1216     TRACE( "(%x,%s,%s)\n", hkey, debugstr_w(subkey), debugstr_w(filename) );
1217
1218     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1219     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1220
1221     len = strlenW( subkey ) * sizeof(WCHAR);
1222     if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
1223
1224     if ((file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1225                              FILE_ATTRIBUTE_NORMAL, -1 )) == INVALID_HANDLE_VALUE)
1226     {
1227         ret = GetLastError();
1228         goto done;
1229     }
1230
1231     SERVER_START_REQ
1232     {
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 );
1238     }
1239     SERVER_END_REQ;
1240     CloseHandle( file );
1241
1242  done:
1243     SetLastError( err );  /* restore the last error code */
1244     return ret;
1245 }
1246
1247
1248 /******************************************************************************
1249  *           RegLoadKeyA   [ADVAPI32.184]
1250  */
1251 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1252 {
1253     HANDLE file;
1254     DWORD ret, len, err = GetLastError();
1255
1256     TRACE( "(%x,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
1257
1258     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1259     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1260
1261     len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), NULL, 0 ) * sizeof(WCHAR);
1262     if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
1263
1264     if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1265                              FILE_ATTRIBUTE_NORMAL, -1 )) == INVALID_HANDLE_VALUE)
1266     {
1267         ret = GetLastError();
1268         goto done;
1269     }
1270
1271     SERVER_START_REQ
1272     {
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 );
1279     }
1280     SERVER_END_REQ;
1281     CloseHandle( file );
1282
1283  done:
1284     SetLastError( err );  /* restore the last error code */
1285     return ret;
1286 }
1287
1288
1289 /******************************************************************************
1290  *           RegSaveKeyA   [ADVAPI32.165]
1291  *
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
1296  */
1297 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
1298 {
1299     char buffer[1024];
1300     int count = 0;
1301     LPSTR name;
1302     DWORD ret, err;
1303     HFILE handle;
1304
1305     TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa );
1306
1307     if (!file || !*file) return ERROR_INVALID_PARAMETER;
1308
1309     err = GetLastError();
1310     GetFullPathNameA( file, sizeof(buffer), buffer, &name );
1311     for (;;)
1312     {
1313         sprintf( name, "reg%04x.tmp", count++ );
1314         handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
1315                             CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1 );
1316         if (handle != INVALID_HANDLE_VALUE) break;
1317         if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
1318
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);
1322     }
1323
1324     SERVER_START_REQ
1325     {
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 );
1330     }
1331     SERVER_END_REQ;
1332
1333     CloseHandle( handle );
1334     if (!ret)
1335     {
1336         if (!MoveFileExA( buffer, file, MOVEFILE_REPLACE_EXISTING ))
1337         {
1338             ERR( "Failed to move %s to %s\n", buffer, file );
1339             ret = GetLastError();
1340         }
1341     }
1342     if (ret) DeleteFileA( buffer );
1343
1344 done:
1345     SetLastError( err );  /* restore last error code */
1346     return ret;
1347 }
1348
1349
1350 /******************************************************************************
1351  *           RegSaveKeyW   [ADVAPI32.166]
1352  */
1353 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1354 {
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;
1359 }
1360
1361
1362 /******************************************************************************
1363  * RegRestoreKeyW [ADVAPI32.164]
1364  *
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
1369  */
1370 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1371 {
1372     TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1373
1374     /* It seems to do this check before the hkey check */
1375     if (!lpFile || !*lpFile)
1376         return ERROR_INVALID_PARAMETER;
1377
1378     FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1379
1380     /* Check for file existence */
1381
1382     return ERROR_SUCCESS;
1383 }
1384
1385
1386 /******************************************************************************
1387  * RegRestoreKeyA [ADVAPI32.163]
1388  */
1389 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1390 {
1391     LPWSTR lpFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile );
1392     LONG ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1393     HeapFree( GetProcessHeap(), 0, lpFileW );
1394     return ret;
1395 }
1396
1397
1398 /******************************************************************************
1399  * RegUnLoadKeyW [ADVAPI32.173]
1400  *
1401  * PARAMS
1402  *    hkey     [I] Handle of open key
1403  *    lpSubKey [I] Address of name of subkey to unload
1404  */
1405 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1406 {
1407     FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1408     return ERROR_SUCCESS;
1409 }
1410
1411
1412 /******************************************************************************
1413  * RegUnLoadKeyA [ADVAPI32.172]
1414  */
1415 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1416 {
1417     LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1418     LONG ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1419     if(lpSubKeyW) HeapFree( GetProcessHeap(), 0, lpSubKeyW);
1420     return ret;
1421 }
1422
1423
1424 /******************************************************************************
1425  * RegReplaceKeyW [ADVAPI32.162]
1426  *
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
1432  */
1433 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1434                               LPCWSTR lpOldFile )
1435 {
1436     FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey), 
1437           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1438     return ERROR_SUCCESS;
1439 }
1440
1441
1442 /******************************************************************************
1443  * RegReplaceKeyA [ADVAPI32.161]
1444  */
1445 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1446                               LPCSTR lpOldFile )
1447 {
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;
1456 }
1457
1458
1459 /******************************************************************************
1460  * RegSetKeySecurity [ADVAPI32.167]
1461  *
1462  * PARAMS
1463  *    hkey          [I] Open handle of key to set
1464  *    SecurityInfo  [I] Descriptor contents
1465  *    pSecurityDesc [I] Address of descriptor for key
1466  */
1467 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1468                                PSECURITY_DESCRIPTOR pSecurityDesc )
1469 {
1470     TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1471
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;
1480
1481     if (!pSecurityDesc)
1482         return ERROR_INVALID_PARAMETER;
1483
1484     FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1485
1486     return ERROR_SUCCESS;
1487 }
1488
1489
1490 /******************************************************************************
1491  * RegGetKeySecurity [ADVAPI32.144]
1492  * Retrieves a copy of security descriptor protecting the registry key
1493  *
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
1499  *
1500  * RETURNS
1501  *    Success: ERROR_SUCCESS
1502  *    Failure: Error code
1503  */
1504 LONG WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
1505                                PSECURITY_DESCRIPTOR pSecurityDescriptor,
1506                                LPDWORD lpcbSecurityDescriptor )
1507 {
1508     TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1509           lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1510
1511     /* FIXME: Check for valid SecurityInformation values */
1512
1513     if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1514         return ERROR_INSUFFICIENT_BUFFER;
1515
1516     FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1517           pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1518
1519     return ERROR_SUCCESS;
1520 }
1521
1522
1523 /******************************************************************************
1524  * RegFlushKey [ADVAPI32.143]
1525  * Immediately writes key to registry.
1526  * Only returns after data has been written to disk.
1527  *
1528  * FIXME: does it really wait until data is written ?
1529  *
1530  * PARAMS
1531  *    hkey [I] Handle of key to write
1532  *
1533  * RETURNS
1534  *    Success: ERROR_SUCCESS
1535  *    Failure: Error code
1536  */
1537 DWORD WINAPI RegFlushKey( HKEY hkey )
1538 {
1539     FIXME( "(%x): stub\n", hkey );
1540     return ERROR_SUCCESS;
1541 }
1542
1543
1544 /******************************************************************************
1545  * RegConnectRegistryW [ADVAPI32.128]
1546  *
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
1551  */
1552 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey, 
1553                                    LPHKEY phkResult )
1554 {
1555     TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1556
1557     if (!lpMachineName || !*lpMachineName) {
1558         /* Use the local machine name */
1559         return RegOpenKeyA( hKey, "", phkResult );
1560     }
1561
1562     FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1563     return ERROR_BAD_NETPATH;
1564 }
1565
1566
1567 /******************************************************************************
1568  * RegConnectRegistryA [ADVAPI32.127]
1569  */
1570 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1571 {
1572     LPWSTR machineW = HEAP_strdupAtoW( GetProcessHeap(), 0, machine );
1573     DWORD ret = RegConnectRegistryW( machineW, hkey, reskey );
1574     HeapFree( GetProcessHeap(), 0, machineW );
1575     return ret;
1576 }
1577
1578
1579 /******************************************************************************
1580  * RegNotifyChangeKeyValue [ADVAPI32.???]
1581  *
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
1588  */
1589 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree, 
1590                                      DWORD fdwNotifyFilter, HANDLE hEvent,
1591                                      BOOL fAsync )
1592 {
1593     FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1594           hEvent,fAsync);
1595     return ERROR_SUCCESS;
1596 }