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