Changed the server to return STATUS_* error codes.
[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 <unistd.h>
17
18 #include "winbase.h"
19 #include "winreg.h"
20 #include "winerror.h"
21 #include "wine/winbase16.h"
22 #include "winversion.h"
23 #include "file.h"
24 #include "heap.h"
25 #include "server.h"
26 #include "debugtools.h"
27
28 DEFAULT_DEBUG_CHANNEL(reg)
29
30
31 /* Ansi->Unicode conversion without string delimiters */
32 static LPWSTR memcpyAtoW( LPWSTR dst, LPCSTR src, INT n )
33 {
34     LPWSTR p = dst;
35     while (n-- > 0) *p++ = (WCHAR)*src++;
36     return dst;
37 }
38
39 /* Unicode->Ansi conversion without string delimiters */
40 static LPSTR memcpyWtoA( LPSTR dst, LPCWSTR src, INT n )
41 {
42     LPSTR p = dst;
43     while (n-- > 0) *p++ = (CHAR)*src++;
44     return dst;
45 }
46
47 /* check if value type needs string conversion (Ansi<->Unicode) */
48 static inline int is_string( DWORD type )
49 {
50     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
51 }
52
53 /* copy key value data into a user-specified buffer
54  *
55  * 'len' is the total length of the data
56  * 'count' is the size of the user-specified buffer
57  * and is updated to reflect the length copied
58  *
59  * if the type is REG_SZ and data is not 0-terminated and there is enough space in the
60  * buffer nt appends a \0
61  */
62 static DWORD copy_data( void *data, const void *src, DWORD len, DWORD *count, DWORD type )
63 {
64     DWORD ret = ERROR_SUCCESS;
65     if (data)
66     {
67         if (*count < len) ret = ERROR_MORE_DATA;
68         else memcpy( data, src, len );
69     }
70     if (count) 
71     {
72         if (is_string( type ) && len && (len < *count) && ((WCHAR *)data)[len-1])
73             ((WCHAR *)data)[len] = 0;
74         *count = len;
75     }
76     return ret;
77 }
78
79 /* same as copy_data but with optional Unicode->Ascii conversion depending on the type */
80 static DWORD copy_data_WtoA( void *data, const void *src, DWORD len, DWORD *count, DWORD type )
81 {
82     DWORD ret = ERROR_SUCCESS;
83     if (is_string( type ))
84     {
85         /* need to convert from Unicode */
86         len /= sizeof(WCHAR);
87         if (data)
88         {
89             if (*count < len) ret = ERROR_MORE_DATA;
90             else if (len)
91             {
92                 memcpyWtoA( data, src, len );
93                 if ((len < *count) && ((char*)data)[len-1]) ((char *)data)[len] = 0;
94             }
95         }
96     }
97     else if (data)
98     {
99         if (*count < len) ret = ERROR_MORE_DATA;
100         else memcpy( data, src, len );
101     }
102     if (count) *count = len;
103     return ret;
104 }
105
106 /* copy a key name into the request buffer */
107 static inline DWORD copy_nameW( LPWSTR dest, LPCWSTR name )
108 {
109     if (name)
110     {
111         if (lstrlenW(name) > MAX_PATH) return ERROR_MORE_DATA;
112         lstrcpyW( dest, name );
113     }
114     else dest[0] = 0;
115     return ERROR_SUCCESS;
116 }
117
118 /* copy a key name into the request buffer */
119 static inline DWORD copy_nameAtoW( LPWSTR dest, LPCSTR name )
120 {
121     if (name)
122     {
123         if (strlen(name) > MAX_PATH) return ERROR_MORE_DATA;
124         lstrcpyAtoW( dest, name );
125     }
126     else dest[0] = 0;
127     return ERROR_SUCCESS;
128 }
129
130 /* do a server call without setting the last error code */
131 static inline int reg_server_call( enum request req )
132 {
133     unsigned int res = server_call_noerr( req );
134     if (res) res = RtlNtStatusToDosError(res);
135     return res;
136 }
137
138 /******************************************************************************
139  *           RegCreateKeyExW   [ADVAPI32.131]
140  *
141  * PARAMS
142  *    hkey       [I] Handle of an open key
143  *    name       [I] Address of subkey name
144  *    reserved   [I] Reserved - must be 0
145  *    class      [I] Address of class string
146  *    options    [I] Special options flag
147  *    access     [I] Desired security access
148  *    sa         [I] Address of key security structure
149  *    retkey     [O] Address of buffer for opened handle
150  *    dispos     [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
151  *
152  * NOTES
153  *  in case of failing retkey remains untouched
154  */
155 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
156                               DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa, 
157                               LPHKEY retkey, LPDWORD dispos )
158 {
159     DWORD ret;
160     struct create_key_request *req = get_req_buffer();
161
162     TRACE( "(0x%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey, debugstr_w(name), reserved,
163            debugstr_w(class), options, access, sa, retkey, dispos );
164
165     if (reserved) return ERROR_INVALID_PARAMETER;
166     if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
167
168     req->parent  = hkey;
169     req->access  = access;
170     req->options = options;
171     req->modif   = time(NULL);
172     if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
173     if (req->name[0] == '\\') return ERROR_BAD_PATHNAME;
174     lstrcpynW( req->class, class ? class : (LPWSTR)"\0\0",
175                server_remaining(req->class) / sizeof(WCHAR) );
176     if ((ret = reg_server_call( REQ_CREATE_KEY )) == ERROR_SUCCESS)
177     {
178         *retkey = req->hkey;
179         if (dispos) *dispos = req->created ? REG_CREATED_NEW_KEY : REG_OPENED_EXISTING_KEY;
180     }
181     return ret;
182 }
183
184
185 /******************************************************************************
186  *           RegCreateKeyExA   [ADVAPI32.130]
187  */
188 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
189                               DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa, 
190                               LPHKEY retkey, LPDWORD dispos )
191 {
192     DWORD ret;
193     struct create_key_request *req = get_req_buffer();
194
195     TRACE( "(0x%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey, debugstr_a(name), reserved,
196            debugstr_a(class), options, access, sa, retkey, dispos );
197
198     if (reserved) return ERROR_INVALID_PARAMETER;
199     if (!(access & KEY_ALL_ACCESS) || (access & ~KEY_ALL_ACCESS)) return ERROR_ACCESS_DENIED;
200
201     req->parent  = hkey;
202     req->access  = access;
203     req->options = options;
204     req->modif   = time(NULL);
205     if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
206     if (req->name[0] == '\\') return ERROR_BAD_PATHNAME;
207     lstrcpynAtoW( req->class, class ? class : "",
208                   server_remaining(req->class) / sizeof(WCHAR) );
209     if ((ret = reg_server_call( REQ_CREATE_KEY )) == ERROR_SUCCESS)
210     {
211         *retkey = req->hkey;
212         if (dispos) *dispos = req->created ? REG_CREATED_NEW_KEY : REG_OPENED_EXISTING_KEY;
213     }
214     return ret;
215 }
216
217
218 /******************************************************************************
219  *           RegCreateKeyW   [ADVAPI32.132]
220  */
221 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
222 {
223     /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
224     /* but at least my version of NT (4.0 SP5) doesn't do this.  -- AJ */
225     return RegCreateKeyExW( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
226                             KEY_ALL_ACCESS, NULL, retkey, NULL );
227 }
228
229
230 /******************************************************************************
231  *           RegCreateKeyA   [ADVAPI32.129]
232  */
233 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
234 {
235     return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
236                             KEY_ALL_ACCESS, NULL, retkey, NULL );
237 }
238
239
240
241 /******************************************************************************
242  *           RegOpenKeyExW   [ADVAPI32.150]
243  *
244  * Opens the specified key
245  *
246  * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
247  *
248  * PARAMS
249  *    hkey       [I] Handle of open key
250  *    name       [I] Name of subkey to open
251  *    reserved   [I] Reserved - must be zero
252  *    access     [I] Security access mask
253  *    retkey     [O] Handle to open key
254  *
255  * RETURNS
256  *    Success: ERROR_SUCCESS
257  *    Failure: Error code
258  *
259  * NOTES
260  *  in case of failing is retkey = 0
261  */
262 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
263 {
264     DWORD ret;
265     struct open_key_request *req = get_req_buffer();
266
267     TRACE( "(0x%x,%s,%ld,%lx,%p)\n", hkey, debugstr_w(name), reserved, access, retkey );
268
269     if (!retkey) return ERROR_INVALID_PARAMETER;
270     *retkey = 0;
271
272     req->parent = hkey;
273     req->access = access;
274     if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
275     if (req->name[0] == '\\') return ERROR_BAD_PATHNAME;
276     if ((ret = reg_server_call( REQ_OPEN_KEY )) == ERROR_SUCCESS) *retkey = req->hkey;
277     return ret;
278 }
279
280
281 /******************************************************************************
282  *           RegOpenKeyExA   [ADVAPI32.149]
283  */
284 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, LPHKEY retkey )
285 {
286     DWORD ret;
287     struct open_key_request *req = get_req_buffer();
288
289     TRACE( "(0x%x,%s,%ld,%lx,%p)\n", hkey, debugstr_a(name), reserved, access, retkey );
290
291     if (!retkey) return ERROR_INVALID_PARAMETER;
292     *retkey = 0;
293
294     req->parent = hkey;
295     req->access = access;
296     if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
297     if (req->name[0] == '\\') return ERROR_BAD_PATHNAME;
298     if ((ret = reg_server_call( REQ_OPEN_KEY )) == ERROR_SUCCESS) *retkey = req->hkey;
299     return ret;
300 }
301
302
303 /******************************************************************************
304  *           RegOpenKeyW   [ADVAPI32.151]
305  *
306  * PARAMS
307  *    hkey    [I] Handle of open key
308  *    name    [I] Address of name of subkey to open
309  *    retkey  [O] Handle to open key
310  *
311  * RETURNS
312  *    Success: ERROR_SUCCESS
313  *    Failure: Error code
314  *
315  * NOTES
316  *  in case of failing is retkey = 0
317  */
318 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, LPHKEY retkey )
319 {
320     return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
321 }
322
323
324 /******************************************************************************
325  *           RegOpenKeyA   [ADVAPI32.148]
326  */
327 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
328 {
329     return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
330 }
331
332
333
334 /******************************************************************************
335  *           RegEnumKeyExW   [ADVAPI32.139]
336  *
337  * PARAMS
338  *    hkey         [I] Handle to key to enumerate
339  *    index        [I] Index of subkey to enumerate
340  *    name         [O] Buffer for subkey name
341  *    name_len     [O] Size of subkey buffer
342  *    reserved     [I] Reserved
343  *    class        [O] Buffer for class string
344  *    class_len    [O] Size of class buffer
345  *    ft           [O] Time key last written to
346  */
347 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
348                             LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
349 {
350     DWORD ret, len, cls_len;
351     struct enum_key_request *req = get_req_buffer();
352
353     TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
354            name_len ? *name_len : -1, reserved, class, class_len, ft );
355
356     if (reserved) return ERROR_INVALID_PARAMETER;
357
358     req->hkey = hkey;
359     req->index = index;
360     if ((ret = reg_server_call( REQ_ENUM_KEY )) != ERROR_SUCCESS) return ret;
361
362     len = lstrlenW( req->name ) + 1;
363     cls_len = lstrlenW( req->class ) + 1;
364     if (len > *name_len) return ERROR_MORE_DATA;
365     if (class_len && (cls_len > *class_len)) return ERROR_MORE_DATA;
366
367     memcpy( name, req->name, len * sizeof(WCHAR) );
368     *name_len = len - 1;
369     if (class_len)
370     {
371         if (class) memcpy( class, req->class, cls_len * sizeof(WCHAR) );
372         *class_len = cls_len - 1;
373     }
374     if (ft) DOSFS_UnixTimeToFileTime( req->modif, ft, 0 );
375     return ERROR_SUCCESS;
376 }
377
378
379 /******************************************************************************
380  *           RegEnumKeyExA   [ADVAPI32.138]
381  */
382 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
383                             LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
384 {
385     DWORD ret, len, cls_len;
386     struct enum_key_request *req = get_req_buffer();
387
388     TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
389            name_len ? *name_len : -1, reserved, class, class_len, ft );
390
391     if (reserved) return ERROR_INVALID_PARAMETER;
392
393     req->hkey = hkey;
394     req->index = index;
395     if ((ret = reg_server_call( REQ_ENUM_KEY )) != ERROR_SUCCESS) return ret;
396
397     len = lstrlenW( req->name ) + 1;
398     cls_len = lstrlenW( req->class ) + 1;
399     if (len > *name_len) return ERROR_MORE_DATA;
400     if (class_len && (cls_len > *class_len)) return ERROR_MORE_DATA;
401
402     memcpyWtoA( name, req->name, len );
403     *name_len = len - 1;
404     if (class_len)
405     {
406         if (class) memcpyWtoA( class, req->class, cls_len );
407         *class_len = cls_len - 1;
408     }
409     if (ft) DOSFS_UnixTimeToFileTime( req->modif, ft, 0 );
410     return ERROR_SUCCESS;
411 }
412
413
414 /******************************************************************************
415  *           RegEnumKeyW   [ADVAPI32.140]
416  */
417 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
418 {
419     return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
420 }
421
422
423 /******************************************************************************
424  *           RegEnumKeyA   [ADVAPI32.137]
425  */
426 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
427 {
428     return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
429 }
430
431
432 /******************************************************************************
433  *           RegQueryInfoKeyW   [ADVAPI32.153]
434  *
435  * PARAMS
436  *    hkey       [I] Handle to key to query
437  *    class      [O] Buffer for class string
438  *    class_len  [O] Size of class string buffer
439  *    reserved   [I] Reserved
440  *    subkeys    [O] Buffer for number of subkeys
441  *    max_subkey [O] Buffer for longest subkey name length
442  *    max_class  [O] Buffer for longest class string length
443  *    values     [O] Buffer for number of value entries
444  *    max_value  [O] Buffer for longest value name length
445  *    max_data   [O] Buffer for longest value data length
446  *    security   [O] Buffer for security descriptor length
447  *    modif      [O] Modification time
448  *
449  * - win95 allows class to be valid and class_len to be NULL 
450  * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
451  * - both allow class to be NULL and class_len to be NULL 
452  * (it's hard to test validity, so test !NULL instead)
453  */
454 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
455                                LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
456                                LPDWORD values, LPDWORD max_value, LPDWORD max_data,
457                                LPDWORD security, FILETIME *modif )
458 {
459     DWORD ret;
460     struct query_key_info_request *req = get_req_buffer();
461
462
463     TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
464            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
465
466     if (class && !class_len && (VERSION_GetVersion() == NT40))
467         return ERROR_INVALID_PARAMETER;
468
469     req->hkey = hkey;
470     if ((ret = reg_server_call( REQ_QUERY_KEY_INFO )) != ERROR_SUCCESS) return ret;
471
472     if (class)
473     {
474         if (class_len && (lstrlenW(req->class) + 1 > *class_len))
475         {
476             *class_len = lstrlenW(req->class);
477             return ERROR_MORE_DATA;
478         }
479         lstrcpyW( class, req->class );
480     }
481     if (class_len) *class_len = lstrlenW( req->class );
482     if (subkeys) *subkeys = req->subkeys;
483     if (max_subkey) *max_subkey = req->max_subkey;
484     if (max_class) *max_class = req->max_class;
485     if (values) *values = req->values;
486     if (max_value) *max_value = req->max_value;
487     if (max_data) *max_data = req->max_data;
488     if (modif) DOSFS_UnixTimeToFileTime( req->modif, modif, 0 );
489     return ERROR_SUCCESS;
490 }
491
492
493 /******************************************************************************
494  *           RegQueryInfoKeyA   [ADVAPI32.152]
495  */
496 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
497                                LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
498                                LPDWORD values, LPDWORD max_value, LPDWORD max_data,
499                                LPDWORD security, FILETIME *modif )
500 {
501     DWORD ret;
502     struct query_key_info_request *req = get_req_buffer();
503
504
505     TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
506            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
507
508     if (class && !class_len && (VERSION_GetVersion() == NT40))
509         return ERROR_INVALID_PARAMETER;
510
511     req->hkey = hkey;
512     if ((ret = reg_server_call( REQ_QUERY_KEY_INFO )) != ERROR_SUCCESS) return ret;
513
514     if (class)
515     {
516         if (class_len && (lstrlenW(req->class) + 1 > *class_len))
517         {
518             *class_len = lstrlenW(req->class);
519             return ERROR_MORE_DATA;
520         }
521         lstrcpyWtoA( class, req->class );
522     }
523     if (class_len) *class_len = lstrlenW( req->class );
524     if (subkeys) *subkeys = req->subkeys;
525     if (max_subkey) *max_subkey = req->max_subkey;
526     if (max_class) *max_class = req->max_class;
527     if (values) *values = req->values;
528     if (max_value) *max_value = req->max_value;
529     if (max_data) *max_data = req->max_data;
530     if (modif) DOSFS_UnixTimeToFileTime( req->modif, modif, 0 );
531     return ERROR_SUCCESS;
532 }
533
534
535 /******************************************************************************
536  *           RegCloseKey   [ADVAPI32.126]
537  *
538  * Releases the handle of the specified key
539  *
540  * PARAMS
541  *    hkey [I] Handle of key to close
542  *
543  * RETURNS
544  *    Success: ERROR_SUCCESS
545  *    Failure: Error code
546  */
547 DWORD WINAPI RegCloseKey( HKEY hkey )
548 {
549     struct close_key_request *req = get_req_buffer();
550     TRACE( "(0x%x)\n", hkey );
551     req->hkey = hkey;
552     return reg_server_call( REQ_CLOSE_KEY );
553 }
554
555
556 /******************************************************************************
557  *           RegDeleteKeyW   [ADVAPI32.134]
558  *
559  * PARAMS
560  *    hkey   [I] Handle to open key
561  *    name   [I] Name of subkey to delete
562  *
563  * RETURNS
564  *    Success: ERROR_SUCCESS
565  *    Failure: Error code
566  */
567 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
568 {
569     DWORD ret;
570     struct delete_key_request *req = get_req_buffer();
571
572     TRACE( "(0x%x,%s)\n", hkey, debugstr_w(name) );
573
574     req->hkey = hkey;
575     if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
576     if (req->name[0] == '\\') return ERROR_BAD_PATHNAME;
577     return reg_server_call( REQ_DELETE_KEY );
578 }
579
580
581 /******************************************************************************
582  *           RegDeleteKeyA   [ADVAPI32.133]
583  */
584 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
585 {
586     DWORD ret;
587     struct delete_key_request *req = get_req_buffer();
588
589     TRACE( "(0x%x,%s)\n", hkey, debugstr_a(name) );
590
591     req->hkey = hkey;
592     if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
593     if (req->name[0] == '\\') return ERROR_BAD_PATHNAME;
594     return reg_server_call( REQ_DELETE_KEY );
595 }
596
597
598
599 /******************************************************************************
600  *           RegSetValueExW   [ADVAPI32.170]
601  *
602  * Sets the data and type of a value under a register key
603  *
604  * PARAMS
605  *    hkey       [I] Handle of key to set value for
606  *    name       [I] Name of value to set
607  *    reserved   [I] Reserved - must be zero
608  *    type       [I] Flag for value type
609  *    data       [I] Address of value data
610  *    count      [I] Size of value data
611  *
612  * RETURNS
613  *    Success: ERROR_SUCCESS
614  *    Failure: Error code
615  *
616  * NOTES
617  *   win95 does not care about count for REG_SZ and finds out the len by itself (js) 
618  *   NT does definitely care (aj)
619  */
620 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
621                              DWORD type, CONST BYTE *data, DWORD count )
622 {
623     DWORD ret;
624     struct set_key_value_request *req = get_req_buffer();
625
626     TRACE( "(0x%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(name), reserved, type, data, count );
627
628     if (reserved) return ERROR_INVALID_PARAMETER;
629
630     if (count && type == REG_SZ)
631     {
632         LPCWSTR str = (LPCWSTR)data;
633         /* if user forgot to count terminating null, add it (yes NT does this) */
634         if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
635             count += sizeof(WCHAR);
636     }
637     if (count >= server_remaining( req->data )) return ERROR_OUTOFMEMORY;  /* FIXME */
638     req->hkey = hkey;
639     req->type = type;
640     req->len = count;
641     if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
642     memcpy( req->data, data, count );
643     return reg_server_call( REQ_SET_KEY_VALUE );
644 }
645
646
647 /******************************************************************************
648  *           RegSetValueExA   [ADVAPI32.169]
649  */
650 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
651                              CONST BYTE *data, DWORD count )
652 {
653     DWORD ret;
654     struct set_key_value_request *req = get_req_buffer();
655
656     TRACE( "(0x%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_a(name), reserved, type, data, count );
657
658     if (reserved) return ERROR_INVALID_PARAMETER;
659
660     if (count && type == REG_SZ)
661     {
662         /* if user forgot to count terminating null, add it (yes NT does this) */
663         if (data[count-1] && !data[count]) count++;
664     }
665     if (is_string( type ))
666     {
667         /* need to convert to Unicode */
668         count *= sizeof(WCHAR);
669         if (count >= server_remaining( req->data )) return ERROR_OUTOFMEMORY;  /* FIXME */
670         memcpyAtoW( (LPWSTR)req->data, data, count / sizeof(WCHAR) );
671     }
672     else
673     {
674         if (count >= server_remaining( req->data )) return ERROR_OUTOFMEMORY;  /* FIXME */
675         memcpy( req->data, data, count );
676     }
677     req->hkey = hkey;
678     req->type = type;
679     req->len = count;
680     if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
681     return reg_server_call( REQ_SET_KEY_VALUE );
682 }
683
684
685 /******************************************************************************
686  *           RegSetValueW   [ADVAPI32.171]
687  */
688 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
689 {
690     HKEY subkey = hkey;
691     DWORD ret;
692
693     TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
694
695     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
696
697     if (name && name[0])  /* need to create the subkey */
698     {
699         if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
700     }
701
702     ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (LPBYTE)data,
703                           (lstrlenW( data ) + 1) * sizeof(WCHAR) );
704     if (subkey != hkey) RegCloseKey( subkey );
705     return ret;
706 }
707
708
709 /******************************************************************************
710  *           RegSetValueA   [ADVAPI32.168]
711  */
712 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
713 {
714     HKEY subkey = hkey;
715     DWORD ret;
716
717     TRACE("(0x%x,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
718
719     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
720
721     if (name && name[0])  /* need to create the subkey */
722     {
723         if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
724     }
725     ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
726     if (subkey != hkey) RegCloseKey( subkey );
727     return ret;
728 }
729
730
731
732 /******************************************************************************
733  *           RegQueryValueExW   [ADVAPI32.158]
734  *
735  * Retrieves type and data for a specified name associated with an open key
736  *
737  * PARAMS
738  *    hkey      [I]   Handle of key to query
739  *    name      [I]   Name of value to query
740  *    reserved  [I]   Reserved - must be NULL
741  *    type      [O]   Address of buffer for value type.  If NULL, the type
742  *                        is not required.
743  *    data      [O]   Address of data buffer.  If NULL, the actual data is
744  *                        not required.
745  *    count     [I/O] Address of data buffer size
746  *
747  * RETURNS 
748  *    ERROR_SUCCESS:   Success
749  *    ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
750  *                     buffer is left untouched. The MS-documentation is wrong (js) !!!
751  */
752 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
753                                LPBYTE data, LPDWORD count )
754 {
755     DWORD ret;
756     struct get_key_value_request *req = get_req_buffer();
757
758     TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
759           hkey, debugstr_w(name), reserved, type, data, count, count ? *count : 0 );
760
761     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
762
763     req->hkey = hkey;
764     if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
765     if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) == ERROR_SUCCESS)
766     {
767         if (type) *type = req->type;
768         ret = copy_data( data, req->data, req->len, count, req->type );
769     }
770     return ret;
771 }
772
773
774 /******************************************************************************
775  *           RegQueryValueExA   [ADVAPI32.157]
776  *
777  * NOTES:
778  * the documentation is wrong: if the buffer is to small it remains untouched 
779  */
780 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
781                                LPBYTE data, LPDWORD count )
782 {
783     DWORD ret;
784     struct get_key_value_request *req = get_req_buffer();
785
786     TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
787           hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
788
789     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
790
791     req->hkey = hkey;
792     if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
793     if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) == ERROR_SUCCESS)
794     {
795         if (type) *type = req->type;
796         ret = copy_data_WtoA( data, req->data, req->len, count, req->type );
797     }
798     return ret;
799 }
800
801
802 /******************************************************************************
803  *           RegQueryValueW   [ADVAPI32.159]
804  */
805 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
806 {
807     DWORD ret;
808     HKEY subkey = hkey;
809
810     TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
811
812     if (name && name[0])
813     {
814         if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
815     }
816     ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
817     if (subkey != hkey) RegCloseKey( subkey );
818     if (ret == ERROR_FILE_NOT_FOUND)
819     {
820         /* return empty string if default value not found */
821         if (data) *data = 0;
822         if (count) *count = 1;
823         ret = ERROR_SUCCESS;
824     }
825     return ret;
826 }
827
828
829 /******************************************************************************
830  *           RegQueryValueA   [ADVAPI32.156]
831  */
832 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
833 {
834     DWORD ret;
835     HKEY subkey = hkey;
836
837     TRACE("(%x,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
838
839     if (name && name[0])
840     {
841         if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
842     }
843     ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
844     if (subkey != hkey) RegCloseKey( subkey );
845     if (ret == ERROR_FILE_NOT_FOUND)
846     {
847         /* return empty string if default value not found */
848         if (data) *data = 0;
849         if (count) *count = 1;
850         ret = ERROR_SUCCESS;
851     }
852     return ret;
853 }
854
855
856 /******************************************************************************
857  *           RegEnumValueW   [ADVAPI32.142]
858  *
859  * PARAMS
860  *    hkey       [I] Handle to key to query
861  *    index      [I] Index of value to query
862  *    value      [O] Value string
863  *    val_count  [I/O] Size of value buffer (in wchars)
864  *    reserved   [I] Reserved
865  *    type       [O] Type code
866  *    data       [O] Value data
867  *    count      [I/O] Size of data buffer (in bytes)
868  */
869
870 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
871                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
872 {
873     DWORD ret, len;
874     struct enum_key_value_request *req = get_req_buffer();
875
876     TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
877           hkey, index, value, val_count, reserved, type, data, count );
878
879     /* NT only checks count, not val_count */
880     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
881
882     req->hkey = hkey;
883     req->index = index;
884     if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
885
886     len = lstrlenW( req->name ) + 1;
887     if (len > *val_count) return ERROR_MORE_DATA;
888     memcpy( value, req->name, len * sizeof(WCHAR) );
889     *val_count = len - 1;
890
891     if (type) *type = req->type;
892     return copy_data( data, req->data, req->len, count, req->type );
893 }
894
895
896 /******************************************************************************
897  *           RegEnumValueA   [ADVAPI32.141]
898  */
899 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
900                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
901 {
902     DWORD ret, len;
903     struct enum_key_value_request *req = get_req_buffer();
904
905     TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
906           hkey, index, value, val_count, reserved, type, data, count );
907
908     /* NT only checks count, not val_count */
909     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
910
911     req->hkey = hkey;
912     req->index = index;
913     if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
914
915     len = lstrlenW( req->name ) + 1;
916     if (len > *val_count) return ERROR_MORE_DATA;
917     memcpyWtoA( value, req->name, len );
918     *val_count = len - 1;
919
920     if (type) *type = req->type;
921     return copy_data_WtoA( data, req->data, req->len, count, req->type );
922 }
923
924
925
926 /******************************************************************************
927  *           RegDeleteValueW   [ADVAPI32.136]
928  *
929  * PARAMS
930  *    hkey   [I] handle to key
931  *    name   [I] name of value to delete
932  *
933  * RETURNS
934  *    error status
935  */
936 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
937 {
938     DWORD ret;
939     struct delete_key_value_request *req = get_req_buffer();
940
941     TRACE( "(0x%x,%s)\n", hkey, debugstr_w(name) );
942
943     req->hkey = hkey;
944     if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
945     return reg_server_call( REQ_DELETE_KEY_VALUE );
946 }
947
948
949 /******************************************************************************
950  *           RegDeleteValueA   [ADVAPI32.135]
951  */
952 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
953 {
954     DWORD ret;
955     struct delete_key_value_request *req = get_req_buffer();
956
957     TRACE( "(0x%x,%s)\n", hkey, debugstr_a(name) );
958
959     req->hkey = hkey;
960     if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
961     return reg_server_call( REQ_DELETE_KEY_VALUE );
962 }
963
964
965 /******************************************************************************
966  *           RegLoadKeyW   [ADVAPI32.185]
967  *
968  * PARAMS
969  *    hkey      [I] Handle of open key
970  *    subkey    [I] Address of name of subkey
971  *    filename  [I] Address of filename for registry information
972  */
973 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
974 {
975     struct load_registry_request *req = get_req_buffer();
976     HANDLE file;
977     DWORD ret, err = GetLastError();
978
979     TRACE( "(%x,%s,%s)\n", hkey, debugstr_w(subkey), debugstr_w(filename) );
980
981     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
982     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
983
984     if ((file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
985                              FILE_ATTRIBUTE_NORMAL, -1 )) == INVALID_HANDLE_VALUE)
986     {
987         ret = GetLastError();
988         goto done;
989     }
990     req->hkey  = hkey;
991     req->file  = file;
992     if ((ret = copy_nameW( req->name, subkey )) != ERROR_SUCCESS) goto done;
993     ret = reg_server_call( REQ_LOAD_REGISTRY );
994     CloseHandle( file );
995
996  done:
997     SetLastError( err );  /* restore the last error code */
998     return ret;
999 }
1000
1001
1002 /******************************************************************************
1003  *           RegLoadKeyA   [ADVAPI32.184]
1004  */
1005 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1006 {
1007     struct load_registry_request *req = get_req_buffer();
1008     HANDLE file;
1009     DWORD ret, err = GetLastError();
1010
1011     TRACE( "(%x,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
1012
1013     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1014     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1015
1016     if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1017                              FILE_ATTRIBUTE_NORMAL, -1 )) == INVALID_HANDLE_VALUE)
1018     {
1019         ret = GetLastError();
1020         goto done;
1021     }
1022     req->hkey  = hkey;
1023     req->file  = file;
1024     if ((ret = copy_nameAtoW( req->name, subkey )) != ERROR_SUCCESS) goto done;
1025     ret = reg_server_call( REQ_LOAD_REGISTRY );
1026     CloseHandle( file );
1027
1028  done:
1029     SetLastError( err );  /* restore the last error code */
1030     return ret;
1031 }
1032
1033
1034 /******************************************************************************
1035  *           RegSaveKeyA   [ADVAPI32.165]
1036  *
1037  * PARAMS
1038  *    hkey   [I] Handle of key where save begins
1039  *    lpFile [I] Address of filename to save to
1040  *    sa     [I] Address of security structure
1041  */
1042 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
1043 {
1044     struct save_registry_request *req = get_req_buffer();
1045     char buffer[1024];
1046     int count = 0;
1047     LPSTR name;
1048     DWORD ret, err;
1049     HFILE handle;
1050
1051     TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa );
1052
1053     if (!file || !*file) return ERROR_INVALID_PARAMETER;
1054
1055     err = GetLastError();
1056     GetFullPathNameA( file, sizeof(buffer), buffer, &name );
1057     for (;;)
1058     {
1059         sprintf( name, "reg%04x.tmp", count++ );
1060         handle = CreateFileA( buffer, GENERIC_WRITE, 0, NULL,
1061                             CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1 );
1062         if (handle != INVALID_HANDLE_VALUE) break;
1063         if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
1064     }
1065
1066     req->hkey = hkey;
1067     req->file = handle;
1068     ret = reg_server_call( REQ_SAVE_REGISTRY );
1069     CloseHandle( handle );
1070     if (!ret)
1071     {
1072         if (!MoveFileExA( buffer, file, MOVEFILE_REPLACE_EXISTING ))
1073         {
1074             ERR( "Failed to move %s to %s\n", buffer, file );
1075             ret = GetLastError();
1076         }
1077     }
1078     if (ret) DeleteFileA( buffer );
1079
1080 done:
1081     SetLastError( err );  /* restore last error code */
1082     return ret;
1083 }
1084
1085
1086 /******************************************************************************
1087  *           RegSaveKeyW   [ADVAPI32.166]
1088  */
1089 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1090 {
1091     LPSTR fileA = HEAP_strdupWtoA( GetProcessHeap(), 0, file );
1092     DWORD ret = RegSaveKeyA( hkey, fileA, sa );
1093     if (fileA) HeapFree( GetProcessHeap(), 0, fileA );
1094     return ret;
1095 }