Update shell xxxAW wrapper prototypes for fixed SHLWAPI functions.
[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  * 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 <stdlib.h>
30 #include <stdio.h>
31 #include <unistd.h>
32
33 #include "winbase.h"
34 #include "winreg.h"
35 #include "winerror.h"
36 #include "wine/unicode.h"
37 #include "heap.h"
38 #include "wine/server.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(reg);
42
43
44 /* check if value type needs string conversion (Ansi<->Unicode) */
45 static inline int is_string( DWORD type )
46 {
47     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
48 }
49
50
51 /******************************************************************************
52  *           RegCreateKeyExW   [ADVAPI32.@]
53  *
54  * PARAMS
55  *    hkey       [I] Handle of an open key
56  *    name       [I] Address of subkey name
57  *    reserved   [I] Reserved - must be 0
58  *    class      [I] Address of class string
59  *    options    [I] Special options flag
60  *    access     [I] Desired security access
61  *    sa         [I] Address of key security structure
62  *    retkey     [O] Address of buffer for opened handle
63  *    dispos     [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
64  *
65  * NOTES
66  *  in case of failing retkey remains untouched
67  */
68 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
69                               DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa, 
70                               LPHKEY retkey, LPDWORD dispos )
71 {
72     OBJECT_ATTRIBUTES attr;
73     UNICODE_STRING nameW, classW;
74
75     if (reserved) return ERROR_INVALID_PARAMETER;
76     if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
77
78     attr.Length = sizeof(attr);
79     attr.RootDirectory = hkey;
80     attr.ObjectName = &nameW;
81     attr.Attributes = 0;
82     attr.SecurityDescriptor = NULL;
83     attr.SecurityQualityOfService = NULL;
84     RtlInitUnicodeString( &nameW, name );
85     RtlInitUnicodeString( &classW, class );
86
87     return RtlNtStatusToDosError( NtCreateKey( retkey, access, &attr, 0,
88                                                &classW, options, dispos ) );
89 }
90
91
92 /******************************************************************************
93  *           RegCreateKeyExA   [ADVAPI32.@]
94  */
95 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
96                               DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa, 
97                               LPHKEY retkey, LPDWORD dispos )
98 {
99     OBJECT_ATTRIBUTES attr;
100     UNICODE_STRING classW;
101     ANSI_STRING nameA, classA;
102     NTSTATUS status;
103
104     if (reserved) return ERROR_INVALID_PARAMETER;
105     if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
106
107     attr.Length = sizeof(attr);
108     attr.RootDirectory = hkey;
109     attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
110     attr.Attributes = 0;
111     attr.SecurityDescriptor = NULL;
112     attr.SecurityQualityOfService = NULL;
113     RtlInitAnsiString( &nameA, name );
114     RtlInitAnsiString( &classA, class );
115
116     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
117                                                  &nameA, FALSE )))
118     {
119         if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
120         {
121             status = NtCreateKey( retkey, access, &attr, 0, &classW, options, dispos );
122             RtlFreeUnicodeString( &classW );
123         }
124     }
125     return RtlNtStatusToDosError( status );
126 }
127
128
129 /******************************************************************************
130  *           RegCreateKeyW   [ADVAPI32.@]
131  */
132 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
133 {
134     /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
135     /* but at least my version of NT (4.0 SP5) doesn't do this.  -- AJ */
136     return RegCreateKeyExW( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
137                             KEY_ALL_ACCESS, NULL, retkey, NULL );
138 }
139
140
141 /******************************************************************************
142  *           RegCreateKeyA   [ADVAPI32.@]
143  */
144 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
145 {
146     return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
147                             KEY_ALL_ACCESS, NULL, retkey, NULL );
148 }
149
150
151
152 /******************************************************************************
153  *           RegOpenKeyExW   [ADVAPI32.@]
154  *
155  * Opens the specified key
156  *
157  * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
158  *
159  * PARAMS
160  *    hkey       [I] Handle of open key
161  *    name       [I] Name of subkey to open
162  *    reserved   [I] Reserved - must be zero
163  *    access     [I] Security access mask
164  *    retkey     [O] Handle to open key
165  *
166  * RETURNS
167  *    Success: ERROR_SUCCESS
168  *    Failure: Error code
169  *
170  * NOTES
171  *  in case of failing is retkey = 0
172  */
173 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
174 {
175     OBJECT_ATTRIBUTES attr;
176     UNICODE_STRING nameW;
177
178     attr.Length = sizeof(attr);
179     attr.RootDirectory = hkey;
180     attr.ObjectName = &nameW;
181     attr.Attributes = 0;
182     attr.SecurityDescriptor = NULL;
183     attr.SecurityQualityOfService = NULL;
184     RtlInitUnicodeString( &nameW, name );
185     return RtlNtStatusToDosError( NtOpenKey( retkey, access, &attr ) );
186 }
187
188
189 /******************************************************************************
190  *           RegOpenKeyExA   [ADVAPI32.@]
191  */
192 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
193 {
194     OBJECT_ATTRIBUTES attr;
195     STRING nameA;
196     NTSTATUS status;
197
198     attr.Length = sizeof(attr);
199     attr.RootDirectory = hkey;
200     attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
201     attr.Attributes = 0;
202     attr.SecurityDescriptor = NULL;
203     attr.SecurityQualityOfService = NULL;
204
205     RtlInitAnsiString( &nameA, name );
206     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
207                                                  &nameA, FALSE )))
208     {
209         status = NtOpenKey( retkey, access, &attr );
210     }
211     return RtlNtStatusToDosError( status );
212 }
213
214
215 /******************************************************************************
216  *           RegOpenKeyW   [ADVAPI32.@]
217  *
218  * PARAMS
219  *    hkey    [I] Handle of open key
220  *    name    [I] Address of name of subkey to open
221  *    retkey  [O] Handle to open key
222  *
223  * RETURNS
224  *    Success: ERROR_SUCCESS
225  *    Failure: Error code
226  *
227  * NOTES
228  *  in case of failing is retkey = 0
229  */
230 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
231 {
232     return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
233 }
234
235
236 /******************************************************************************
237  *           RegOpenKeyA   [ADVAPI32.@]
238  */
239 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
240 {
241     return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
242 }
243
244
245 /******************************************************************************
246  *           RegOpenCurrentUser   [ADVAPI32.@]
247  * FIXME: This function is supposed to retrieve a handle to the
248  * HKEY_CURRENT_USER for the user the current thread is impersonating.
249  * Since Wine does not currently allow threads to impersonate other users,
250  * this stub should work fine.
251  */
252 DWORD WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
253 {
254     return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
255 }
256
257
258
259 /******************************************************************************
260  *           RegEnumKeyExW   [ADVAPI32.@]
261  *
262  * PARAMS
263  *    hkey         [I] Handle to key to enumerate
264  *    index        [I] Index of subkey to enumerate
265  *    name         [O] Buffer for subkey name
266  *    name_len     [O] Size of subkey buffer
267  *    reserved     [I] Reserved
268  *    class        [O] Buffer for class string
269  *    class_len    [O] Size of class buffer
270  *    ft           [O] Time key last written to
271  */
272 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
273                             LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
274 {
275     NTSTATUS status;
276     char buffer[256], *buf_ptr = buffer;
277     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
278     DWORD total_size;
279
280     TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
281            name_len ? *name_len : -1, reserved, class, class_len, ft );
282
283     if (reserved) return ERROR_INVALID_PARAMETER;
284
285     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
286                              buffer, sizeof(buffer), &total_size );
287
288     while (status == STATUS_BUFFER_OVERFLOW)
289     {
290         /* retry with a dynamically allocated buffer */
291         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
292         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
293             return ERROR_NOT_ENOUGH_MEMORY;
294         info = (KEY_NODE_INFORMATION *)buf_ptr;
295         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
296                                  buf_ptr, total_size, &total_size );
297     }
298
299     if (!status)
300     {
301         DWORD len = info->NameLength / sizeof(WCHAR);
302         DWORD cls_len = info->ClassLength / sizeof(WCHAR);
303
304         if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
305
306         if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
307             status = STATUS_BUFFER_OVERFLOW;
308         else
309         {
310             *name_len = len;
311             memcpy( name, info->Name, info->NameLength );
312             name[len] = 0;
313             if (class_len)
314             {
315                 *class_len = cls_len;
316                 if (class)
317                 {
318                     memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
319                     class[cls_len] = 0;
320                 }
321             }
322         }
323     }
324
325     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
326     return RtlNtStatusToDosError( status );
327 }
328
329
330 /******************************************************************************
331  *           RegEnumKeyExA   [ADVAPI32.@]
332  */
333 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
334                             LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
335 {
336     NTSTATUS status;
337     char buffer[256], *buf_ptr = buffer;
338     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
339     DWORD total_size;
340
341     TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
342            name_len ? *name_len : -1, reserved, class, class_len, ft );
343
344     if (reserved) return ERROR_INVALID_PARAMETER;
345
346     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
347                              buffer, sizeof(buffer), &total_size );
348
349     while (status == STATUS_BUFFER_OVERFLOW)
350     {
351         /* retry with a dynamically allocated buffer */
352         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
353         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
354             return ERROR_NOT_ENOUGH_MEMORY;
355         info = (KEY_NODE_INFORMATION *)buf_ptr;
356         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
357                                  buf_ptr, total_size, &total_size );
358     }
359
360     if (!status)
361     {
362         DWORD len, cls_len;
363
364         RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
365         RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
366                                    info->ClassLength );
367         if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
368
369         if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
370             status = STATUS_BUFFER_OVERFLOW;
371         else
372         {
373             *name_len = len;
374             RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
375             name[len] = 0;
376             if (class_len)
377             {
378                 *class_len = cls_len;
379                 if (class)
380                 {
381                     RtlUnicodeToMultiByteN( class, cls_len, NULL,
382                                             (WCHAR *)(buf_ptr + info->ClassOffset),
383                                             info->ClassLength );
384                     class[cls_len] = 0;
385                 }
386             }
387         }
388     }
389
390     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
391     return RtlNtStatusToDosError( status );
392 }
393
394
395 /******************************************************************************
396  *           RegEnumKeyW   [ADVAPI32.@]
397  */
398 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
399 {
400     return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
401 }
402
403
404 /******************************************************************************
405  *           RegEnumKeyA   [ADVAPI32.@]
406  */
407 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
408 {
409     return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
410 }
411
412
413 /******************************************************************************
414  *           RegQueryInfoKeyW   [ADVAPI32.@]
415  *
416  * PARAMS
417  *    hkey       [I] Handle to key to query
418  *    class      [O] Buffer for class string
419  *    class_len  [O] Size of class string buffer
420  *    reserved   [I] Reserved
421  *    subkeys    [O] Buffer for number of subkeys
422  *    max_subkey [O] Buffer for longest subkey name length
423  *    max_class  [O] Buffer for longest class string length
424  *    values     [O] Buffer for number of value entries
425  *    max_value  [O] Buffer for longest value name length
426  *    max_data   [O] Buffer for longest value data length
427  *    security   [O] Buffer for security descriptor length
428  *    modif      [O] Modification time
429  *
430  * - win95 allows class to be valid and class_len to be NULL 
431  * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
432  * - both allow class to be NULL and class_len to be NULL 
433  * (it's hard to test validity, so test !NULL instead)
434  */
435 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
436                                LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
437                                LPDWORD values, LPDWORD max_value, LPDWORD max_data,
438                                LPDWORD security, FILETIME *modif )
439 {
440     NTSTATUS status;
441     char buffer[256], *buf_ptr = buffer;
442     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
443     DWORD total_size;
444
445     TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
446            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
447
448     if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
449         return ERROR_INVALID_PARAMETER;
450
451     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
452     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
453
454     if (class)
455     {
456         /* retry with a dynamically allocated buffer */
457         while (status == STATUS_BUFFER_OVERFLOW)
458         {
459             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
460             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
461                 return ERROR_NOT_ENOUGH_MEMORY;
462             info = (KEY_FULL_INFORMATION *)buf_ptr;
463             status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
464         }
465
466         if (status) goto done;
467
468         if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
469         {
470             status = STATUS_BUFFER_OVERFLOW;
471         }
472         else
473         {
474             memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
475             class[info->ClassLength/sizeof(WCHAR)] = 0;
476         }
477     }
478     else status = STATUS_SUCCESS;
479
480     if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
481     if (subkeys) *subkeys = info->SubKeys;
482     if (max_subkey) *max_subkey = info->MaxNameLen;
483     if (max_class) *max_class = info->MaxClassLen;
484     if (values) *values = info->Values;
485     if (max_value) *max_value = info->MaxValueNameLen;
486     if (max_data) *max_data = info->MaxValueDataLen;
487     if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
488
489  done:
490     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
491     return RtlNtStatusToDosError( status );
492 }
493
494
495 /******************************************************************************
496  *           RegQueryInfoKeyA   [ADVAPI32.@]
497  */
498 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
499                                LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
500                                LPDWORD values, LPDWORD max_value, LPDWORD max_data,
501                                LPDWORD security, FILETIME *modif )
502 {
503     NTSTATUS status;
504     char buffer[256], *buf_ptr = buffer;
505     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
506     DWORD total_size, len;
507
508     TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
509            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
510
511     if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/))
512         return ERROR_INVALID_PARAMETER;
513
514     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
515     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
516
517     if (class || class_len)
518     {
519         /* retry with a dynamically allocated buffer */
520         while (status == STATUS_BUFFER_OVERFLOW)
521         {
522             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
523             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
524                 return ERROR_NOT_ENOUGH_MEMORY;
525             info = (KEY_FULL_INFORMATION *)buf_ptr;
526             status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
527         }
528
529         if (status) goto done;
530
531         RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
532         if (class_len)
533         {
534             if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
535             *class_len = len;
536         }
537         if (class && !status)
538         {
539             RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
540                                     info->ClassLength );
541             class[len] = 0;
542         }
543     }
544     else status = STATUS_SUCCESS;
545
546     if (subkeys) *subkeys = info->SubKeys;
547     if (max_subkey) *max_subkey = info->MaxNameLen;
548     if (max_class) *max_class = info->MaxClassLen;
549     if (values) *values = info->Values;
550     if (max_value) *max_value = info->MaxValueNameLen;
551     if (max_data) *max_data = info->MaxValueDataLen;
552     if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
553
554  done:
555     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
556     return RtlNtStatusToDosError( status );
557 }
558
559
560 /******************************************************************************
561  *           RegCloseKey   [ADVAPI32.@]
562  *
563  * Releases the handle of the specified key
564  *
565  * PARAMS
566  *    hkey [I] Handle of key to close
567  *
568  * RETURNS
569  *    Success: ERROR_SUCCESS
570  *    Failure: Error code
571  */
572 DWORD WINAPI RegCloseKey( HKEY hkey )
573 {
574     if (!hkey || hkey >= 0x80000000) return ERROR_SUCCESS;
575     return RtlNtStatusToDosError( NtClose( hkey ) );
576 }
577
578
579 /******************************************************************************
580  *           RegDeleteKeyW   [ADVAPI32.@]
581  *
582  * PARAMS
583  *    hkey   [I] Handle to open key
584  *    name   [I] Name of subkey to delete
585  *
586  * RETURNS
587  *    Success: ERROR_SUCCESS
588  *    Failure: Error code
589  */
590 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
591 {
592     DWORD ret;
593     HKEY tmp;
594
595     if (!name || !*name) return NtDeleteKey( hkey );
596     if (!(ret = RegOpenKeyExW( hkey, name, 0, 0, &tmp )))
597     {
598         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
599         RegCloseKey( tmp );
600     }
601     return ret;
602 }
603
604
605 /******************************************************************************
606  *           RegDeleteKeyA   [ADVAPI32.@]
607  */
608 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
609 {
610     DWORD ret;
611     HKEY tmp;
612
613     if (!name || !*name) return NtDeleteKey( hkey );
614     if (!(ret = RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
615     {
616         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
617         RegCloseKey( tmp );
618     }
619     return ret;
620 }
621
622
623
624 /******************************************************************************
625  *           RegSetValueExW   [ADVAPI32.@]
626  *
627  * Sets the data and type of a value under a register key
628  *
629  * PARAMS
630  *    hkey       [I] Handle of key to set value for
631  *    name       [I] Name of value to set
632  *    reserved   [I] Reserved - must be zero
633  *    type       [I] Flag for value type
634  *    data       [I] Address of value data
635  *    count      [I] Size of value data
636  *
637  * RETURNS
638  *    Success: ERROR_SUCCESS
639  *    Failure: Error code
640  *
641  * NOTES
642  *   win95 does not care about count for REG_SZ and finds out the len by itself (js) 
643  *   NT does definitely care (aj)
644  */
645 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
646                              DWORD type, CONST BYTE *data, DWORD count )
647 {
648     UNICODE_STRING nameW;
649
650     if (GetVersion() & 0x80000000)  /* win95 */
651     {
652         if (type == REG_SZ) count = (strlenW( (WCHAR *)data ) + 1) * sizeof(WCHAR);
653     }
654     else if (count && is_string(type))
655     {
656         LPCWSTR str = (LPCWSTR)data;
657         /* if user forgot to count terminating null, add it (yes NT does this) */
658         if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
659             count += sizeof(WCHAR);
660     }
661
662     RtlInitUnicodeString( &nameW, name );
663     return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
664 }
665
666
667 /******************************************************************************
668  *           RegSetValueExA   [ADVAPI32.@]
669  */
670 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
671                              CONST BYTE *data, DWORD count )
672 {
673     ANSI_STRING nameA;
674     WCHAR *dataW = NULL;
675     NTSTATUS status;
676
677     if (GetVersion() & 0x80000000)  /* win95 */
678     {
679         if (type == REG_SZ) count = strlen(data) + 1;
680     }
681     else if (count && is_string(type))
682     {
683         /* if user forgot to count terminating null, add it (yes NT does this) */
684         if (data[count-1] && !data[count]) count++;
685     }
686
687     if (is_string( type )) /* need to convert to Unicode */
688     {
689         DWORD lenW;
690         RtlMultiByteToUnicodeSize( &lenW, data, count );
691         if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
692         RtlMultiByteToUnicodeN( dataW, lenW, NULL, data, count );
693         count = lenW;
694         data = (BYTE *)dataW;
695     }
696
697     RtlInitAnsiString( &nameA, name );
698     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
699                                                  &nameA, FALSE )))
700     {
701         status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
702     }
703     if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
704     return RtlNtStatusToDosError( status );
705 }
706
707
708 /******************************************************************************
709  *           RegSetValueW   [ADVAPI32.@]
710  */
711 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
712 {
713     HKEY subkey = hkey;
714     DWORD ret;
715
716     TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
717
718     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
719
720     if (name && name[0])  /* need to create the subkey */
721     {
722         if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
723     }
724
725     ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (LPBYTE)data,
726                           (strlenW( data ) + 1) * sizeof(WCHAR) );
727     if (subkey != hkey) RegCloseKey( subkey );
728     return ret;
729 }
730
731
732 /******************************************************************************
733  *           RegSetValueA   [ADVAPI32.@]
734  */
735 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
736 {
737     HKEY subkey = hkey;
738     DWORD ret;
739
740     TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
741
742     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
743
744     if (name && name[0])  /* need to create the subkey */
745     {
746         if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
747     }
748     ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
749     if (subkey != hkey) RegCloseKey( subkey );
750     return ret;
751 }
752
753
754
755 /******************************************************************************
756  *           RegQueryValueExW   [ADVAPI32.@]
757  *
758  * Retrieves type and data for a specified name associated with an open key
759  *
760  * PARAMS
761  *    hkey      [I]   Handle of key to query
762  *    name      [I]   Name of value to query
763  *    reserved  [I]   Reserved - must be NULL
764  *    type      [O]   Address of buffer for value type.  If NULL, the type
765  *                        is not required.
766  *    data      [O]   Address of data buffer.  If NULL, the actual data is
767  *                        not required.
768  *    count     [I/O] Address of data buffer size
769  *
770  * RETURNS 
771  *    ERROR_SUCCESS:   Success
772  *    ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
773  *                     buffer is left untouched. The MS-documentation is wrong (js) !!!
774  */
775 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
776                                LPBYTE data, LPDWORD count )
777 {
778     NTSTATUS status;
779     UNICODE_STRING name_str;
780     DWORD total_size;
781     char buffer[256], *buf_ptr = buffer;
782     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
783     static const int info_size = info->Data - (UCHAR *)info;
784
785     TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
786           hkey, debugstr_w(name), reserved, type, data, count, count ? *count : 0 );
787
788     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
789
790     RtlInitUnicodeString( &name_str, name );
791
792     if (data) total_size = min( sizeof(buffer), *count + info_size );
793     else total_size = info_size;
794
795     status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
796                               buffer, total_size, &total_size );
797     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
798
799     if (data)
800     {
801         /* retry with a dynamically allocated buffer */
802         while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
803         {
804             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
805             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
806                 return ERROR_NOT_ENOUGH_MEMORY;
807             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
808             status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
809                                       buf_ptr, total_size, &total_size );
810         }
811
812         if (!status)
813         {
814             memcpy( data, buf_ptr + info_size, total_size - info_size );
815             /* if the type is REG_SZ and data is not 0-terminated
816              * and there is enough space in the buffer NT appends a \0 */
817             if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
818             {
819                 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
820                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
821             }
822         }
823         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
824     }
825     else status = STATUS_SUCCESS;
826
827     if (type) *type = info->Type;
828     if (count) *count = total_size - info_size;
829
830  done:
831     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
832     return RtlNtStatusToDosError(status);
833 }
834
835
836 /******************************************************************************
837  *           RegQueryValueExA   [ADVAPI32.@]
838  *
839  * NOTES:
840  * the documentation is wrong: if the buffer is too small it remains untouched 
841  */
842 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
843                                LPBYTE data, LPDWORD count )
844 {
845     NTSTATUS status;
846     ANSI_STRING nameA;
847     DWORD total_size;
848     char buffer[256], *buf_ptr = buffer;
849     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
850     static const int info_size = info->Data - (UCHAR *)info;
851
852     TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
853           hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
854
855     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
856
857     RtlInitAnsiString( &nameA, name );
858     if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
859                                                 &nameA, FALSE )))
860         return RtlNtStatusToDosError(status);
861
862     status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
863                               KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
864     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
865
866     /* we need to fetch the contents for a string type even if not requested,
867      * because we need to compute the length of the ASCII string. */
868     if (data || is_string(info->Type))
869     {
870         /* retry with a dynamically allocated buffer */
871         while (status == STATUS_BUFFER_OVERFLOW)
872         {
873             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
874             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
875             {
876                 status = STATUS_NO_MEMORY;
877                 goto done;
878             }
879             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
880             status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
881                                     KeyValuePartialInformation, buf_ptr, total_size, &total_size );
882         }
883
884         if (status) goto done;
885
886         if (is_string(info->Type))
887         {
888             DWORD len;
889
890             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
891                                        total_size - info_size );
892             if (data && len)
893             {
894                 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
895                 else
896                 {
897                     RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info_size),
898                                             total_size - info_size );
899                     /* if the type is REG_SZ and data is not 0-terminated
900                      * and there is enough space in the buffer NT appends a \0 */
901                     if (len < *count && data[len-1]) data[len] = 0;
902                 }
903             }
904             total_size = len + info_size;
905         }
906         else if (data)
907         {
908             if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
909             else memcpy( data, buf_ptr + info_size, total_size - info_size );
910         }
911     }
912     else status = STATUS_SUCCESS;
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     return RtlNtStatusToDosError(status);
920 }
921
922
923 /******************************************************************************
924  *           RegQueryValueW   [ADVAPI32.@]
925  */
926 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
927 {
928     DWORD ret;
929     HKEY subkey = hkey;
930
931     TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
932
933     if (name && name[0])
934     {
935         if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
936     }
937     ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
938     if (subkey != hkey) RegCloseKey( subkey );
939     if (ret == ERROR_FILE_NOT_FOUND)
940     {
941         /* return empty string if default value not found */
942         if (data) *data = 0;
943         if (count) *count = 1;
944         ret = ERROR_SUCCESS;
945     }
946     return ret;
947 }
948
949
950 /******************************************************************************
951  *           RegQueryValueA   [ADVAPI32.@]
952  */
953 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
954 {
955     DWORD ret;
956     HKEY subkey = hkey;
957
958     TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
959
960     if (name && name[0])
961     {
962         if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
963     }
964     ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
965     if (subkey != hkey) RegCloseKey( subkey );
966     if (ret == ERROR_FILE_NOT_FOUND)
967     {
968         /* return empty string if default value not found */
969         if (data) *data = 0;
970         if (count) *count = 1;
971         ret = ERROR_SUCCESS;
972     }
973     return ret;
974 }
975
976
977 /******************************************************************************
978  *           RegEnumValueW   [ADVAPI32.@]
979  *
980  * PARAMS
981  *    hkey       [I] Handle to key to query
982  *    index      [I] Index of value to query
983  *    value      [O] Value string
984  *    val_count  [I/O] Size of value buffer (in wchars)
985  *    reserved   [I] Reserved
986  *    type       [O] Type code
987  *    data       [O] Value data
988  *    count      [I/O] Size of data buffer (in bytes)
989  */
990
991 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
992                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
993 {
994     NTSTATUS status;
995     DWORD total_size;
996     char buffer[256], *buf_ptr = buffer;
997     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
998     static const int info_size = (char *)info->Name - (char *)info;
999
1000     TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
1001           hkey, index, value, val_count, reserved, type, data, count );
1002
1003     /* NT only checks count, not val_count */
1004     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1005
1006     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1007     if (data) total_size += *count;
1008     total_size = min( sizeof(buffer), total_size );
1009
1010     status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1011                                   buffer, total_size, &total_size );
1012     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1013
1014     if (value || data)
1015     {
1016         /* retry with a dynamically allocated buffer */
1017         while (status == STATUS_BUFFER_OVERFLOW)
1018         {
1019             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1020             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1021                 return ERROR_NOT_ENOUGH_MEMORY;
1022             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1023             status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1024                                           buf_ptr, total_size, &total_size );
1025         }
1026
1027         if (status) goto done;
1028
1029         if (value)
1030         {
1031             if (info->NameLength/sizeof(WCHAR) >= *val_count)
1032             {
1033                 status = STATUS_BUFFER_OVERFLOW;
1034                 goto done;
1035             }
1036             memcpy( value, info->Name, info->NameLength );
1037             *val_count = info->NameLength / sizeof(WCHAR);
1038             value[*val_count] = 0;
1039         }
1040
1041         if (data)
1042         {
1043             if (total_size - info->DataOffset > *count)
1044             {
1045                 status = STATUS_BUFFER_OVERFLOW;
1046                 goto done;
1047             }
1048             memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1049             if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1050             {
1051                 /* if the type is REG_SZ and data is not 0-terminated
1052                  * and there is enough space in the buffer NT appends a \0 */
1053                 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1054                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1055             }
1056         }
1057     }
1058     else status = STATUS_SUCCESS;
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.@]
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 = (char *)info->Name - (char *)info;
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;
1115
1116             RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1117             if (len >= *val_count)
1118             {
1119                 status = STATUS_BUFFER_OVERFLOW;
1120                 goto done;
1121             }
1122             RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1123             value[len] = 0;
1124             *val_count = len;
1125         }
1126
1127         if (is_string(info->Type))
1128         {
1129             DWORD len;
1130             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1131                                        total_size - info->DataOffset );
1132             if (data && len)
1133             {
1134                 if (len > *count)
1135                 {
1136                     status = STATUS_BUFFER_OVERFLOW;
1137                     goto done;
1138                 }
1139                 RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1140                                         total_size - info->DataOffset );
1141                 /* if the type is REG_SZ and data is not 0-terminated
1142                  * and there is enough space in the buffer NT appends a \0 */
1143                 if (len < *count && data[len-1]) data[len] = 0;
1144             }
1145             info->DataLength = len;
1146         }
1147         else if (data)
1148         {
1149             if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1150             else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1151         }
1152     }
1153     else status = STATUS_SUCCESS;
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.@]
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.@]
1185  */
1186 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1187 {
1188     STRING nameA;
1189     NTSTATUS status;
1190
1191     RtlInitAnsiString( &nameA, name );
1192     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1193                                                  &nameA, FALSE )))
1194     {
1195         status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1196     }
1197     return RtlNtStatusToDosError( status );
1198 }
1199
1200
1201 /******************************************************************************
1202  *           RegLoadKeyW   [ADVAPI32.@]
1203  *
1204  * PARAMS
1205  *    hkey      [I] Handle of open key
1206  *    subkey    [I] Address of name of subkey
1207  *    filename  [I] Address of filename for registry information
1208  */
1209 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1210 {
1211     HANDLE file;
1212     DWORD ret, len, err = GetLastError();
1213
1214     TRACE( "(%x,%s,%s)\n", hkey, debugstr_w(subkey), debugstr_w(filename) );
1215
1216     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1217     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1218
1219     len = strlenW( subkey ) * sizeof(WCHAR);
1220     if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
1221
1222     if ((file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1223                              FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
1224     {
1225         ret = GetLastError();
1226         goto done;
1227     }
1228
1229     SERVER_START_REQ( load_registry )
1230     {
1231         req->hkey  = hkey;
1232         req->file  = file;
1233         wine_server_add_data( req, subkey, len );
1234         ret = RtlNtStatusToDosError( wine_server_call(req) );
1235     }
1236     SERVER_END_REQ;
1237     CloseHandle( file );
1238
1239  done:
1240     SetLastError( err );  /* restore the last error code */
1241     return ret;
1242 }
1243
1244
1245 /******************************************************************************
1246  *           RegLoadKeyA   [ADVAPI32.@]
1247  */
1248 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1249 {
1250     WCHAR buffer[MAX_PATH];
1251     HANDLE file;
1252     DWORD ret, len, err = GetLastError();
1253
1254     TRACE( "(%x,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
1255
1256     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1257     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1258
1259     if (!(len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), buffer, MAX_PATH )))
1260         return ERROR_INVALID_PARAMETER;
1261
1262     if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1263                              FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
1264     {
1265         ret = GetLastError();
1266         goto done;
1267     }
1268
1269     SERVER_START_REQ( load_registry )
1270     {
1271         req->hkey  = hkey;
1272         req->file  = file;
1273         wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
1274         ret = RtlNtStatusToDosError( wine_server_call(req) );
1275     }
1276     SERVER_END_REQ;
1277     CloseHandle( file );
1278
1279  done:
1280     SetLastError( err );  /* restore the last error code */
1281     return ret;
1282 }
1283
1284
1285 /******************************************************************************
1286  *           RegSaveKeyA   [ADVAPI32.@]
1287  *
1288  * PARAMS
1289  *    hkey   [I] Handle of key where save begins
1290  *    lpFile [I] Address of filename to save to
1291  *    sa     [I] Address of security structure
1292  */
1293 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
1294 {
1295     char buffer[1024];
1296     int count = 0;
1297     LPSTR name;
1298     DWORD ret, err;
1299     HFILE handle;
1300
1301     TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa );
1302
1303     if (!file || !*file) return ERROR_INVALID_PARAMETER;
1304
1305     err = GetLastError();
1306     GetFullPathNameA( file, sizeof(buffer), buffer, &name );
1307     for (;;)
1308     {
1309         sprintf( name, "reg%04x.tmp", count++ );
1310         handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
1311                             CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1312         if (handle != INVALID_HANDLE_VALUE) break;
1313         if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
1314
1315         /* Something gone haywire ? Please report if this happens abnormally */
1316         if (count >= 100)
1317             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);
1318     }
1319
1320     SERVER_START_REQ( save_registry )
1321     {
1322         req->hkey = hkey;
1323         req->file = handle;
1324         ret = RtlNtStatusToDosError( wine_server_call( req ) );
1325     }
1326     SERVER_END_REQ;
1327
1328     CloseHandle( handle );
1329     if (!ret)
1330     {
1331         if (!MoveFileExA( buffer, file, MOVEFILE_REPLACE_EXISTING ))
1332         {
1333             ERR( "Failed to move %s to %s\n", buffer, file );
1334             ret = GetLastError();
1335         }
1336     }
1337     if (ret) DeleteFileA( buffer );
1338
1339 done:
1340     SetLastError( err );  /* restore last error code */
1341     return ret;
1342 }
1343
1344
1345 /******************************************************************************
1346  *           RegSaveKeyW   [ADVAPI32.@]
1347  */
1348 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1349 {
1350     LPSTR fileA = HEAP_strdupWtoA( GetProcessHeap(), 0, file );
1351     DWORD ret = RegSaveKeyA( hkey, fileA, sa );
1352     if (fileA) HeapFree( GetProcessHeap(), 0, fileA );
1353     return ret;
1354 }
1355
1356
1357 /******************************************************************************
1358  * RegRestoreKeyW [ADVAPI32.@]
1359  *
1360  * PARAMS
1361  *    hkey    [I] Handle of key where restore begins
1362  *    lpFile  [I] Address of filename containing saved tree
1363  *    dwFlags [I] Optional flags
1364  */
1365 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1366 {
1367     TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1368
1369     /* It seems to do this check before the hkey check */
1370     if (!lpFile || !*lpFile)
1371         return ERROR_INVALID_PARAMETER;
1372
1373     FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1374
1375     /* Check for file existence */
1376
1377     return ERROR_SUCCESS;
1378 }
1379
1380
1381 /******************************************************************************
1382  * RegRestoreKeyA [ADVAPI32.@]
1383  */
1384 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1385 {
1386     LPWSTR lpFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile );
1387     LONG ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1388     HeapFree( GetProcessHeap(), 0, lpFileW );
1389     return ret;
1390 }
1391
1392
1393 /******************************************************************************
1394  * RegUnLoadKeyW [ADVAPI32.@]
1395  *
1396  * PARAMS
1397  *    hkey     [I] Handle of open key
1398  *    lpSubKey [I] Address of name of subkey to unload
1399  */
1400 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1401 {
1402     FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1403     return ERROR_SUCCESS;
1404 }
1405
1406
1407 /******************************************************************************
1408  * RegUnLoadKeyA [ADVAPI32.@]
1409  */
1410 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1411 {
1412     LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1413     LONG ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1414     if(lpSubKeyW) HeapFree( GetProcessHeap(), 0, lpSubKeyW);
1415     return ret;
1416 }
1417
1418
1419 /******************************************************************************
1420  * RegReplaceKeyW [ADVAPI32.@]
1421  *
1422  * PARAMS
1423  *    hkey      [I] Handle of open key
1424  *    lpSubKey  [I] Address of name of subkey
1425  *    lpNewFile [I] Address of filename for file with new data
1426  *    lpOldFile [I] Address of filename for backup file
1427  */
1428 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1429                               LPCWSTR lpOldFile )
1430 {
1431     FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey), 
1432           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1433     return ERROR_SUCCESS;
1434 }
1435
1436
1437 /******************************************************************************
1438  * RegReplaceKeyA [ADVAPI32.@]
1439  */
1440 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1441                               LPCSTR lpOldFile )
1442 {
1443     LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1444     LPWSTR lpNewFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile );
1445     LPWSTR lpOldFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile );
1446     LONG ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1447     HeapFree( GetProcessHeap(), 0, lpOldFileW );
1448     HeapFree( GetProcessHeap(), 0, lpNewFileW );
1449     HeapFree( GetProcessHeap(), 0, lpSubKeyW );
1450     return ret;
1451 }
1452
1453
1454 /******************************************************************************
1455  * RegSetKeySecurity [ADVAPI32.@]
1456  *
1457  * PARAMS
1458  *    hkey          [I] Open handle of key to set
1459  *    SecurityInfo  [I] Descriptor contents
1460  *    pSecurityDesc [I] Address of descriptor for key
1461  */
1462 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1463                                PSECURITY_DESCRIPTOR pSecurityDesc )
1464 {
1465     TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1466
1467     /* It seems to perform this check before the hkey check */
1468     if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1469         (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1470         (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1471         (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1472         /* Param OK */
1473     } else
1474         return ERROR_INVALID_PARAMETER;
1475
1476     if (!pSecurityDesc)
1477         return ERROR_INVALID_PARAMETER;
1478
1479     FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1480
1481     return ERROR_SUCCESS;
1482 }
1483
1484
1485 /******************************************************************************
1486  * RegGetKeySecurity [ADVAPI32.@]
1487  * Retrieves a copy of security descriptor protecting the registry key
1488  *
1489  * PARAMS
1490  *    hkey                   [I]   Open handle of key to set
1491  *    SecurityInformation    [I]   Descriptor contents
1492  *    pSecurityDescriptor    [O]   Address of descriptor for key
1493  *    lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1494  *
1495  * RETURNS
1496  *    Success: ERROR_SUCCESS
1497  *    Failure: Error code
1498  */
1499 LONG WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
1500                                PSECURITY_DESCRIPTOR pSecurityDescriptor,
1501                                LPDWORD lpcbSecurityDescriptor )
1502 {
1503     TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1504           lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1505
1506     /* FIXME: Check for valid SecurityInformation values */
1507
1508     if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1509         return ERROR_INSUFFICIENT_BUFFER;
1510
1511     FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1512           pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1513
1514     return ERROR_SUCCESS;
1515 }
1516
1517
1518 /******************************************************************************
1519  * RegFlushKey [ADVAPI32.@]
1520  * Immediately writes key to registry.
1521  * Only returns after data has been written to disk.
1522  *
1523  * FIXME: does it really wait until data is written ?
1524  *
1525  * PARAMS
1526  *    hkey [I] Handle of key to write
1527  *
1528  * RETURNS
1529  *    Success: ERROR_SUCCESS
1530  *    Failure: Error code
1531  */
1532 DWORD WINAPI RegFlushKey( HKEY hkey )
1533 {
1534     FIXME( "(%x): stub\n", hkey );
1535     return ERROR_SUCCESS;
1536 }
1537
1538
1539 /******************************************************************************
1540  * RegConnectRegistryW [ADVAPI32.@]
1541  *
1542  * PARAMS
1543  *    lpMachineName [I] Address of name of remote computer
1544  *    hHey          [I] Predefined registry handle
1545  *    phkResult     [I] Address of buffer for remote registry handle
1546  */
1547 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey, 
1548                                    LPHKEY phkResult )
1549 {
1550     TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1551
1552     if (!lpMachineName || !*lpMachineName) {
1553         /* Use the local machine name */
1554         return RegOpenKeyA( hKey, "", phkResult );
1555     }
1556
1557     FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1558     return ERROR_BAD_NETPATH;
1559 }
1560
1561
1562 /******************************************************************************
1563  * RegConnectRegistryA [ADVAPI32.@]
1564  */
1565 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1566 {
1567     LPWSTR machineW = HEAP_strdupAtoW( GetProcessHeap(), 0, machine );
1568     DWORD ret = RegConnectRegistryW( machineW, hkey, reskey );
1569     HeapFree( GetProcessHeap(), 0, machineW );
1570     return ret;
1571 }
1572
1573
1574 /******************************************************************************
1575  * RegNotifyChangeKeyValue [ADVAPI32.@]
1576  *
1577  * PARAMS
1578  *    hkey            [I] Handle of key to watch
1579  *    fWatchSubTree   [I] Flag for subkey notification
1580  *    fdwNotifyFilter [I] Changes to be reported
1581  *    hEvent          [I] Handle of signaled event
1582  *    fAsync          [I] Flag for asynchronous reporting
1583  */
1584 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree, 
1585                                      DWORD fdwNotifyFilter, HANDLE hEvent,
1586                                      BOOL fAsync )
1587 {
1588     FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1589           hEvent,fAsync);
1590     return ERROR_SUCCESS;
1591 }