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