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