Copy the vsnprintfW implementation from libunicode.so to msvcrt and
[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 <stdarg.h>
31 #include <stdio.h>
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winreg.h"
36 #include "winerror.h"
37 #include "ntstatus.h"
38 #include "wine/unicode.h"
39 #include "wine/server.h"
40 #include "wine/debug.h"
41 #include "winternl.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(reg);
44
45 /* allowed bits for access mask */
46 #define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
47
48 #define HKEY_SPECIAL_ROOT_FIRST   HKEY_CLASSES_ROOT
49 #define HKEY_SPECIAL_ROOT_LAST    HKEY_DYN_DATA
50 #define NB_SPECIAL_ROOT_KEYS      ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
51
52 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
53
54 static const WCHAR name_CLASSES_ROOT[] =
55     {'M','a','c','h','i','n','e','\\',
56      'S','o','f','t','w','a','r','e','\\',
57      'C','l','a','s','s','e','s',0};
58 static const WCHAR name_LOCAL_MACHINE[] =
59     {'M','a','c','h','i','n','e',0};
60 static const WCHAR name_USERS[] =
61     {'U','s','e','r',0};
62 static const WCHAR name_PERFORMANCE_DATA[] =
63     {'P','e','r','f','D','a','t','a',0};
64 static const WCHAR name_CURRENT_CONFIG[] =
65     {'M','a','c','h','i','n','e','\\',
66      'S','y','s','t','e','m','\\',
67      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
68      'H','a','r','d','w','a','r','e','P','r','o','f','i','l','e','s','\\',
69      'C','u','r','r','e','n','t',0};
70 static const WCHAR name_DYN_DATA[] =
71     {'D','y','n','D','a','t','a',0};
72
73 #define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
74 static UNICODE_STRING root_key_names[NB_SPECIAL_ROOT_KEYS] =
75 {
76     DECL_STR(CLASSES_ROOT),
77     { 0, 0, NULL },         /* HKEY_CURRENT_USER is determined dynamically */
78     DECL_STR(LOCAL_MACHINE),
79     DECL_STR(USERS),
80     DECL_STR(PERFORMANCE_DATA),
81     DECL_STR(CURRENT_CONFIG),
82     DECL_STR(DYN_DATA)
83 };
84 #undef DECL_STR
85
86
87 /* check if value type needs string conversion (Ansi<->Unicode) */
88 inline static int is_string( DWORD type )
89 {
90     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
91 }
92
93 /* check if current version is NT or Win95 */
94 inline static int is_version_nt(void)
95 {
96     return !(GetVersion() & 0x80000000);
97 }
98
99 /* create one of the HKEY_* special root keys */
100 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
101 {
102     HKEY ret = 0;
103     int idx = (UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST;
104
105     if (hkey == HKEY_CURRENT_USER)
106     {
107         if (RtlOpenCurrentUser( access, &hkey )) return 0;
108         TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
109     }
110     else
111     {
112         OBJECT_ATTRIBUTES attr;
113
114         attr.Length = sizeof(attr);
115         attr.RootDirectory = 0;
116         attr.ObjectName = &root_key_names[idx];
117         attr.Attributes = 0;
118         attr.SecurityDescriptor = NULL;
119         attr.SecurityQualityOfService = NULL;
120         if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
121         TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
122     }
123
124     if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
125         ret = hkey;
126     else
127         NtClose( hkey );  /* somebody beat us to it */
128     return ret;
129 }
130
131 /* map the hkey from special root to normal key if necessary */
132 inline static HKEY get_special_root_hkey( HKEY hkey )
133 {
134     HKEY ret = hkey;
135
136     if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
137     {
138         if (!(ret = special_root_keys[(UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST]))
139             ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
140     }
141     return ret;
142 }
143
144
145 /******************************************************************************
146  *           RegCreateKeyExW   [ADVAPI32.@]
147  *
148  * See RegCreateKeyExA.
149  */
150 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPCWSTR class,
151                               DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
152                               PHKEY retkey, LPDWORD dispos )
153 {
154     OBJECT_ATTRIBUTES attr;
155     UNICODE_STRING nameW, classW;
156
157     if (reserved) return ERROR_INVALID_PARAMETER;
158     if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
159     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
160
161     attr.Length = sizeof(attr);
162     attr.RootDirectory = hkey;
163     attr.ObjectName = &nameW;
164     attr.Attributes = 0;
165     attr.SecurityDescriptor = NULL;
166     attr.SecurityQualityOfService = NULL;
167     RtlInitUnicodeString( &nameW, name );
168     RtlInitUnicodeString( &classW, class );
169
170     return RtlNtStatusToDosError( NtCreateKey( retkey, access, &attr, 0,
171                                                &classW, options, dispos ) );
172 }
173
174
175 /******************************************************************************
176  *           RegCreateKeyExA   [ADVAPI32.@]
177  *
178  * Open a registry key, creating it if it doesn't exist.
179  *
180  * PARAMS
181  *    hkey       [I] Handle of the parent registry key
182  *    name       [I] Name of the new key to open or create
183  *    reserved   [I] Reserved, pass 0
184  *    class      [I] The object type of the new key
185  *    options    [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
186  *    access     [I] Access level desired
187  *    sa         [I] Security attributes for the key
188  *    retkey     [O] Destination for the resulting handle
189  *    dispos     [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
190  *
191  * RETURNS
192  *    Success: ERROR_SUCCESS.
193  *    Failure: A standard Win32 error code. retkey remains untouched.
194  *
195  * FIXME
196  *   MAXIMUM_ALLOWED in access mask not supported by server
197  */
198 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPCSTR class,
199                               DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
200                               PHKEY retkey, LPDWORD dispos )
201 {
202     OBJECT_ATTRIBUTES attr;
203     UNICODE_STRING classW;
204     ANSI_STRING nameA, classA;
205     NTSTATUS status;
206
207     if (reserved) return ERROR_INVALID_PARAMETER;
208     if (!is_version_nt()) access = KEY_ALL_ACCESS;  /* Win95 ignores the access mask */
209     else if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
210     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
211
212     attr.Length = sizeof(attr);
213     attr.RootDirectory = hkey;
214     attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
215     attr.Attributes = 0;
216     attr.SecurityDescriptor = NULL;
217     attr.SecurityQualityOfService = NULL;
218     RtlInitAnsiString( &nameA, name );
219     RtlInitAnsiString( &classA, class );
220
221     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
222                                                  &nameA, FALSE )))
223     {
224         if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
225         {
226             status = NtCreateKey( retkey, access, &attr, 0, &classW, options, dispos );
227             RtlFreeUnicodeString( &classW );
228         }
229     }
230     return RtlNtStatusToDosError( status );
231 }
232
233
234 /******************************************************************************
235  *           RegCreateKeyW   [ADVAPI32.@]
236  */
237 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
238 {
239     /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
240     /* but at least my version of NT (4.0 SP5) doesn't do this.  -- AJ */
241     return RegCreateKeyExW( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
242                             KEY_ALL_ACCESS, NULL, retkey, NULL );
243 }
244
245
246 /******************************************************************************
247  *           RegCreateKeyA   [ADVAPI32.@]
248  */
249 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
250 {
251     return RegCreateKeyExA( hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
252                             KEY_ALL_ACCESS, NULL, retkey, NULL );
253 }
254
255
256
257 /******************************************************************************
258  *           RegOpenKeyExW   [ADVAPI32.@]
259  *
260  * See RegOpenKeyExA.
261  */
262 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
263 {
264     OBJECT_ATTRIBUTES attr;
265     UNICODE_STRING nameW;
266
267     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
268
269     attr.Length = sizeof(attr);
270     attr.RootDirectory = hkey;
271     attr.ObjectName = &nameW;
272     attr.Attributes = 0;
273     attr.SecurityDescriptor = NULL;
274     attr.SecurityQualityOfService = NULL;
275     RtlInitUnicodeString( &nameW, name );
276     return RtlNtStatusToDosError( NtOpenKey( retkey, access, &attr ) );
277 }
278
279
280 /******************************************************************************
281  *           RegOpenKeyExA   [ADVAPI32.@]
282  *
283  * Open a registry key.
284  *
285  * PARAMS
286  *    hkey       [I] Handle of open key
287  *    name       [I] Name of subkey to open
288  *    reserved   [I] Reserved - must be zero
289  *    access     [I] Security access mask
290  *    retkey     [O] Handle to open key
291  *
292  * RETURNS
293  *    Success: ERROR_SUCCESS
294  *    Failure: A standard Win32 error code. retkey is set to 0.
295  *
296  * NOTES
297  *  - Unlike RegCreateKeyExA(), this function will not create the key if it
298  *    does not exist.
299  */
300 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
301 {
302     OBJECT_ATTRIBUTES attr;
303     STRING nameA;
304     NTSTATUS status;
305
306     if (!is_version_nt()) access = KEY_ALL_ACCESS;  /* Win95 ignores the access mask */
307
308     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
309
310     attr.Length = sizeof(attr);
311     attr.RootDirectory = hkey;
312     attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
313     attr.Attributes = 0;
314     attr.SecurityDescriptor = NULL;
315     attr.SecurityQualityOfService = NULL;
316
317     RtlInitAnsiString( &nameA, name );
318     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
319                                                  &nameA, FALSE )))
320     {
321         status = NtOpenKey( retkey, access, &attr );
322     }
323     return RtlNtStatusToDosError( status );
324 }
325
326
327 /******************************************************************************
328  *           RegOpenKeyW   [ADVAPI32.@]
329  *
330  * See RegOpenKeyA.
331  */
332 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
333 {
334     return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
335 }
336
337
338 /******************************************************************************
339  *           RegOpenKeyA   [ADVAPI32.@]
340  *           
341  * Open a registry key.
342  *
343  * PARAMS
344  *    hkey    [I] Handle of parent key to open the new key under
345  *    name    [I] Name of the key under hkey to open
346  *    retkey  [O] Destination for the resulting Handle
347  *
348  * RETURNS
349  *    Success: ERROR_SUCCESS
350  *    Failure: A standard Win32 error code. retkey is set to 0.
351  */
352 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
353 {
354     return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
355 }
356
357
358 /******************************************************************************
359  *           RegOpenCurrentUser   [ADVAPI32.@]
360  * FIXME: This function is supposed to retrieve a handle to the
361  * HKEY_CURRENT_USER for the user the current thread is impersonating.
362  * Since Wine does not currently allow threads to impersonate other users,
363  * this stub should work fine.
364  */
365 DWORD WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
366 {
367     return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
368 }
369
370
371
372 /******************************************************************************
373  *           RegEnumKeyExW   [ADVAPI32.@]
374  *
375  * PARAMS
376  *    hkey         [I] Handle to key to enumerate
377  *    index        [I] Index of subkey to enumerate
378  *    name         [O] Buffer for subkey name
379  *    name_len     [O] Size of subkey buffer
380  *    reserved     [I] Reserved
381  *    class        [O] Buffer for class string
382  *    class_len    [O] Size of class buffer
383  *    ft           [O] Time key last written to
384  */
385 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
386                             LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
387 {
388     NTSTATUS status;
389     char buffer[256], *buf_ptr = buffer;
390     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
391     DWORD total_size;
392
393     TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
394            name_len ? *name_len : -1, reserved, class, class_len, ft );
395
396     if (reserved) return ERROR_INVALID_PARAMETER;
397     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
398
399     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
400                              buffer, sizeof(buffer), &total_size );
401
402     while (status == STATUS_BUFFER_OVERFLOW)
403     {
404         /* retry with a dynamically allocated buffer */
405         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
406         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
407             return ERROR_NOT_ENOUGH_MEMORY;
408         info = (KEY_NODE_INFORMATION *)buf_ptr;
409         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
410                                  buf_ptr, total_size, &total_size );
411     }
412
413     if (!status)
414     {
415         DWORD len = info->NameLength / sizeof(WCHAR);
416         DWORD cls_len = info->ClassLength / sizeof(WCHAR);
417
418         if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
419
420         if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
421             status = STATUS_BUFFER_OVERFLOW;
422         else
423         {
424             *name_len = len;
425             memcpy( name, info->Name, info->NameLength );
426             name[len] = 0;
427             if (class_len)
428             {
429                 *class_len = cls_len;
430                 if (class)
431                 {
432                     memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
433                     class[cls_len] = 0;
434                 }
435             }
436         }
437     }
438
439     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
440     return RtlNtStatusToDosError( status );
441 }
442
443
444 /******************************************************************************
445  *           RegEnumKeyExA   [ADVAPI32.@]
446  */
447 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
448                             LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
449 {
450     NTSTATUS status;
451     char buffer[256], *buf_ptr = buffer;
452     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
453     DWORD total_size;
454
455     TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
456            name_len ? *name_len : -1, reserved, class, class_len, ft );
457
458     if (reserved) return ERROR_INVALID_PARAMETER;
459     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
460
461     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
462                              buffer, sizeof(buffer), &total_size );
463
464     while (status == STATUS_BUFFER_OVERFLOW)
465     {
466         /* retry with a dynamically allocated buffer */
467         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
468         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
469             return ERROR_NOT_ENOUGH_MEMORY;
470         info = (KEY_NODE_INFORMATION *)buf_ptr;
471         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
472                                  buf_ptr, total_size, &total_size );
473     }
474
475     if (!status)
476     {
477         DWORD len, cls_len;
478
479         RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
480         RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
481                                    info->ClassLength );
482         if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
483
484         if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
485             status = STATUS_BUFFER_OVERFLOW;
486         else
487         {
488             *name_len = len;
489             RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
490             name[len] = 0;
491             if (class_len)
492             {
493                 *class_len = cls_len;
494                 if (class)
495                 {
496                     RtlUnicodeToMultiByteN( class, cls_len, NULL,
497                                             (WCHAR *)(buf_ptr + info->ClassOffset),
498                                             info->ClassLength );
499                     class[cls_len] = 0;
500                 }
501             }
502         }
503     }
504
505     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
506     return RtlNtStatusToDosError( status );
507 }
508
509
510 /******************************************************************************
511  *           RegEnumKeyW   [ADVAPI32.@]
512  */
513 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
514 {
515     return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
516 }
517
518
519 /******************************************************************************
520  *           RegEnumKeyA   [ADVAPI32.@]
521  */
522 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
523 {
524     return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
525 }
526
527
528 /******************************************************************************
529  *           RegQueryInfoKeyW   [ADVAPI32.@]
530  *
531  * PARAMS
532  *    hkey       [I] Handle to key to query
533  *    class      [O] Buffer for class string
534  *    class_len  [O] Size of class string buffer
535  *    reserved   [I] Reserved
536  *    subkeys    [O] Buffer for number of subkeys
537  *    max_subkey [O] Buffer for longest subkey name length
538  *    max_class  [O] Buffer for longest class string length
539  *    values     [O] Buffer for number of value entries
540  *    max_value  [O] Buffer for longest value name length
541  *    max_data   [O] Buffer for longest value data length
542  *    security   [O] Buffer for security descriptor length
543  *    modif      [O] Modification time
544  *
545  * - win95 allows class to be valid and class_len to be NULL
546  * - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
547  * - both allow class to be NULL and class_len to be NULL
548  * (it's hard to test validity, so test !NULL instead)
549  */
550 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
551                                LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
552                                LPDWORD values, LPDWORD max_value, LPDWORD max_data,
553                                LPDWORD security, FILETIME *modif )
554 {
555     NTSTATUS status;
556     char buffer[256], *buf_ptr = buffer;
557     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
558     DWORD total_size;
559
560     TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
561            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
562
563     if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
564     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
565
566     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
567     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
568
569     if (class)
570     {
571         /* retry with a dynamically allocated buffer */
572         while (status == STATUS_BUFFER_OVERFLOW)
573         {
574             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
575             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
576                 return ERROR_NOT_ENOUGH_MEMORY;
577             info = (KEY_FULL_INFORMATION *)buf_ptr;
578             status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
579         }
580
581         if (status) goto done;
582
583         if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
584         {
585             status = STATUS_BUFFER_OVERFLOW;
586         }
587         else
588         {
589             memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
590             class[info->ClassLength/sizeof(WCHAR)] = 0;
591         }
592     }
593     else status = STATUS_SUCCESS;
594
595     if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
596     if (subkeys) *subkeys = info->SubKeys;
597     if (max_subkey) *max_subkey = info->MaxNameLen;
598     if (max_class) *max_class = info->MaxClassLen;
599     if (values) *values = info->Values;
600     if (max_value) *max_value = info->MaxValueNameLen;
601     if (max_data) *max_data = info->MaxValueDataLen;
602     if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
603
604  done:
605     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
606     return RtlNtStatusToDosError( status );
607 }
608
609
610 /******************************************************************************
611  *           RegQueryMultipleValuesA   [ADVAPI32.@]
612  */
613 DWORD WINAPI RegQueryMultipleValuesA(HKEY hkey, PVALENTA val_list, DWORD num_vals,
614                                      LPSTR lpValueBuf, LPDWORD ldwTotsize)
615 {
616     int i;
617     DWORD maxBytes = *ldwTotsize;
618     HRESULT status;
619     LPSTR bufptr = lpValueBuf;
620     *ldwTotsize = 0;
621
622     TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
623
624     for(i=0; i < num_vals; ++i)
625     {
626
627         val_list[i].ve_valuelen=0;
628         status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
629         if(status != ERROR_SUCCESS)
630         {
631             return status;
632         }
633
634         if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
635         {
636             status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
637                                       bufptr, &val_list[i].ve_valuelen);
638             if(status != ERROR_SUCCESS)
639             {
640                 return status;
641             }
642
643             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
644
645             bufptr += val_list[i].ve_valuelen;
646         }
647
648         *ldwTotsize += val_list[i].ve_valuelen;
649     }
650     return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
651 }
652
653
654 /******************************************************************************
655  *           RegQueryMultipleValuesW   [ADVAPI32.@]
656  */
657 DWORD WINAPI RegQueryMultipleValuesW(HKEY hkey, PVALENTW val_list, DWORD num_vals,
658                                      LPWSTR lpValueBuf, LPDWORD ldwTotsize)
659 {
660     int i;
661     DWORD maxBytes = *ldwTotsize;
662     HRESULT status;
663     LPSTR bufptr = (LPSTR)lpValueBuf;
664     *ldwTotsize = 0;
665
666     TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
667
668     for(i=0; i < num_vals; ++i)
669     {
670         val_list[i].ve_valuelen=0;
671         status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
672         if(status != ERROR_SUCCESS)
673         {
674             return status;
675         }
676
677         if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
678         {
679             status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
680                                       bufptr, &val_list[i].ve_valuelen);
681             if(status != ERROR_SUCCESS)
682             {
683                 return status;
684             }
685
686             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
687
688             bufptr += val_list[i].ve_valuelen;
689         }
690
691         *ldwTotsize += val_list[i].ve_valuelen;
692     }
693     return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
694 }
695
696 /******************************************************************************
697  *           RegQueryInfoKeyA   [ADVAPI32.@]
698  */
699 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
700                                LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
701                                LPDWORD values, LPDWORD max_value, LPDWORD max_data,
702                                LPDWORD security, FILETIME *modif )
703 {
704     NTSTATUS status;
705     char buffer[256], *buf_ptr = buffer;
706     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
707     DWORD total_size, len;
708
709     TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
710            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
711
712     if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
713     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
714
715     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
716     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
717
718     if (class || class_len)
719     {
720         /* retry with a dynamically allocated buffer */
721         while (status == STATUS_BUFFER_OVERFLOW)
722         {
723             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
724             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
725                 return ERROR_NOT_ENOUGH_MEMORY;
726             info = (KEY_FULL_INFORMATION *)buf_ptr;
727             status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
728         }
729
730         if (status) goto done;
731
732         RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
733         if (class_len)
734         {
735             if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
736             *class_len = len;
737         }
738         if (class && !status)
739         {
740             RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
741                                     info->ClassLength );
742             class[len] = 0;
743         }
744     }
745     else status = STATUS_SUCCESS;
746
747     if (subkeys) *subkeys = info->SubKeys;
748     if (max_subkey) *max_subkey = info->MaxNameLen;
749     if (max_class) *max_class = info->MaxClassLen;
750     if (values) *values = info->Values;
751     if (max_value) *max_value = info->MaxValueNameLen;
752     if (max_data) *max_data = info->MaxValueDataLen;
753     if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
754
755  done:
756     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
757     return RtlNtStatusToDosError( status );
758 }
759
760
761 /******************************************************************************
762  *           RegCloseKey   [ADVAPI32.@]
763  *
764  * Close an open registry key.
765  *
766  * PARAMS
767  *    hkey [I] Handle of key to close
768  *
769  * RETURNS
770  *    Success: ERROR_SUCCESS
771  *    Failure: Error code
772  */
773 DWORD WINAPI RegCloseKey( HKEY hkey )
774 {
775     if (!hkey || hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
776     return RtlNtStatusToDosError( NtClose( hkey ) );
777 }
778
779
780 /******************************************************************************
781  *           RegDeleteKeyW   [ADVAPI32.@]
782  *
783  * See RegDeleteKeyA.
784  */
785 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
786 {
787     DWORD ret;
788     HKEY tmp;
789
790     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
791
792     if (!name || !*name)
793     {
794         ret = RtlNtStatusToDosError( NtDeleteKey( hkey ) );
795     }
796     else if (!(ret = RegOpenKeyExW( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
797     {
798         if (!is_version_nt()) /* win95 does recursive key deletes */
799         {
800             WCHAR name[MAX_PATH];
801
802             while(!RegEnumKeyW(tmp, 0, name, sizeof(name)))
803             {
804                 if(RegDeleteKeyW(tmp, name))  /* recurse */
805                     break;
806             }
807         }
808         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
809         RegCloseKey( tmp );
810     }
811     TRACE("%s ret=%08lx\n", debugstr_w(name), ret);
812     return ret;
813 }
814
815
816 /******************************************************************************
817  *           RegDeleteKeyA   [ADVAPI32.@]
818  *
819  * Delete a registry key.
820  *
821  * PARAMS
822  *    hkey   [I] Handle to parent key containing the key to delete
823  *    name   [I] Name of the key user hkey to delete
824  *
825  * RETURNS
826  *    Success: ERROR_SUCCESS
827  *    Failure: Error code
828  */
829 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
830 {
831     DWORD ret;
832     HKEY tmp;
833
834     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
835
836     if (!name || !*name)
837     {
838         ret = RtlNtStatusToDosError( NtDeleteKey( hkey ) );
839     }
840     else if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
841     {
842         if (!is_version_nt()) /* win95 does recursive key deletes */
843         {
844             CHAR name[MAX_PATH];
845
846             while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
847             {
848                 if(RegDeleteKeyA(tmp, name))  /* recurse */
849                     break;
850             }
851         }
852         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
853         RegCloseKey( tmp );
854     }
855     TRACE("%s ret=%08lx\n", debugstr_a(name), ret);
856     return ret;
857 }
858
859
860
861 /******************************************************************************
862  *           RegSetValueExW   [ADVAPI32.@]
863  *
864  * Set the data and contents of a registry value.
865  *
866  * PARAMS
867  *    hkey       [I] Handle of key to set value for
868  *    name       [I] Name of value to set
869  *    reserved   [I] Reserved, must be zero
870  *    type       [I] Type of the value being set
871  *    data       [I] The new contents of the value to set
872  *    count      [I] Size of data
873  *
874  * RETURNS
875  *    Success: ERROR_SUCCESS
876  *    Failure: Error code
877  *
878  * NOTES
879  *   win95 does not care about count for REG_SZ and finds out the len by itself (js)
880  *   NT does definitely care (aj)
881  */
882 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
883                              DWORD type, CONST BYTE *data, DWORD count )
884 {
885     UNICODE_STRING nameW;
886
887     if (!is_version_nt())  /* win95 */
888     {
889         if (type == REG_SZ) count = (strlenW( (WCHAR *)data ) + 1) * sizeof(WCHAR);
890     }
891     else if (count && is_string(type))
892     {
893         LPCWSTR str = (LPCWSTR)data;
894         /* if user forgot to count terminating null, add it (yes NT does this) */
895         if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
896             count += sizeof(WCHAR);
897     }
898     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
899
900     RtlInitUnicodeString( &nameW, name );
901     return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
902 }
903
904
905 /******************************************************************************
906  *           RegSetValueExA   [ADVAPI32.@]
907  */
908 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
909                              CONST BYTE *data, DWORD count )
910 {
911     ANSI_STRING nameA;
912     WCHAR *dataW = NULL;
913     NTSTATUS status;
914
915     if (!is_version_nt())  /* win95 */
916     {
917         if (type == REG_SZ) count = strlen(data) + 1;
918     }
919     else if (count && is_string(type))
920     {
921         /* if user forgot to count terminating null, add it (yes NT does this) */
922         if (data[count-1] && !data[count]) count++;
923     }
924
925     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
926
927     if (is_string( type )) /* need to convert to Unicode */
928     {
929         DWORD lenW;
930         RtlMultiByteToUnicodeSize( &lenW, data, count );
931         if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
932         RtlMultiByteToUnicodeN( dataW, lenW, NULL, data, count );
933         count = lenW;
934         data = (BYTE *)dataW;
935     }
936
937     RtlInitAnsiString( &nameA, name );
938     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
939                                                  &nameA, FALSE )))
940     {
941         status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
942     }
943     if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
944     return RtlNtStatusToDosError( status );
945 }
946
947
948 /******************************************************************************
949  *           RegSetValueW   [ADVAPI32.@]
950  */
951 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
952 {
953     HKEY subkey = hkey;
954     DWORD ret;
955
956     TRACE("(%p,%s,%ld,%s,%ld)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
957
958     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
959
960     if (name && name[0])  /* need to create the subkey */
961     {
962         if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
963     }
964
965     ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (LPBYTE)data,
966                           (strlenW( data ) + 1) * sizeof(WCHAR) );
967     if (subkey != hkey) RegCloseKey( subkey );
968     return ret;
969 }
970
971
972 /******************************************************************************
973  *           RegSetValueA   [ADVAPI32.@]
974  */
975 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
976 {
977     HKEY subkey = hkey;
978     DWORD ret;
979
980     TRACE("(%p,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
981
982     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
983
984     if (name && name[0])  /* need to create the subkey */
985     {
986         if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
987     }
988     ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
989     if (subkey != hkey) RegCloseKey( subkey );
990     return ret;
991 }
992
993
994
995 /******************************************************************************
996  *           RegQueryValueExW   [ADVAPI32.@]
997  *
998  * See RegQueryValueExA.
999  */
1000 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1001                                LPBYTE data, LPDWORD count )
1002 {
1003     NTSTATUS status;
1004     UNICODE_STRING name_str;
1005     DWORD total_size;
1006     char buffer[256], *buf_ptr = buffer;
1007     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1008     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1009
1010     TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1011           hkey, debugstr_w(name), reserved, type, data, count,
1012           (count && data) ? *count : 0 );
1013
1014     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1015     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1016
1017     RtlInitUnicodeString( &name_str, name );
1018
1019     if (data) total_size = min( sizeof(buffer), *count + info_size );
1020     else total_size = info_size;
1021
1022     status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1023                               buffer, total_size, &total_size );
1024     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1025
1026     if (data)
1027     {
1028         /* retry with a dynamically allocated buffer */
1029         while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1030         {
1031             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1032             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1033                 return ERROR_NOT_ENOUGH_MEMORY;
1034             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1035             status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1036                                       buf_ptr, total_size, &total_size );
1037         }
1038
1039         if (!status)
1040         {
1041             memcpy( data, buf_ptr + info_size, total_size - info_size );
1042             /* if the type is REG_SZ and data is not 0-terminated
1043              * and there is enough space in the buffer NT appends a \0 */
1044             if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1045             {
1046                 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1047                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1048             }
1049         }
1050         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1051     }
1052     else status = STATUS_SUCCESS;
1053
1054     if (type) *type = info->Type;
1055     if (count) *count = total_size - info_size;
1056
1057  done:
1058     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1059     return RtlNtStatusToDosError(status);
1060 }
1061
1062
1063 /******************************************************************************
1064  *           RegQueryValueExA   [ADVAPI32.@]
1065  *
1066  * Get the type and contents of a specified value under with a key.
1067  *
1068  * PARAMS
1069  *    hkey      [I]   Handle of the key to query
1070  *    name      [I]   Name of value under hkey to query
1071  *    reserved  [I]   Reserved - must be NULL
1072  *    type      [O]   Destination for the value type, or NULL if not required
1073  *    data      [O]   Destination for the values contents, or NULL if not required
1074  *    count     [I/O] Size of data, updated with the number of bytes returned
1075  *
1076  * RETURNS
1077  *  Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1078  *  Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1079  *           ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1080  *           ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1081  *                     
1082  * NOTES
1083  *   MSDN states that if data is too small it is partially filled. In reality 
1084  *   it remains untouched.
1085  */
1086 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1087                                LPBYTE data, LPDWORD count )
1088 {
1089     NTSTATUS status;
1090     ANSI_STRING nameA;
1091     DWORD total_size;
1092     char buffer[256], *buf_ptr = buffer;
1093     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1094     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1095
1096     TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1097           hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1098
1099     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1100     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1101
1102     RtlInitAnsiString( &nameA, name );
1103     if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1104                                                 &nameA, FALSE )))
1105         return RtlNtStatusToDosError(status);
1106
1107     status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1108                               KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
1109     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1110
1111     /* we need to fetch the contents for a string type even if not requested,
1112      * because we need to compute the length of the ASCII string. */
1113     if (data || is_string(info->Type))
1114     {
1115         /* retry with a dynamically allocated buffer */
1116         while (status == STATUS_BUFFER_OVERFLOW)
1117         {
1118             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1119             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1120             {
1121                 status = STATUS_NO_MEMORY;
1122                 goto done;
1123             }
1124             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1125             status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1126                                     KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1127         }
1128
1129         if (status) goto done;
1130
1131         if (is_string(info->Type))
1132         {
1133             DWORD len;
1134
1135             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1136                                        total_size - info_size );
1137             if (data && len)
1138             {
1139                 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1140                 else
1141                 {
1142                     RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1143                                             total_size - info_size );
1144                     /* if the type is REG_SZ and data is not 0-terminated
1145                      * and there is enough space in the buffer NT appends a \0 */
1146                     if (len < *count && data[len-1]) data[len] = 0;
1147                 }
1148             }
1149             total_size = len + info_size;
1150         }
1151         else if (data)
1152         {
1153             if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
1154             else memcpy( data, buf_ptr + info_size, total_size - info_size );
1155         }
1156     }
1157     else status = STATUS_SUCCESS;
1158
1159     if (type) *type = info->Type;
1160     if (count) *count = total_size - info_size;
1161
1162  done:
1163     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1164     return RtlNtStatusToDosError(status);
1165 }
1166
1167
1168 /******************************************************************************
1169  *           RegQueryValueW   [ADVAPI32.@]
1170  */
1171 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1172 {
1173     DWORD ret;
1174     HKEY subkey = hkey;
1175
1176     TRACE("(%p,%s,%p,%ld)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1177
1178     if (name && name[0])
1179     {
1180         if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1181     }
1182     ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
1183     if (subkey != hkey) RegCloseKey( subkey );
1184     if (ret == ERROR_FILE_NOT_FOUND)
1185     {
1186         /* return empty string if default value not found */
1187         if (data) *data = 0;
1188         if (count) *count = 1;
1189         ret = ERROR_SUCCESS;
1190     }
1191     return ret;
1192 }
1193
1194
1195 /******************************************************************************
1196  *           RegQueryValueA   [ADVAPI32.@]
1197  */
1198 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1199 {
1200     DWORD ret;
1201     HKEY subkey = hkey;
1202
1203     TRACE("(%p,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1204
1205     if (name && name[0])
1206     {
1207         if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1208     }
1209     ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
1210     if (subkey != hkey) RegCloseKey( subkey );
1211     if (ret == ERROR_FILE_NOT_FOUND)
1212     {
1213         /* return empty string if default value not found */
1214         if (data) *data = 0;
1215         if (count) *count = 1;
1216         ret = ERROR_SUCCESS;
1217     }
1218     return ret;
1219 }
1220
1221
1222 /******************************************************************************
1223  *           RegEnumValueW   [ADVAPI32.@]
1224  *
1225  * PARAMS
1226  *    hkey       [I] Handle to key to query
1227  *    index      [I] Index of value to query
1228  *    value      [O] Value string
1229  *    val_count  [I/O] Size of value buffer (in wchars)
1230  *    reserved   [I] Reserved
1231  *    type       [O] Type code
1232  *    data       [O] Value data
1233  *    count      [I/O] Size of data buffer (in bytes)
1234  */
1235
1236 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1237                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1238 {
1239     NTSTATUS status;
1240     DWORD total_size;
1241     char buffer[256], *buf_ptr = buffer;
1242     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1243     static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1244
1245     TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1246           hkey, index, value, val_count, reserved, type, data, count );
1247
1248     /* NT only checks count, not val_count */
1249     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1250     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1251
1252     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1253     if (data) total_size += *count;
1254     total_size = min( sizeof(buffer), total_size );
1255
1256     status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1257                                   buffer, total_size, &total_size );
1258     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1259
1260     if (value || data)
1261     {
1262         /* retry with a dynamically allocated buffer */
1263         while (status == STATUS_BUFFER_OVERFLOW)
1264         {
1265             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1266             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1267                 return ERROR_NOT_ENOUGH_MEMORY;
1268             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1269             status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1270                                           buf_ptr, total_size, &total_size );
1271         }
1272
1273         if (status) goto done;
1274
1275         if (value)
1276         {
1277             if (info->NameLength/sizeof(WCHAR) >= *val_count)
1278             {
1279                 status = STATUS_BUFFER_OVERFLOW;
1280                 goto overflow;
1281             }
1282             memcpy( value, info->Name, info->NameLength );
1283             *val_count = info->NameLength / sizeof(WCHAR);
1284             value[*val_count] = 0;
1285         }
1286
1287         if (data)
1288         {
1289             if (total_size - info->DataOffset > *count)
1290             {
1291                 status = STATUS_BUFFER_OVERFLOW;
1292                 goto overflow;
1293             }
1294             memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1295             if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1296             {
1297                 /* if the type is REG_SZ and data is not 0-terminated
1298                  * and there is enough space in the buffer NT appends a \0 */
1299                 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1300                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1301             }
1302         }
1303     }
1304     else status = STATUS_SUCCESS;
1305
1306  overflow:
1307     if (type) *type = info->Type;
1308     if (count) *count = info->DataLength;
1309
1310  done:
1311     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1312     return RtlNtStatusToDosError(status);
1313 }
1314
1315
1316 /******************************************************************************
1317  *           RegEnumValueA   [ADVAPI32.@]
1318  */
1319 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1320                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1321 {
1322     NTSTATUS status;
1323     DWORD total_size;
1324     char buffer[256], *buf_ptr = buffer;
1325     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1326     static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1327
1328     TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1329           hkey, index, value, val_count, reserved, type, data, count );
1330
1331     /* NT only checks count, not val_count */
1332     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1333     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1334
1335     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1336     if (data) total_size += *count;
1337     total_size = min( sizeof(buffer), total_size );
1338
1339     status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1340                                   buffer, total_size, &total_size );
1341     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1342
1343     /* we need to fetch the contents for a string type even if not requested,
1344      * because we need to compute the length of the ASCII string. */
1345     if (value || data || is_string(info->Type))
1346     {
1347         /* retry with a dynamically allocated buffer */
1348         while (status == STATUS_BUFFER_OVERFLOW)
1349         {
1350             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1351             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1352                 return ERROR_NOT_ENOUGH_MEMORY;
1353             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1354             status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1355                                           buf_ptr, total_size, &total_size );
1356         }
1357
1358         if (status) goto done;
1359
1360         if (is_string(info->Type))
1361         {
1362             DWORD len;
1363             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1364                                        total_size - info->DataOffset );
1365             if (data && len)
1366             {
1367                 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1368                 else
1369                 {
1370                     RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1371                                             total_size - info->DataOffset );
1372                     /* if the type is REG_SZ and data is not 0-terminated
1373                      * and there is enough space in the buffer NT appends a \0 */
1374                     if (len < *count && data[len-1]) data[len] = 0;
1375                 }
1376             }
1377             info->DataLength = len;
1378         }
1379         else if (data)
1380         {
1381             if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1382             else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1383         }
1384
1385         if (value && !status)
1386         {
1387             DWORD len;
1388
1389             RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1390             if (len >= *val_count)
1391             {
1392                 status = STATUS_BUFFER_OVERFLOW;
1393                 if (*val_count)
1394                 {
1395                     len = *val_count - 1;
1396                     RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1397                     value[len] = 0;
1398                 }
1399             }
1400             else
1401             {
1402                 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1403                 value[len] = 0;
1404                 *val_count = len;
1405             }
1406         }
1407     }
1408     else status = STATUS_SUCCESS;
1409
1410     if (type) *type = info->Type;
1411     if (count) *count = info->DataLength;
1412
1413  done:
1414     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1415     return RtlNtStatusToDosError(status);
1416 }
1417
1418
1419
1420 /******************************************************************************
1421  *           RegDeleteValueW   [ADVAPI32.@]
1422  *
1423  * See RegDeleteValueA.
1424  */
1425 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1426 {
1427     UNICODE_STRING nameW;
1428
1429     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1430
1431     RtlInitUnicodeString( &nameW, name );
1432     return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1433 }
1434
1435
1436 /******************************************************************************
1437  *           RegDeleteValueA   [ADVAPI32.@]
1438  *
1439  * Delete a value from the registry.
1440  *
1441  * PARAMS
1442  *  hkey [I] Registry handle of the key holding the value
1443  *  name [I] Name of the value under hkey to delete
1444  *
1445  * RETURNS
1446  *  Success: 0
1447  *  Failure: A standard Windows error code.
1448  */
1449 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1450 {
1451     STRING nameA;
1452     NTSTATUS status;
1453
1454     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1455
1456     RtlInitAnsiString( &nameA, name );
1457     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1458                                                  &nameA, FALSE )))
1459         status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1460     return RtlNtStatusToDosError( status );
1461 }
1462
1463
1464 /******************************************************************************
1465  *           RegLoadKeyW   [ADVAPI32.@]
1466  *
1467  * PARAMS
1468  *    hkey      [I] Handle of open key
1469  *    subkey    [I] Address of name of subkey
1470  *    filename  [I] Address of filename for registry information
1471  */
1472 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1473 {
1474     HANDLE file;
1475     DWORD ret, len, err = GetLastError();
1476     HKEY shkey;
1477
1478     TRACE( "(%p,%s,%s)\n", hkey, debugstr_w(subkey), debugstr_w(filename) );
1479
1480     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1481     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1482     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1483
1484     len = strlenW( subkey ) * sizeof(WCHAR);
1485     if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
1486
1487     if ((file = CreateFileW( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1488                              FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
1489     {
1490         ret = GetLastError();
1491         goto done;
1492     }
1493
1494     RegCreateKeyW(hkey,subkey,&shkey);
1495
1496     SERVER_START_REQ( load_registry )
1497     {
1498         req->hkey  = shkey;
1499         req->file  = file;
1500         wine_server_add_data( req, subkey, len );
1501         ret = RtlNtStatusToDosError( wine_server_call(req) );
1502     }
1503     SERVER_END_REQ;
1504     CloseHandle( file );
1505     RegCloseKey(shkey);
1506
1507  done:
1508     SetLastError( err );  /* restore the last error code */
1509     return ret;
1510 }
1511
1512
1513 /******************************************************************************
1514  *           RegLoadKeyA   [ADVAPI32.@]
1515  */
1516 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1517 {
1518     WCHAR buffer[MAX_PATH];
1519     HANDLE file;
1520     DWORD ret, len, err = GetLastError();
1521     HKEY shkey;
1522
1523     TRACE( "(%p,%s,%s)\n", hkey, debugstr_a(subkey), debugstr_a(filename) );
1524
1525     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
1526     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
1527     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1528
1529     if (!(len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), buffer, MAX_PATH )))
1530         return ERROR_INVALID_PARAMETER;
1531
1532     if ((file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1533                              FILE_ATTRIBUTE_NORMAL, 0 )) == INVALID_HANDLE_VALUE)
1534     {
1535         ret = GetLastError();
1536         goto done;
1537     }
1538
1539     RegCreateKeyA(hkey,subkey,&shkey);
1540
1541     SERVER_START_REQ( load_registry )
1542     {
1543         req->hkey  = shkey;
1544         req->file  = file;
1545         wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
1546         ret = RtlNtStatusToDosError( wine_server_call(req) );
1547     }
1548     SERVER_END_REQ;
1549     CloseHandle( file );
1550     RegCloseKey(shkey);
1551
1552  done:
1553     SetLastError( err );  /* restore the last error code */
1554     return ret;
1555 }
1556
1557
1558 /******************************************************************************
1559  *           RegSaveKeyW   [ADVAPI32.@]
1560  *
1561  * PARAMS
1562  *    hkey   [I] Handle of key where save begins
1563  *    lpFile [I] Address of filename to save to
1564  *    sa     [I] Address of security structure
1565  */
1566 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1567 {
1568     static const WCHAR format[] =
1569         {'r','e','g','%','0','4','x','.','t','m','p',0};
1570     WCHAR buffer[MAX_PATH];
1571     int count = 0;
1572     LPWSTR nameW;
1573     DWORD ret, err;
1574     HANDLE handle;
1575
1576     TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
1577
1578     if (!file || !*file) return ERROR_INVALID_PARAMETER;
1579     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1580
1581     err = GetLastError();
1582     GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
1583
1584     for (;;)
1585     {
1586         snprintfW( nameW, 16, format, count++ );
1587         handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1588                             CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1589         if (handle != INVALID_HANDLE_VALUE) break;
1590         if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
1591
1592         /* Something gone haywire ? Please report if this happens abnormally */
1593         if (count >= 100)
1594             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", debugstr_w(buffer), count);
1595     }
1596
1597     SERVER_START_REQ( save_registry )
1598     {
1599         req->hkey = hkey;
1600         req->file = handle;
1601         ret = RtlNtStatusToDosError( wine_server_call( req ) );
1602     }
1603     SERVER_END_REQ;
1604
1605     CloseHandle( handle );
1606     if (!ret)
1607     {
1608         if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
1609         {
1610             ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
1611                 debugstr_w(file) );
1612             ret = GetLastError();
1613         }
1614     }
1615     if (ret) DeleteFileW( buffer );
1616
1617 done:
1618     SetLastError( err );  /* restore last error code */
1619     return ret;
1620 }
1621
1622
1623 /******************************************************************************
1624  *           RegSaveKeyA  [ADVAPI32.@]
1625  */
1626 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
1627 {
1628     UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
1629     NTSTATUS status;
1630     STRING fileA;
1631
1632     RtlInitAnsiString(&fileA, file);
1633     if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
1634         return RtlNtStatusToDosError( status );
1635     return RegSaveKeyW(hkey, fileW->Buffer, sa);
1636 }
1637
1638
1639 /******************************************************************************
1640  * RegRestoreKeyW [ADVAPI32.@]
1641  *
1642  * PARAMS
1643  *    hkey    [I] Handle of key where restore begins
1644  *    lpFile  [I] Address of filename containing saved tree
1645  *    dwFlags [I] Optional flags
1646  */
1647 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1648 {
1649     TRACE("(%p,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1650
1651     /* It seems to do this check before the hkey check */
1652     if (!lpFile || !*lpFile)
1653         return ERROR_INVALID_PARAMETER;
1654
1655     FIXME("(%p,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1656
1657     /* Check for file existence */
1658
1659     return ERROR_SUCCESS;
1660 }
1661
1662
1663 /******************************************************************************
1664  * RegRestoreKeyA [ADVAPI32.@]
1665  */
1666 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1667 {
1668     UNICODE_STRING lpFileW;
1669     LONG ret;
1670
1671     RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
1672     ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
1673     RtlFreeUnicodeString( &lpFileW );
1674     return ret;
1675 }
1676
1677
1678 /******************************************************************************
1679  * RegUnLoadKeyW [ADVAPI32.@]
1680  *
1681  * PARAMS
1682  *    hkey     [I] Handle of open key
1683  *    lpSubKey [I] Address of name of subkey to unload
1684  */
1685 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1686 {
1687     DWORD ret;
1688     HKEY shkey;
1689
1690     TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
1691
1692     ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
1693     if( ret )
1694         return ERROR_INVALID_PARAMETER;
1695
1696     SERVER_START_REQ( unload_registry )
1697     {
1698         req->hkey  = shkey;
1699         ret = RtlNtStatusToDosError( wine_server_call(req) );
1700     }
1701     SERVER_END_REQ;
1702     RegCloseKey(shkey);
1703
1704     return ret;
1705 }
1706
1707
1708 /******************************************************************************
1709  * RegUnLoadKeyA [ADVAPI32.@]
1710  */
1711 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1712 {
1713     UNICODE_STRING lpSubKeyW;
1714     LONG ret;
1715
1716     RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
1717     ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
1718     RtlFreeUnicodeString( &lpSubKeyW );
1719     return ret;
1720 }
1721
1722
1723 /******************************************************************************
1724  * RegReplaceKeyW [ADVAPI32.@]
1725  *
1726  * PARAMS
1727  *    hkey      [I] Handle of open key
1728  *    lpSubKey  [I] Address of name of subkey
1729  *    lpNewFile [I] Address of filename for file with new data
1730  *    lpOldFile [I] Address of filename for backup file
1731  */
1732 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1733                               LPCWSTR lpOldFile )
1734 {
1735     FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1736           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1737     return ERROR_SUCCESS;
1738 }
1739
1740
1741 /******************************************************************************
1742  * RegReplaceKeyA [ADVAPI32.@]
1743  */
1744 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1745                               LPCSTR lpOldFile )
1746 {
1747     UNICODE_STRING lpSubKeyW;
1748     UNICODE_STRING lpNewFileW;
1749     UNICODE_STRING lpOldFileW;
1750     LONG ret;
1751
1752     RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
1753     RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
1754     RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
1755     ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
1756     RtlFreeUnicodeString( &lpOldFileW );
1757     RtlFreeUnicodeString( &lpNewFileW );
1758     RtlFreeUnicodeString( &lpSubKeyW );
1759     return ret;
1760 }
1761
1762
1763 /******************************************************************************
1764  * RegSetKeySecurity [ADVAPI32.@]
1765  *
1766  * PARAMS
1767  *    hkey          [I] Open handle of key to set
1768  *    SecurityInfo  [I] Descriptor contents
1769  *    pSecurityDesc [I] Address of descriptor for key
1770  */
1771 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1772                                PSECURITY_DESCRIPTOR pSecurityDesc )
1773 {
1774     TRACE("(%p,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1775
1776     /* It seems to perform this check before the hkey check */
1777     if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1778         (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1779         (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1780         (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1781         /* Param OK */
1782     } else
1783         return ERROR_INVALID_PARAMETER;
1784
1785     if (!pSecurityDesc)
1786         return ERROR_INVALID_PARAMETER;
1787
1788     FIXME(":(%p,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1789
1790     return ERROR_SUCCESS;
1791 }
1792
1793
1794 /******************************************************************************
1795  * RegGetKeySecurity [ADVAPI32.@]
1796  *
1797  * Get a copy of the security descriptor for a given registry key.
1798  *
1799  * PARAMS
1800  *    hkey                   [I]   Open handle of key to set
1801  *    SecurityInformation    [I]   Descriptor contents
1802  *    pSecurityDescriptor    [O]   Address of descriptor for key
1803  *    lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1804  *
1805  * RETURNS
1806  *    Success: ERROR_SUCCESS
1807  *    Failure: Error code
1808  */
1809 LONG WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
1810                                PSECURITY_DESCRIPTOR pSecurityDescriptor,
1811                                LPDWORD lpcbSecurityDescriptor )
1812 {
1813     TRACE("(%p,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1814           lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1815
1816     /* FIXME: Check for valid SecurityInformation values */
1817
1818     if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1819         return ERROR_INSUFFICIENT_BUFFER;
1820
1821     FIXME("(%p,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1822           pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1823
1824     /* Do not leave security descriptor filled with garbage */
1825     RtlCreateSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
1826
1827     return ERROR_SUCCESS;
1828 }
1829
1830
1831 /******************************************************************************
1832  * RegFlushKey [ADVAPI32.@]
1833  * 
1834  * Immediately write a registry key to registry.
1835  *
1836  * PARAMS
1837  * hkey [I] Handle of key to write
1838  *
1839  * RETURNS
1840  *   Success: ERROR_SUCCESS
1841  *   Failure: Error code
1842  */
1843 DWORD WINAPI RegFlushKey( HKEY hkey )
1844 {
1845     hkey = get_special_root_hkey( hkey );
1846     if (!hkey) return ERROR_INVALID_HANDLE;
1847
1848     return RtlNtStatusToDosError( NtFlushKey( hkey ) );
1849 }
1850
1851
1852 /******************************************************************************
1853  * RegConnectRegistryW [ADVAPI32.@]
1854  *
1855  * PARAMS
1856  *    lpMachineName [I] Address of name of remote computer
1857  *    hHey          [I] Predefined registry handle
1858  *    phkResult     [I] Address of buffer for remote registry handle
1859  */
1860 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1861                                    PHKEY phkResult )
1862 {
1863     LONG ret;
1864
1865     TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1866
1867     if (!lpMachineName || !*lpMachineName) {
1868         /* Use the local machine name */
1869         ret = RegOpenKeyW( hKey, NULL, phkResult );
1870     }
1871     else if (lpMachineName[0] != '\\' || lpMachineName[1] != '\\')
1872         ret = ERROR_BAD_NETPATH;
1873     else
1874     {
1875         WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
1876         DWORD len = sizeof(compName) / sizeof(WCHAR);
1877
1878         if (GetComputerNameW(compName, &len))
1879         {
1880             if (!strcmpiW(lpMachineName + 2, compName))
1881                 ret = RegOpenKeyW(hKey, NULL, phkResult);
1882             else
1883             {
1884                 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1885                 ret = ERROR_BAD_NETPATH;
1886             }
1887         }
1888         else
1889             ret = GetLastError();
1890     }
1891     return ret;
1892 }
1893
1894
1895 /******************************************************************************
1896  * RegConnectRegistryA [ADVAPI32.@]
1897  */
1898 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
1899 {
1900     UNICODE_STRING machineW;
1901     LONG ret;
1902
1903     RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
1904     ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
1905     RtlFreeUnicodeString( &machineW );
1906     return ret;
1907 }
1908
1909
1910 /******************************************************************************
1911  * RegNotifyChangeKeyValue [ADVAPI32.@]
1912  *
1913  * PARAMS
1914  *    hkey            [I] Handle of key to watch
1915  *    fWatchSubTree   [I] Flag for subkey notification
1916  *    fdwNotifyFilter [I] Changes to be reported
1917  *    hEvent          [I] Handle of signaled event
1918  *    fAsync          [I] Flag for asynchronous reporting
1919  */
1920 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1921                                      DWORD fdwNotifyFilter, HANDLE hEvent,
1922                                      BOOL fAsync )
1923 {
1924     LONG ret;
1925
1926     TRACE("(%p,%i,%ld,%p,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
1927           hEvent,fAsync);
1928
1929     if( !fAsync )
1930         hEvent = CreateEventA(NULL, 0, 0, NULL);
1931
1932     SERVER_START_REQ( set_registry_notification )
1933     {
1934         req->hkey    = hkey;
1935         req->event   = hEvent;
1936         req->subtree = fWatchSubTree;
1937         req->filter  = fdwNotifyFilter;
1938         ret = RtlNtStatusToDosError( wine_server_call(req) );
1939     }
1940     SERVER_END_REQ;
1941  
1942     if( !fAsync )
1943     {
1944         if( ret == ERROR_SUCCESS )
1945             WaitForSingleObject( hEvent, INFINITE );
1946         CloseHandle( hEvent );
1947     }
1948
1949     return ret;
1950 }
1951
1952 /******************************************************************************
1953  * RegOpenUserClassesRoot [ADVAPI32.@]
1954  *
1955  * Open the HKEY_CLASSES_ROOT key for a user.
1956  *
1957  * PARAMS
1958  *    hToken     [I] Handle of token representing the user
1959  *    dwOptions  [I] Reserved, nust be 0
1960  *    samDesired [I] Desired access rights
1961  *    phkResult  [O] Destination for the resulting key handle
1962  *
1963  * NOTES
1964  * On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
1965  * "HKEY_LOCAL_MACHINE\Software\Classes" and the
1966  * "HKEY_CURRENT_USER\Software\Classes" keys merged together.
1967  */
1968 LONG WINAPI RegOpenUserClassesRoot(
1969     HANDLE hToken,
1970     DWORD dwOptions,
1971     REGSAM samDesired,
1972     PHKEY phkResult
1973 )
1974 {
1975     FIXME("(%p, 0x%lx, 0x%lx, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
1976
1977     *phkResult = HKEY_CLASSES_ROOT;
1978     return ERROR_SUCCESS;
1979 }