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