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