ole32: Add on the size of the whole OBJREF structure in the case of custom marshaling.
[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 "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38 #include "winerror.h"
39 #include "winternl.h"
40 #include "winuser.h"
41
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(reg);
46
47 /* allowed bits for access mask */
48 #define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
49
50 #define HKEY_SPECIAL_ROOT_FIRST   HKEY_CLASSES_ROOT
51 #define HKEY_SPECIAL_ROOT_LAST    HKEY_DYN_DATA
52 #define NB_SPECIAL_ROOT_KEYS      ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
53
54 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
55
56 static const WCHAR name_CLASSES_ROOT[] =
57     {'M','a','c','h','i','n','e','\\',
58      'S','o','f','t','w','a','r','e','\\',
59      'C','l','a','s','s','e','s',0};
60 static const WCHAR name_LOCAL_MACHINE[] =
61     {'M','a','c','h','i','n','e',0};
62 static const WCHAR name_USERS[] =
63     {'U','s','e','r',0};
64 static const WCHAR name_PERFORMANCE_DATA[] =
65     {'P','e','r','f','D','a','t','a',0};
66 static const WCHAR name_CURRENT_CONFIG[] =
67     {'M','a','c','h','i','n','e','\\',
68      'S','y','s','t','e','m','\\',
69      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
70      'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
71      'C','u','r','r','e','n','t',0};
72 static const WCHAR name_DYN_DATA[] =
73     {'D','y','n','D','a','t','a',0};
74
75 #define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
76 static UNICODE_STRING root_key_names[NB_SPECIAL_ROOT_KEYS] =
77 {
78     DECL_STR(CLASSES_ROOT),
79     { 0, 0, NULL },         /* HKEY_CURRENT_USER is determined dynamically */
80     DECL_STR(LOCAL_MACHINE),
81     DECL_STR(USERS),
82     DECL_STR(PERFORMANCE_DATA),
83     DECL_STR(CURRENT_CONFIG),
84     DECL_STR(DYN_DATA)
85 };
86 #undef DECL_STR
87
88
89 /* check if value type needs string conversion (Ansi<->Unicode) */
90 inline static int is_string( DWORD type )
91 {
92     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
93 }
94
95 /* check if current version is NT or Win95 */
96 inline static int is_version_nt(void)
97 {
98     return !(GetVersion() & 0x80000000);
99 }
100
101 /* create one of the HKEY_* special root keys */
102 static HKEY create_special_root_hkey( HANDLE hkey, DWORD access )
103 {
104     HKEY ret = 0;
105     int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
106
107     if (hkey == HKEY_CURRENT_USER)
108     {
109         if (RtlOpenCurrentUser( access, &hkey )) return 0;
110         TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
111     }
112     else
113     {
114         OBJECT_ATTRIBUTES attr;
115
116         attr.Length = sizeof(attr);
117         attr.RootDirectory = 0;
118         attr.ObjectName = &root_key_names[idx];
119         attr.Attributes = 0;
120         attr.SecurityDescriptor = NULL;
121         attr.SecurityQualityOfService = NULL;
122         if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
123         TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
124     }
125
126     if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
127         ret = hkey;
128     else
129         NtClose( hkey );  /* somebody beat us to it */
130     return ret;
131 }
132
133 /* map the hkey from special root to normal key if necessary */
134 inline static HKEY get_special_root_hkey( HKEY hkey )
135 {
136     HKEY ret = hkey;
137
138     if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
139     {
140         if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
141             ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
142     }
143     return ret;
144 }
145
146
147 /******************************************************************************
148  * RegCreateKeyExW   [ADVAPI32.@]
149  *
150  * See RegCreateKeyExA.
151  */
152 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
153                               DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
154                               PHKEY retkey, LPDWORD dispos )
155 {
156     OBJECT_ATTRIBUTES attr;
157     UNICODE_STRING nameW, classW;
158
159     if (reserved) return ERROR_INVALID_PARAMETER;
160     if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
161     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
162
163     attr.Length = sizeof(attr);
164     attr.RootDirectory = hkey;
165     attr.ObjectName = &nameW;
166     attr.Attributes = 0;
167     attr.SecurityDescriptor = NULL;
168     attr.SecurityQualityOfService = NULL;
169     RtlInitUnicodeString( &nameW, name );
170     RtlInitUnicodeString( &classW, class );
171
172     return RtlNtStatusToDosError( NtCreateKey( (PHANDLE)retkey, access, &attr, 0,
173                                                &classW, options, dispos ) );
174 }
175
176
177 /******************************************************************************
178  * RegCreateKeyExA   [ADVAPI32.@]
179  *
180  * Open a registry key, creating it if it doesn't exist.
181  *
182  * PARAMS
183  *  hkey       [I] Handle of the parent registry key
184  *  name       [I] Name of the new key to open or create
185  *  reserved   [I] Reserved, pass 0
186  *  class      [I] The object type of the new key
187  *  options    [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
188  *  access     [I] Access level desired
189  *  sa         [I] Security attributes for the key
190  *  retkey     [O] Destination for the resulting handle
191  *  dispos     [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
192  *
193  * RETURNS
194  *  Success: ERROR_SUCCESS.
195  *  Failure: A standard Win32 error code. retkey remains untouched.
196  *
197  * FIXME
198  *  MAXIMUM_ALLOWED in access mask not supported by server
199  */
200 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
201                               DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
202                               PHKEY retkey, LPDWORD dispos )
203 {
204     OBJECT_ATTRIBUTES attr;
205     UNICODE_STRING classW;
206     ANSI_STRING nameA, classA;
207     NTSTATUS status;
208
209     if (reserved) return ERROR_INVALID_PARAMETER;
210     if (!is_version_nt())
211     {
212         access = KEY_ALL_ACCESS;  /* Win95 ignores the access mask */
213         if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
214     }
215     else if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
216     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
217
218     attr.Length = sizeof(attr);
219     attr.RootDirectory = hkey;
220     attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
221     attr.Attributes = 0;
222     attr.SecurityDescriptor = NULL;
223     attr.SecurityQualityOfService = NULL;
224     RtlInitAnsiString( &nameA, name );
225     RtlInitAnsiString( &classA, class );
226
227     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
228                                                  &nameA, FALSE )))
229     {
230         if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
231         {
232             status = NtCreateKey( (PHANDLE)retkey, access, &attr, 0, &classW, options, dispos );
233             RtlFreeUnicodeString( &classW );
234         }
235     }
236     return RtlNtStatusToDosError( status );
237 }
238
239
240 /******************************************************************************
241  * RegCreateKeyW   [ADVAPI32.@]
242  *
243  * Creates the specified reg key.
244  *
245  * PARAMS
246  *  hKey      [I] Handle to an open key.
247  *  lpSubKey  [I] Name of a key that will be opened or created.
248  *  phkResult [O] Receives a handle to the opened or created key.
249  *
250  * RETURNS
251  *  Success: ERROR_SUCCESS
252  *  Failure: nonzero error code defined in Winerror.h
253  */
254 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
255 {
256     /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
257     /* but at least my version of NT (4.0 SP5) doesn't do this.  -- AJ */
258     return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
259                             KEY_ALL_ACCESS, NULL, phkResult, NULL );
260 }
261
262
263 /******************************************************************************
264  * RegCreateKeyA   [ADVAPI32.@]
265  *
266  * See RegCreateKeyW.
267  */
268 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
269 {
270     return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
271                             KEY_ALL_ACCESS, NULL, phkResult, NULL );
272 }
273
274
275
276 /******************************************************************************
277  * RegOpenKeyExW   [ADVAPI32.@]
278  * 
279  * See RegOpenKeyExA.
280  */
281 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
282 {
283     OBJECT_ATTRIBUTES attr;
284     UNICODE_STRING nameW;
285
286     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
287
288     attr.Length = sizeof(attr);
289     attr.RootDirectory = hkey;
290     attr.ObjectName = &nameW;
291     attr.Attributes = 0;
292     attr.SecurityDescriptor = NULL;
293     attr.SecurityQualityOfService = NULL;
294     RtlInitUnicodeString( &nameW, name );
295     return RtlNtStatusToDosError( NtOpenKey( (PHANDLE)retkey, access, &attr ) );
296 }
297
298
299 /******************************************************************************
300  * RegOpenKeyExA   [ADVAPI32.@]
301  *
302  * Open a registry key.
303  *
304  * PARAMS
305  *  hkey       [I] Handle of open key
306  *  name       [I] Name of subkey to open
307  *  reserved   [I] Reserved - must be zero
308  *  access     [I] Security access mask
309  *  retkey     [O] Handle to open key
310  *
311  * RETURNS
312  *  Success: ERROR_SUCCESS
313  *  Failure: A standard Win32 error code. retkey is set to 0.
314  *
315  * NOTES
316  *  Unlike RegCreateKeyExA(), this function will not create the key if it
317  *  does not exist.
318  */
319 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
320 {
321     OBJECT_ATTRIBUTES attr;
322     STRING nameA;
323     NTSTATUS status;
324
325     if (!is_version_nt()) access = KEY_ALL_ACCESS;  /* Win95 ignores the access mask */
326
327     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
328
329     attr.Length = sizeof(attr);
330     attr.RootDirectory = hkey;
331     attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
332     attr.Attributes = 0;
333     attr.SecurityDescriptor = NULL;
334     attr.SecurityQualityOfService = NULL;
335
336     RtlInitAnsiString( &nameA, name );
337     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
338                                                  &nameA, FALSE )))
339     {
340         status = NtOpenKey( (PHANDLE)retkey, access, &attr );
341     }
342     return RtlNtStatusToDosError( status );
343 }
344
345
346 /******************************************************************************
347  * RegOpenKeyW   [ADVAPI32.@]
348  *
349  * See RegOpenKeyA.
350  */
351 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
352 {
353     if (!name || !*name)
354     {
355         *retkey = hkey;
356         return ERROR_SUCCESS;
357     }
358     return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
359 }
360
361
362 /******************************************************************************
363  * RegOpenKeyA   [ADVAPI32.@]
364  *           
365  * Open a registry key.
366  *
367  * PARAMS
368  *  hkey    [I] Handle of parent key to open the new key under
369  *  name    [I] Name of the key under hkey to open
370  *  retkey  [O] Destination for the resulting Handle
371  *
372  * RETURNS
373  *  Success: ERROR_SUCCESS
374  *  Failure: A standard Win32 error code. retkey is set to 0.
375  */
376 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
377 {
378     if (!name || !*name)
379     {
380         *retkey = hkey;
381         return ERROR_SUCCESS;
382     }
383     return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
384 }
385
386
387 /******************************************************************************
388  * RegOpenCurrentUser   [ADVAPI32.@]
389  *
390  * Get a handle to the HKEY_CURRENT_USER key for the user 
391  * the current thread is impersonating.
392  *
393  * PARAMS
394  *  access [I] Desired access rights to the key
395  *  retkey [O] Handle to the opened key
396  *
397  * RETURNS
398  *  Success: ERROR_SUCCESS
399  *  Failure: nonzero error code from Winerror.h
400  *
401  * FIXME
402  *  This function is supposed to retrieve a handle to the
403  *  HKEY_CURRENT_USER for the user the current thread is impersonating.
404  *  Since Wine does not currently allow threads to impersonate other users,
405  *  this stub should work fine.
406  */
407 DWORD WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
408 {
409     return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
410 }
411
412
413
414 /******************************************************************************
415  * RegEnumKeyExW   [ADVAPI32.@]
416  *
417  * Enumerate subkeys of the specified open registry key.
418  *
419  * PARAMS
420  *  hkey         [I] Handle to key to enumerate
421  *  index        [I] Index of subkey to enumerate
422  *  name         [O] Buffer for subkey name
423  *  name_len     [O] Size of subkey buffer
424  *  reserved     [I] Reserved
425  *  class        [O] Buffer for class string
426  *  class_len    [O] Size of class buffer
427  *  ft           [O] Time key last written to
428  *
429  * RETURNS
430  *  Success: ERROR_SUCCESS
431  *  Failure: System error code. If there are no more subkeys available, the
432  *           function returns ERROR_NO_MORE_ITEMS.
433  */
434 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
435                             LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
436 {
437     NTSTATUS status;
438     char buffer[256], *buf_ptr = buffer;
439     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
440     DWORD total_size;
441
442     TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
443            name_len ? *name_len : -1, reserved, class, class_len, ft );
444
445     if (reserved) return ERROR_INVALID_PARAMETER;
446     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
447
448     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
449                              buffer, sizeof(buffer), &total_size );
450
451     while (status == STATUS_BUFFER_OVERFLOW)
452     {
453         /* retry with a dynamically allocated buffer */
454         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
455         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
456             return ERROR_NOT_ENOUGH_MEMORY;
457         info = (KEY_NODE_INFORMATION *)buf_ptr;
458         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
459                                  buf_ptr, total_size, &total_size );
460     }
461
462     if (!status)
463     {
464         DWORD len = info->NameLength / sizeof(WCHAR);
465         DWORD cls_len = info->ClassLength / sizeof(WCHAR);
466
467         if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
468
469         if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
470             status = STATUS_BUFFER_OVERFLOW;
471         else
472         {
473             *name_len = len;
474             memcpy( name, info->Name, info->NameLength );
475             name[len] = 0;
476             if (class_len)
477             {
478                 *class_len = cls_len;
479                 if (class)
480                 {
481                     memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
482                     class[cls_len] = 0;
483                 }
484             }
485         }
486     }
487
488     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
489     return RtlNtStatusToDosError( status );
490 }
491
492
493 /******************************************************************************
494  * RegEnumKeyExA   [ADVAPI32.@]
495  *
496  * See RegEnumKeyExW.
497  */
498 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
499                             LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
500 {
501     NTSTATUS status;
502     char buffer[256], *buf_ptr = buffer;
503     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
504     DWORD total_size;
505
506     TRACE( "(%p,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len,
507            name_len ? *name_len : -1, reserved, class, class_len, ft );
508
509     if (reserved) return ERROR_INVALID_PARAMETER;
510     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
511
512     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
513                              buffer, sizeof(buffer), &total_size );
514
515     while (status == STATUS_BUFFER_OVERFLOW)
516     {
517         /* retry with a dynamically allocated buffer */
518         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
519         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
520             return ERROR_NOT_ENOUGH_MEMORY;
521         info = (KEY_NODE_INFORMATION *)buf_ptr;
522         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
523                                  buf_ptr, total_size, &total_size );
524     }
525
526     if (!status)
527     {
528         DWORD len, cls_len;
529
530         RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
531         RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
532                                    info->ClassLength );
533         if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
534
535         if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
536             status = STATUS_BUFFER_OVERFLOW;
537         else
538         {
539             *name_len = len;
540             RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
541             name[len] = 0;
542             if (class_len)
543             {
544                 *class_len = cls_len;
545                 if (class)
546                 {
547                     RtlUnicodeToMultiByteN( class, cls_len, NULL,
548                                             (WCHAR *)(buf_ptr + info->ClassOffset),
549                                             info->ClassLength );
550                     class[cls_len] = 0;
551                 }
552             }
553         }
554     }
555
556     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
557     return RtlNtStatusToDosError( status );
558 }
559
560
561 /******************************************************************************
562  * RegEnumKeyW   [ADVAPI32.@]
563  *
564  * Enumerates subkyes of the specified open reg key.
565  *
566  * PARAMS
567  *  hKey    [I] Handle to an open key.
568  *  dwIndex [I] Index of the subkey of hKey to retrieve.
569  *  lpName  [O] Name of the subkey.
570  *  cchName [I] Size of lpName in TCHARS.
571  *
572  * RETURNS
573  *  Success: ERROR_SUCCESS
574  *  Failure: system error code. If there are no more subkeys available, the
575  *           function returns ERROR_NO_MORE_ITEMS.
576  */
577 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
578 {
579     return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
580 }
581
582
583 /******************************************************************************
584  * RegEnumKeyA   [ADVAPI32.@]
585  *
586  * See RegEnumKeyW.
587  */
588 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
589 {
590     return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
591 }
592
593
594 /******************************************************************************
595  * RegQueryInfoKeyW   [ADVAPI32.@]
596  *
597  * Retrieves information about the specified registry key.
598  *
599  * PARAMS
600  *    hkey       [I] Handle to key to query
601  *    class      [O] Buffer for class string
602  *    class_len  [O] Size of class string buffer
603  *    reserved   [I] Reserved
604  *    subkeys    [O] Buffer for number of subkeys
605  *    max_subkey [O] Buffer for longest subkey name length
606  *    max_class  [O] Buffer for longest class string length
607  *    values     [O] Buffer for number of value entries
608  *    max_value  [O] Buffer for longest value name length
609  *    max_data   [O] Buffer for longest value data length
610  *    security   [O] Buffer for security descriptor length
611  *    modif      [O] Modification time
612  *
613  * RETURNS
614  *  Success: ERROR_SUCCESS
615  *  Failure: system error code.
616  *
617  * NOTES
618  *  - win95 allows class to be valid and class_len to be NULL
619  *  - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
620  *  - both allow class to be NULL and class_len to be NULL
621  *    (it's hard to test validity, so test !NULL instead)
622  */
623 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
624                                LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
625                                LPDWORD values, LPDWORD max_value, LPDWORD max_data,
626                                LPDWORD security, FILETIME *modif )
627 {
628     NTSTATUS status;
629     char buffer[256], *buf_ptr = buffer;
630     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
631     DWORD total_size;
632
633     TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
634            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
635
636     if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
637     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
638
639     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
640     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
641
642     if (class)
643     {
644         /* retry with a dynamically allocated buffer */
645         while (status == STATUS_BUFFER_OVERFLOW)
646         {
647             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
648             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
649                 return ERROR_NOT_ENOUGH_MEMORY;
650             info = (KEY_FULL_INFORMATION *)buf_ptr;
651             status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
652         }
653
654         if (status) goto done;
655
656         if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
657         {
658             status = STATUS_BUFFER_OVERFLOW;
659         }
660         else
661         {
662             memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
663             class[info->ClassLength/sizeof(WCHAR)] = 0;
664         }
665     }
666     else status = STATUS_SUCCESS;
667
668     if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
669     if (subkeys) *subkeys = info->SubKeys;
670     if (max_subkey) *max_subkey = info->MaxNameLen;
671     if (max_class) *max_class = info->MaxClassLen;
672     if (values) *values = info->Values;
673     if (max_value) *max_value = info->MaxValueNameLen;
674     if (max_data) *max_data = info->MaxValueDataLen;
675     if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
676
677  done:
678     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
679     return RtlNtStatusToDosError( status );
680 }
681
682
683 /******************************************************************************
684  * RegQueryMultipleValuesA   [ADVAPI32.@]
685  *
686  * Retrieves the type and data for a list of value names associated with a key.
687  *
688  * PARAMS
689  *  hKey       [I] Handle to an open key.
690  *  val_list   [O] Array of VALENT structures that describes the entries.
691  *  num_vals   [I] Number of elements in val_list.
692  *  lpValueBuf [O] Pointer to a buffer that receives the data for each value.
693  *  ldwTotsize [I/O] Size of lpValueBuf.
694  *
695  * RETURNS
696  *  Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
697  *  Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
698  *           bytes.
699  */
700 DWORD WINAPI RegQueryMultipleValuesA(HKEY hkey, PVALENTA val_list, DWORD num_vals,
701                                      LPSTR lpValueBuf, LPDWORD ldwTotsize)
702 {
703     unsigned int i;
704     DWORD maxBytes = *ldwTotsize;
705     HRESULT status;
706     LPSTR bufptr = lpValueBuf;
707     *ldwTotsize = 0;
708
709     TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
710
711     for(i=0; i < num_vals; ++i)
712     {
713
714         val_list[i].ve_valuelen=0;
715         status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
716         if(status != ERROR_SUCCESS)
717         {
718             return status;
719         }
720
721         if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
722         {
723             status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
724                                       (LPBYTE)bufptr, &val_list[i].ve_valuelen);
725             if(status != ERROR_SUCCESS)
726             {
727                 return status;
728             }
729
730             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
731
732             bufptr += val_list[i].ve_valuelen;
733         }
734
735         *ldwTotsize += val_list[i].ve_valuelen;
736     }
737     return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
738 }
739
740
741 /******************************************************************************
742  * RegQueryMultipleValuesW   [ADVAPI32.@]
743  *
744  * See RegQueryMultipleValuesA.
745  */
746 DWORD WINAPI RegQueryMultipleValuesW(HKEY hkey, PVALENTW val_list, DWORD num_vals,
747                                      LPWSTR lpValueBuf, LPDWORD ldwTotsize)
748 {
749     unsigned int i;
750     DWORD maxBytes = *ldwTotsize;
751     HRESULT status;
752     LPSTR bufptr = (LPSTR)lpValueBuf;
753     *ldwTotsize = 0;
754
755     TRACE("(%p,%p,%ld,%p,%p=%ld)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
756
757     for(i=0; i < num_vals; ++i)
758     {
759         val_list[i].ve_valuelen=0;
760         status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
761         if(status != ERROR_SUCCESS)
762         {
763             return status;
764         }
765
766         if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
767         {
768             status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
769                                       (LPBYTE)bufptr, &val_list[i].ve_valuelen);
770             if(status != ERROR_SUCCESS)
771             {
772                 return status;
773             }
774
775             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
776
777             bufptr += val_list[i].ve_valuelen;
778         }
779
780         *ldwTotsize += val_list[i].ve_valuelen;
781     }
782     return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
783 }
784
785 /******************************************************************************
786  * RegQueryInfoKeyA   [ADVAPI32.@]
787  *
788  * Retrieves information about a registry key.
789  *
790  * PARAMS
791  *  hKey                   [I] Handle to an open key.
792  *  lpClass                [O] Class string of the key.
793  *  lpcClass               [I/O] size of lpClass.
794  *  lpReserved             [I] Reserved; must be NULL.
795  *  lpcSubKeys             [O] Number of subkeys contained by the key.
796  *  lpcMaxSubKeyLen        [O] Size of the key's subkey with the longest name.
797  *  lpcMaxClassLen         [O] Size of the longest string specifying a subkey
798  *                             class in TCHARS.
799  *  lpcValues              [O] Number of values associated with the key.
800  *  lpcMaxValueNameLen     [O] Size of the key's longest value name in TCHARS.
801  *  lpcMaxValueLen         [O] Longest data component among the key's values
802  *  lpcbSecurityDescriptor [O] Size of the key's security descriptor.
803  *  lpftLastWriteTime      [O] FILETIME strucutre that is the last write time.
804  *
805  *  RETURNS
806  *   Success: ERROR_SUCCESS
807  *   Failure: nonzero error code from Winerror.h
808  */
809 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
810                                LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
811                                LPDWORD values, LPDWORD max_value, LPDWORD max_data,
812                                LPDWORD security, FILETIME *modif )
813 {
814     NTSTATUS status;
815     char buffer[256], *buf_ptr = buffer;
816     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
817     DWORD total_size, len;
818
819     TRACE( "(%p,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
820            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
821
822     if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
823     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
824
825     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
826     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
827
828     if (class || class_len)
829     {
830         /* retry with a dynamically allocated buffer */
831         while (status == STATUS_BUFFER_OVERFLOW)
832         {
833             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
834             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
835                 return ERROR_NOT_ENOUGH_MEMORY;
836             info = (KEY_FULL_INFORMATION *)buf_ptr;
837             status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
838         }
839
840         if (status) goto done;
841
842         RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
843         if (class_len)
844         {
845             if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
846             *class_len = len;
847         }
848         if (class && !status)
849         {
850             RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
851                                     info->ClassLength );
852             class[len] = 0;
853         }
854     }
855     else status = STATUS_SUCCESS;
856
857     if (subkeys) *subkeys = info->SubKeys;
858     if (max_subkey) *max_subkey = info->MaxNameLen;
859     if (max_class) *max_class = info->MaxClassLen;
860     if (values) *values = info->Values;
861     if (max_value) *max_value = info->MaxValueNameLen;
862     if (max_data) *max_data = info->MaxValueDataLen;
863     if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
864
865  done:
866     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
867     return RtlNtStatusToDosError( status );
868 }
869
870
871 /******************************************************************************
872  * RegCloseKey   [ADVAPI32.@]
873  *
874  * Close an open registry key.
875  *
876  * PARAMS
877  *  hkey [I] Handle of key to close
878  *
879  * RETURNS
880  *  Success: ERROR_SUCCESS
881  *  Failure: Error code
882  */
883 DWORD WINAPI RegCloseKey( HKEY hkey )
884 {
885     if (!hkey) return ERROR_INVALID_HANDLE;
886     if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
887     return RtlNtStatusToDosError( NtClose( hkey ) );
888 }
889
890
891 /******************************************************************************
892  * RegDeleteKeyW   [ADVAPI32.@]
893  *
894  * See RegDeleteKeyA.
895  */
896 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
897 {
898     DWORD ret;
899     HKEY tmp;
900
901     if (!name) return ERROR_INVALID_PARAMETER;
902
903     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
904
905     if (!(ret = RegOpenKeyExW( hkey, name, 0, DELETE, &tmp )))
906     {
907         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
908         RegCloseKey( tmp );
909     }
910     TRACE("%s ret=%08lx\n", debugstr_w(name), ret);
911     return ret;
912 }
913
914
915 /******************************************************************************
916  * RegDeleteKeyA   [ADVAPI32.@]
917  *
918  * Delete a registry key.
919  *
920  * PARAMS
921  *  hkey   [I] Handle to parent key containing the key to delete
922  *  name   [I] Name of the key user hkey to delete
923  *
924  * NOTES
925  *
926  * MSDN is wrong when it says that hkey must be opened with the DELETE access
927  * right. In reality, it opens a new handle with DELETE access.
928  *
929  * RETURNS
930  *  Success: ERROR_SUCCESS
931  *  Failure: Error code
932  */
933 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
934 {
935     DWORD ret;
936     HKEY tmp;
937
938     if (!name) return ERROR_INVALID_PARAMETER;
939
940     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
941
942     if (!(ret = RegOpenKeyExA( hkey, name, 0, DELETE, &tmp )))
943     {
944         if (!is_version_nt()) /* win95 does recursive key deletes */
945         {
946             CHAR name[MAX_PATH];
947
948             while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
949             {
950                 if(RegDeleteKeyA(tmp, name))  /* recurse */
951                     break;
952             }
953         }
954         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
955         RegCloseKey( tmp );
956     }
957     TRACE("%s ret=%08lx\n", debugstr_a(name), ret);
958     return ret;
959 }
960
961
962
963 /******************************************************************************
964  * RegSetValueExW   [ADVAPI32.@]
965  *
966  * Set the data and contents of a registry value.
967  *
968  * PARAMS
969  *  hkey       [I] Handle of key to set value for
970  *  name       [I] Name of value to set
971  *  reserved   [I] Reserved, must be zero
972  *  type       [I] Type of the value being set
973  *  data       [I] The new contents of the value to set
974  *  count      [I] Size of data
975  *
976  * RETURNS
977  *  Success: ERROR_SUCCESS
978  *  Failure: Error code
979  */
980 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
981                              DWORD type, CONST BYTE *data, DWORD count )
982 {
983     UNICODE_STRING nameW;
984
985     /* no need for version check, not implemented on win9x anyway */
986     if (count && is_string(type))
987     {
988         LPCWSTR str = (LPCWSTR)data;
989         /* if user forgot to count terminating null, add it (yes NT does this) */
990         if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
991             count += sizeof(WCHAR);
992     }
993     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
994
995     RtlInitUnicodeString( &nameW, name );
996     return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
997 }
998
999
1000 /******************************************************************************
1001  * RegSetValueExA   [ADVAPI32.@]
1002  *
1003  * See RegSetValueExW.
1004  *
1005  * NOTES
1006  *  win95 does not care about count for REG_SZ and finds out the len by itself (js)
1007  *  NT does definitely care (aj)
1008  */
1009 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1010                              CONST BYTE *data, DWORD count )
1011 {
1012     ANSI_STRING nameA;
1013     WCHAR *dataW = NULL;
1014     NTSTATUS status;
1015
1016     if (!is_version_nt())  /* win95 */
1017     {
1018         if (type == REG_SZ)
1019         {
1020             if (!data) return ERROR_INVALID_PARAMETER;
1021             count = strlen((const char *)data) + 1;
1022         }
1023     }
1024     else if (count && is_string(type))
1025     {
1026         /* if user forgot to count terminating null, add it (yes NT does this) */
1027         if (data[count-1] && !data[count]) count++;
1028     }
1029
1030     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1031
1032     if (is_string( type )) /* need to convert to Unicode */
1033     {
1034         DWORD lenW;
1035         RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1036         if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
1037         RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1038         count = lenW;
1039         data = (BYTE *)dataW;
1040     }
1041
1042     RtlInitAnsiString( &nameA, name );
1043     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1044                                                  &nameA, FALSE )))
1045     {
1046         status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
1047     }
1048     HeapFree( GetProcessHeap(), 0, dataW );
1049     return RtlNtStatusToDosError( status );
1050 }
1051
1052
1053 /******************************************************************************
1054  * RegSetValueW   [ADVAPI32.@]
1055  *
1056  * Sets the data for the default or unnamed value of a reg key.
1057  *
1058  * PARAMS
1059  *  hKey     [I] Handle to an open key.
1060  *  lpSubKey [I] Name of a subkey of hKey.
1061  *  dwType   [I] Type of information to store.
1062  *  lpData   [I] String that contains the data to set for the default value.
1063  *  cbData   [I] Size of lpData.
1064  *
1065  * RETURNS
1066  *  Success: ERROR_SUCCESS
1067  *  Failure: nonzero error code from Winerror.h
1068  */
1069 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1070 {
1071     HKEY subkey = hkey;
1072     DWORD ret;
1073
1074     TRACE("(%p,%s,%ld,%s,%ld)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1075
1076     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
1077
1078     if (name && name[0])  /* need to create the subkey */
1079     {
1080         if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1081     }
1082
1083     ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1084                           (strlenW( data ) + 1) * sizeof(WCHAR) );
1085     if (subkey != hkey) RegCloseKey( subkey );
1086     return ret;
1087 }
1088
1089
1090 /******************************************************************************
1091  * RegSetValueA   [ADVAPI32.@]
1092  *
1093  * See RegSetValueW.
1094  */
1095 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1096 {
1097     HKEY subkey = hkey;
1098     DWORD ret;
1099
1100     TRACE("(%p,%s,%ld,%s,%ld)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1101
1102     if (type != REG_SZ) return ERROR_INVALID_PARAMETER;
1103
1104     if (name && name[0])  /* need to create the subkey */
1105     {
1106         if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1107     }
1108     ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1109     if (subkey != hkey) RegCloseKey( subkey );
1110     return ret;
1111 }
1112
1113
1114
1115 /******************************************************************************
1116  * RegQueryValueExW   [ADVAPI32.@]
1117  *
1118  * See RegQueryValueExA.
1119  */
1120 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1121                                LPBYTE data, LPDWORD count )
1122 {
1123     NTSTATUS status;
1124     UNICODE_STRING name_str;
1125     DWORD total_size;
1126     char buffer[256], *buf_ptr = buffer;
1127     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1128     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1129
1130     TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1131           hkey, debugstr_w(name), reserved, type, data, count,
1132           (count && data) ? *count : 0 );
1133
1134     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1135     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1136
1137     RtlInitUnicodeString( &name_str, name );
1138
1139     if (data) total_size = min( sizeof(buffer), *count + info_size );
1140     else total_size = info_size;
1141
1142     status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1143                               buffer, total_size, &total_size );
1144     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1145
1146     if (data)
1147     {
1148         /* retry with a dynamically allocated buffer */
1149         while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1150         {
1151             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1152             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1153                 return ERROR_NOT_ENOUGH_MEMORY;
1154             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1155             status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
1156                                       buf_ptr, total_size, &total_size );
1157         }
1158
1159         if (!status)
1160         {
1161             memcpy( data, buf_ptr + info_size, total_size - info_size );
1162             /* if the type is REG_SZ and data is not 0-terminated
1163              * and there is enough space in the buffer NT appends a \0 */
1164             if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1165             {
1166                 WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
1167                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1168             }
1169         }
1170         else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1171     }
1172     else status = STATUS_SUCCESS;
1173
1174     if (type) *type = info->Type;
1175     if (count) *count = total_size - info_size;
1176
1177  done:
1178     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1179     return RtlNtStatusToDosError(status);
1180 }
1181
1182
1183 /******************************************************************************
1184  * RegQueryValueExA   [ADVAPI32.@]
1185  *
1186  * Get the type and contents of a specified value under with a key.
1187  *
1188  * PARAMS
1189  *  hkey      [I]   Handle of the key to query
1190  *  name      [I]   Name of value under hkey to query
1191  *  reserved  [I]   Reserved - must be NULL
1192  *  type      [O]   Destination for the value type, or NULL if not required
1193  *  data      [O]   Destination for the values contents, or NULL if not required
1194  *  count     [I/O] Size of data, updated with the number of bytes returned
1195  *
1196  * RETURNS
1197  *  Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
1198  *  Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
1199  *           ERROR_INVALID_PARAMETER, if any other parameter is invalid.
1200  *           ERROR_MORE_DATA, if on input *count is too small to hold the contents.
1201  *                     
1202  * NOTES
1203  *   MSDN states that if data is too small it is partially filled. In reality 
1204  *   it remains untouched.
1205  */
1206 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1207                                LPBYTE data, LPDWORD count )
1208 {
1209     NTSTATUS status;
1210     ANSI_STRING nameA;
1211     DWORD total_size;
1212     char buffer[256], *buf_ptr = buffer;
1213     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1214     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1215
1216     TRACE("(%p,%s,%p,%p,%p,%p=%ld)\n",
1217           hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
1218
1219     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1220     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1221
1222     RtlInitAnsiString( &nameA, name );
1223     if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1224                                                 &nameA, FALSE )))
1225         return RtlNtStatusToDosError(status);
1226
1227     status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1228                               KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
1229     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1230
1231     /* we need to fetch the contents for a string type even if not requested,
1232      * because we need to compute the length of the ASCII string. */
1233     if (data || is_string(info->Type))
1234     {
1235         /* retry with a dynamically allocated buffer */
1236         while (status == STATUS_BUFFER_OVERFLOW)
1237         {
1238             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1239             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1240             {
1241                 status = STATUS_NO_MEMORY;
1242                 goto done;
1243             }
1244             info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1245             status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
1246                                     KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1247         }
1248
1249         if (status) goto done;
1250
1251         if (is_string(info->Type))
1252         {
1253             DWORD len;
1254
1255             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
1256                                        total_size - info_size );
1257             if (data && len)
1258             {
1259                 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1260                 else
1261                 {
1262                     RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1263                                             total_size - info_size );
1264                     /* if the type is REG_SZ and data is not 0-terminated
1265                      * and there is enough space in the buffer NT appends a \0 */
1266                     if (len < *count && data[len-1]) data[len] = 0;
1267                 }
1268             }
1269             total_size = len + info_size;
1270         }
1271         else if (data)
1272         {
1273             if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
1274             else memcpy( data, buf_ptr + info_size, total_size - info_size );
1275         }
1276     }
1277     else status = STATUS_SUCCESS;
1278
1279     if (type) *type = info->Type;
1280     if (count) *count = total_size - info_size;
1281
1282  done:
1283     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1284     return RtlNtStatusToDosError(status);
1285 }
1286
1287
1288 /******************************************************************************
1289  * RegQueryValueW   [ADVAPI32.@]
1290  *
1291  * Retrieves the data associated with the default or unnamed value of a key.
1292  *
1293  * PARAMS
1294  *  hkey      [I] Handle to an open key.
1295  *  name      [I] Name of the subkey of hKey.
1296  *  data      [O] Receives the string associated with the default value
1297  *                of the key.
1298  *  count     [I/O] Size of lpValue in bytes.
1299  *
1300  *  RETURNS
1301  *   Success: ERROR_SUCCESS
1302  *   Failure: nonzero error code from Winerror.h
1303  */
1304 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1305 {
1306     DWORD ret;
1307     HKEY subkey = hkey;
1308
1309     TRACE("(%p,%s,%p,%ld)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1310
1311     if (name && name[0])
1312     {
1313         if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1314     }
1315     ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1316     if (subkey != hkey) RegCloseKey( subkey );
1317     if (ret == ERROR_FILE_NOT_FOUND)
1318     {
1319         /* return empty string if default value not found */
1320         if (data) *data = 0;
1321         if (count) *count = sizeof(WCHAR);
1322         ret = ERROR_SUCCESS;
1323     }
1324     return ret;
1325 }
1326
1327
1328 /******************************************************************************
1329  * RegQueryValueA   [ADVAPI32.@]
1330  *
1331  * See RegQueryValueW.
1332  */
1333 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1334 {
1335     DWORD ret;
1336     HKEY subkey = hkey;
1337
1338     TRACE("(%p,%s,%p,%ld)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1339
1340     if (name && name[0])
1341     {
1342         if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
1343     }
1344     ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1345     if (subkey != hkey) RegCloseKey( subkey );
1346     if (ret == ERROR_FILE_NOT_FOUND)
1347     {
1348         /* return empty string if default value not found */
1349         if (data) *data = 0;
1350         if (count) *count = 1;
1351         ret = ERROR_SUCCESS;
1352     }
1353     return ret;
1354 }
1355
1356
1357 /******************************************************************************
1358  * ADVAPI_ApplyRestrictions   [internal]
1359  *
1360  * Helper function for RegGetValueA/W.
1361  */
1362 VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType, DWORD cbData,
1363                                PLONG ret )
1364 {
1365     /* Check if the type is restricted by the passed flags */
1366     if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
1367     {
1368         DWORD dwMask = 0;
1369
1370         switch (dwType)
1371         {
1372         case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
1373         case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
1374         case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
1375         case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
1376         case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
1377         case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
1378         case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
1379         }
1380
1381         if (dwFlags & dwMask)
1382         {
1383             /* Type is not restricted, check for size mismatch */
1384             if (dwType == REG_BINARY)
1385             {
1386                 DWORD cbExpect = 0;
1387
1388                 if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD)
1389                     cbExpect = 4;
1390                 else if ((dwFlags & RRF_RT_DWORD) == RRF_RT_QWORD)
1391                     cbExpect = 8;
1392
1393                 if (cbExpect && cbData != cbExpect)
1394                     *ret = ERROR_DATATYPE_MISMATCH;
1395             }
1396         }
1397         else *ret = ERROR_UNSUPPORTED_TYPE;
1398     }
1399 }
1400
1401
1402 /******************************************************************************
1403  * RegGetValueW   [ADVAPI32.@]
1404  *
1405  * Retrieves the type and data for a value name associated with a key 
1406  * optionally expanding it's content and restricting it's type.
1407  *
1408  * PARAMS
1409  *  hKey      [I] Handle to an open key.
1410  *  pszSubKey [I] Name of the subkey of hKey.
1411  *  pszValue  [I] Name of value under hKey/szSubKey to query.
1412  *  dwFlags   [I] Flags restricting the value type to retrieve.
1413  *  pdwType   [O] Destination for the values type, may be NULL.
1414  *  pvData    [O] Destination for the values content, may be NULL.
1415  *  pcbData   [I/O] Size of pvData, updated with the size required to 
1416  *                  retrieve the whole content.
1417  *
1418  * RETURNS
1419  *  Success: ERROR_SUCCESS
1420  *  Failure: nonzero error code from Winerror.h
1421  *
1422  * NOTES
1423  *  - Unless RRF_NOEXPAND is specified REG_EXPAND_SZ is automatically expanded
1424  *    and REG_SZ is retrieved instead.
1425  *  - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ 
1426  *    without RRF_NOEXPAND is thus not allowed.
1427  */
1428 LONG WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue, 
1429                           DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
1430                           LPDWORD pcbData )
1431 {
1432     DWORD dwType, cbData = pcbData ? *pcbData : 0;
1433     PVOID pvBuf = NULL;
1434     LONG ret;
1435
1436     TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n", 
1437           hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
1438           pvData, pcbData, cbData);
1439
1440     if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
1441         return ERROR_INVALID_PARAMETER;
1442
1443     if (pszSubKey && pszSubKey[0])
1444     {
1445         ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1446         if (ret != ERROR_SUCCESS) return ret;
1447     }
1448
1449     ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1450     
1451     /* If we are going to expand we need to read in the whole the value even
1452      * if the passed buffer was too small as the expanded string might be
1453      * smaller than the unexpanded one and could fit into cbData bytes. */
1454     if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1455         (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
1456     {
1457         do {
1458             if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf);
1459             
1460             pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1461             if (!pvBuf)
1462             {
1463                 ret = ERROR_NOT_ENOUGH_MEMORY;
1464                 break;
1465             }
1466
1467             if (ret == ERROR_MORE_DATA)
1468                 ret = RegQueryValueExW(hKey, pszValue, NULL, 
1469                                        &dwType, pvBuf, &cbData);
1470             else
1471             {
1472                 /* Even if cbData was large enough we have to copy the 
1473                  * string since ExpandEnvironmentStrings can't handle
1474                  * overlapping buffers. */
1475                 CopyMemory(pvBuf, pvData, cbData);
1476             }
1477
1478             /* Both the type or the value itself could have been modified in
1479              * between so we have to keep retrying until the buffer is large
1480              * enough or we no longer have to expand the value. */
1481         } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1482
1483         if (ret == ERROR_SUCCESS)
1484         {
1485             if (dwType == REG_EXPAND_SZ)
1486             {
1487                 cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1488                                                    pcbData ? *pcbData : 0);
1489                 dwType = REG_SZ;
1490                 if(pcbData && cbData > *pcbData)
1491                     ret = ERROR_MORE_DATA;
1492             }
1493             else if (pcbData)
1494                 CopyMemory(pvData, pvBuf, *pcbData);
1495         }
1496
1497         if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf);
1498     }
1499
1500     if (pszSubKey && pszSubKey[0])
1501         RegCloseKey(hKey);
1502
1503     ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1504
1505     if (pcbData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1506         ZeroMemory(pvData, *pcbData);
1507
1508     if (pdwType) *pdwType = dwType;
1509     if (pcbData) *pcbData = cbData;
1510
1511     return ret;
1512 }
1513
1514
1515 /******************************************************************************
1516  * RegGetValueA   [ADVAPI32.@]
1517  *
1518  * See RegGetValueW.
1519  */
1520 LONG WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue, 
1521                           DWORD dwFlags, LPDWORD pdwType, PVOID pvData, 
1522                           LPDWORD pcbData )
1523 {
1524     DWORD dwType, cbData = pcbData ? *pcbData : 0;
1525     PVOID pvBuf = NULL;
1526     LONG ret;
1527
1528     TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n", 
1529           hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
1530           cbData);
1531
1532     if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
1533         return ERROR_INVALID_PARAMETER;
1534
1535     if (pszSubKey && pszSubKey[0])
1536     {
1537         ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
1538         if (ret != ERROR_SUCCESS) return ret;
1539     }
1540
1541     ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);
1542
1543     /* If we are going to expand we need to read in the whole the value even
1544      * if the passed buffer was too small as the expanded string might be
1545      * smaller than the unexpanded one and could fit into cbData bytes. */
1546     if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1547         (dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
1548     {
1549         do {
1550             if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf);
1551
1552             pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
1553             if (!pvBuf)
1554             {
1555                 ret = ERROR_NOT_ENOUGH_MEMORY;
1556                 break;
1557             }
1558
1559             if (ret == ERROR_MORE_DATA)
1560                 ret = RegQueryValueExA(hKey, pszValue, NULL, 
1561                                        &dwType, pvBuf, &cbData);
1562             else
1563             {
1564                 /* Even if cbData was large enough we have to copy the 
1565                  * string since ExpandEnvironmentStrings can't handle
1566                  * overlapping buffers. */
1567                 CopyMemory(pvBuf, pvData, cbData);
1568             }
1569
1570             /* Both the type or the value itself could have been modified in
1571              * between so we have to keep retrying until the buffer is large
1572              * enough or we no longer have to expand the value. */
1573         } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
1574
1575         if (ret == ERROR_SUCCESS)
1576         {
1577             if (dwType == REG_EXPAND_SZ)
1578             {
1579                 cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
1580                                                    pcbData ? *pcbData : 0);
1581                 dwType = REG_SZ;
1582                 if(pcbData && cbData > *pcbData)
1583                     ret = ERROR_MORE_DATA;
1584             }
1585             else if (pcbData)
1586                 CopyMemory(pvData, pvBuf, *pcbData);
1587         }
1588
1589         if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf);
1590     }
1591
1592     if (pszSubKey && pszSubKey[0])
1593         RegCloseKey(hKey);
1594
1595     ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);
1596
1597     if (pcbData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1598         ZeroMemory(pvData, *pcbData);
1599
1600     if (pdwType) *pdwType = dwType;
1601     if (pcbData) *pcbData = cbData;
1602
1603     return ret;
1604 }
1605
1606
1607 /******************************************************************************
1608  * RegEnumValueW   [ADVAPI32.@]
1609  *
1610  * Enumerates the values for the specified open registry key.
1611  *
1612  * PARAMS
1613  *  hkey       [I] Handle to key to query
1614  *  index      [I] Index of value to query
1615  *  value      [O] Value string
1616  *  val_count  [I/O] Size of value buffer (in wchars)
1617  *  reserved   [I] Reserved
1618  *  type       [O] Type code
1619  *  data       [O] Value data
1620  *  count      [I/O] Size of data buffer (in bytes)
1621  *
1622  * RETURNS
1623  *  Success: ERROR_SUCCESS
1624  *  Failure: nonzero error code from Winerror.h
1625  */
1626
1627 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1628                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1629 {
1630     NTSTATUS status;
1631     DWORD total_size;
1632     char buffer[256], *buf_ptr = buffer;
1633     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1634     static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1635
1636     TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1637           hkey, index, value, val_count, reserved, type, data, count );
1638
1639     /* NT only checks count, not val_count */
1640     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1641     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1642
1643     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1644     if (data) total_size += *count;
1645     total_size = min( sizeof(buffer), total_size );
1646
1647     status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1648                                   buffer, total_size, &total_size );
1649     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1650
1651     if (value || data)
1652     {
1653         /* retry with a dynamically allocated buffer */
1654         while (status == STATUS_BUFFER_OVERFLOW)
1655         {
1656             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1657             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1658                 return ERROR_NOT_ENOUGH_MEMORY;
1659             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1660             status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1661                                           buf_ptr, total_size, &total_size );
1662         }
1663
1664         if (status) goto done;
1665
1666         if (value)
1667         {
1668             if (info->NameLength/sizeof(WCHAR) >= *val_count)
1669             {
1670                 status = STATUS_BUFFER_OVERFLOW;
1671                 goto overflow;
1672             }
1673             memcpy( value, info->Name, info->NameLength );
1674             *val_count = info->NameLength / sizeof(WCHAR);
1675             value[*val_count] = 0;
1676         }
1677
1678         if (data)
1679         {
1680             if (total_size - info->DataOffset > *count)
1681             {
1682                 status = STATUS_BUFFER_OVERFLOW;
1683                 goto overflow;
1684             }
1685             memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1686             if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
1687             {
1688                 /* if the type is REG_SZ and data is not 0-terminated
1689                  * and there is enough space in the buffer NT appends a \0 */
1690                 WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
1691                 if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1692             }
1693         }
1694     }
1695     else status = STATUS_SUCCESS;
1696
1697  overflow:
1698     if (type) *type = info->Type;
1699     if (count) *count = info->DataLength;
1700
1701  done:
1702     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1703     return RtlNtStatusToDosError(status);
1704 }
1705
1706
1707 /******************************************************************************
1708  * RegEnumValueA   [ADVAPI32.@]
1709  *
1710  * See RegEnumValueW.
1711  */
1712 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1713                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1714 {
1715     NTSTATUS status;
1716     DWORD total_size;
1717     char buffer[256], *buf_ptr = buffer;
1718     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1719     static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1720
1721     TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
1722           hkey, index, value, val_count, reserved, type, data, count );
1723
1724     /* NT only checks count, not val_count */
1725     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1726     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1727
1728     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
1729     if (data) total_size += *count;
1730     total_size = min( sizeof(buffer), total_size );
1731
1732     status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1733                                   buffer, total_size, &total_size );
1734     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1735
1736     /* we need to fetch the contents for a string type even if not requested,
1737      * because we need to compute the length of the ASCII string. */
1738     if (value || data || is_string(info->Type))
1739     {
1740         /* retry with a dynamically allocated buffer */
1741         while (status == STATUS_BUFFER_OVERFLOW)
1742         {
1743             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1744             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1745                 return ERROR_NOT_ENOUGH_MEMORY;
1746             info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
1747             status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
1748                                           buf_ptr, total_size, &total_size );
1749         }
1750
1751         if (status) goto done;
1752
1753         if (is_string(info->Type))
1754         {
1755             DWORD len;
1756             RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
1757                                        total_size - info->DataOffset );
1758             if (data && len)
1759             {
1760                 if (len > *count) status = STATUS_BUFFER_OVERFLOW;
1761                 else
1762                 {
1763                     RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1764                                             total_size - info->DataOffset );
1765                     /* if the type is REG_SZ and data is not 0-terminated
1766                      * and there is enough space in the buffer NT appends a \0 */
1767                     if (len < *count && data[len-1]) data[len] = 0;
1768                 }
1769             }
1770             info->DataLength = len;
1771         }
1772         else if (data)
1773         {
1774             if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
1775             else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1776         }
1777
1778         if (value && !status)
1779         {
1780             DWORD len;
1781
1782             RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
1783             if (len >= *val_count)
1784             {
1785                 status = STATUS_BUFFER_OVERFLOW;
1786                 if (*val_count)
1787                 {
1788                     len = *val_count - 1;
1789                     RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1790                     value[len] = 0;
1791                 }
1792             }
1793             else
1794             {
1795                 RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
1796                 value[len] = 0;
1797                 *val_count = len;
1798             }
1799         }
1800     }
1801     else status = STATUS_SUCCESS;
1802
1803     if (type) *type = info->Type;
1804     if (count) *count = info->DataLength;
1805
1806  done:
1807     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1808     return RtlNtStatusToDosError(status);
1809 }
1810
1811
1812
1813 /******************************************************************************
1814  * RegDeleteValueW   [ADVAPI32.@]
1815  *
1816  * See RegDeleteValueA.
1817  */
1818 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1819 {
1820     UNICODE_STRING nameW;
1821
1822     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1823
1824     RtlInitUnicodeString( &nameW, name );
1825     return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1826 }
1827
1828
1829 /******************************************************************************
1830  * RegDeleteValueA   [ADVAPI32.@]
1831  *
1832  * Delete a value from the registry.
1833  *
1834  * PARAMS
1835  *  hkey [I] Registry handle of the key holding the value
1836  *  name [I] Name of the value under hkey to delete
1837  *
1838  * RETURNS
1839  *  Success: ERROR_SUCCESS
1840  *  Failure: nonzero error code from Winerror.h
1841  */
1842 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1843 {
1844     STRING nameA;
1845     NTSTATUS status;
1846
1847     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1848
1849     RtlInitAnsiString( &nameA, name );
1850     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
1851                                                  &nameA, FALSE )))
1852         status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1853     return RtlNtStatusToDosError( status );
1854 }
1855
1856
1857 /******************************************************************************
1858  * RegLoadKeyW   [ADVAPI32.@]
1859  *
1860  * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
1861  * registration information from a specified file into that subkey.
1862  *
1863  * PARAMS
1864  *  hkey      [I] Handle of open key
1865  *  subkey    [I] Address of name of subkey
1866  *  filename  [I] Address of filename for registry information
1867  *
1868  * RETURNS
1869  *  Success: ERROR_SUCCES
1870  *  Failure: nonzero error code from Winerror.h
1871  */
1872 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1873 {
1874     OBJECT_ATTRIBUTES destkey, file;
1875     UNICODE_STRING subkeyW, filenameW;
1876
1877     if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;
1878
1879     destkey.Length = sizeof(destkey);
1880     destkey.RootDirectory = hkey;               /* root key: HKLM or HKU */
1881     destkey.ObjectName = &subkeyW;              /* name of the key */
1882     destkey.Attributes = 0;
1883     destkey.SecurityDescriptor = NULL;
1884     destkey.SecurityQualityOfService = NULL;
1885     RtlInitUnicodeString(&subkeyW, subkey);
1886
1887     file.Length = sizeof(file);
1888     file.RootDirectory = NULL;
1889     file.ObjectName = &filenameW;               /* file containing the hive */
1890     file.Attributes = OBJ_CASE_INSENSITIVE;
1891     file.SecurityDescriptor = NULL;
1892     file.SecurityQualityOfService = NULL;
1893     RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);
1894
1895     return RtlNtStatusToDosError( NtLoadKey(&destkey, &file) );
1896 }
1897
1898
1899 /******************************************************************************
1900  * RegLoadKeyA   [ADVAPI32.@]
1901  *
1902  * See RegLoadKeyW.
1903  */
1904 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1905 {
1906     UNICODE_STRING subkeyW, filenameW;
1907     STRING subkeyA, filenameA;
1908     NTSTATUS status;
1909
1910     RtlInitAnsiString(&subkeyA, subkey);
1911     RtlInitAnsiString(&filenameA, filename);
1912
1913     if ((status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)))
1914         return RtlNtStatusToDosError(status);
1915
1916     if ((status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
1917         return RtlNtStatusToDosError(status);
1918
1919     return RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
1920 }
1921
1922
1923 /******************************************************************************
1924  * RegSaveKeyW   [ADVAPI32.@]
1925  *
1926  * Save a key and all of its subkeys and values to a new file in the standard format.
1927  *
1928  * PARAMS
1929  *  hkey   [I] Handle of key where save begins
1930  *  lpFile [I] Address of filename to save to
1931  *  sa     [I] Address of security structure
1932  *
1933  * RETURNS
1934  *  Success: ERROR_SUCCESS
1935  *  Failure: nonzero error code from Winerror.h
1936  */
1937 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1938 {
1939     static const WCHAR format[] =
1940         {'r','e','g','%','0','4','x','.','t','m','p',0};
1941     WCHAR buffer[MAX_PATH];
1942     int count = 0;
1943     LPWSTR nameW;
1944     DWORD ret, err;
1945     HANDLE handle;
1946
1947     TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
1948
1949     if (!file || !*file) return ERROR_INVALID_PARAMETER;
1950     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1951
1952     err = GetLastError();
1953     GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );
1954
1955     for (;;)
1956     {
1957         snprintfW( nameW, 16, format, count++ );
1958         handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1959                             CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1960         if (handle != INVALID_HANDLE_VALUE) break;
1961         if ((ret = GetLastError()) != ERROR_ALREADY_EXISTS) goto done;
1962
1963         /* Something gone haywire ? Please report if this happens abnormally */
1964         if (count >= 100)
1965             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);
1966     }
1967
1968     ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
1969
1970     CloseHandle( handle );
1971     if (!ret)
1972     {
1973         if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
1974         {
1975             ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
1976                 debugstr_w(file) );
1977             ret = GetLastError();
1978         }
1979     }
1980     if (ret) DeleteFileW( buffer );
1981
1982 done:
1983     SetLastError( err );  /* restore last error code */
1984     return ret;
1985 }
1986
1987
1988 /******************************************************************************
1989  * RegSaveKeyA  [ADVAPI32.@]
1990  *
1991  * See RegSaveKeyW.
1992  */
1993 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
1994 {
1995     UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
1996     NTSTATUS status;
1997     STRING fileA;
1998
1999     RtlInitAnsiString(&fileA, file);
2000     if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
2001         return RtlNtStatusToDosError( status );
2002     return RegSaveKeyW(hkey, fileW->Buffer, sa);
2003 }
2004
2005
2006 /******************************************************************************
2007  * RegRestoreKeyW [ADVAPI32.@]
2008  *
2009  * Read the registry information from a file and copy it over a key.
2010  *
2011  * PARAMS
2012  *  hkey    [I] Handle of key where restore begins
2013  *  lpFile  [I] Address of filename containing saved tree
2014  *  dwFlags [I] Optional flags
2015  *
2016  * RETURNS
2017  *  Success: ERROR_SUCCESS
2018  *  Failure: nonzero error code from Winerror.h
2019  */
2020 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2021 {
2022     TRACE("(%p,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
2023
2024     /* It seems to do this check before the hkey check */
2025     if (!lpFile || !*lpFile)
2026         return ERROR_INVALID_PARAMETER;
2027
2028     FIXME("(%p,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2029
2030     /* Check for file existence */
2031
2032     return ERROR_SUCCESS;
2033 }
2034
2035
2036 /******************************************************************************
2037  * RegRestoreKeyA [ADVAPI32.@]
2038  *
2039  * See RegRestoreKeyW.
2040  */
2041 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2042 {
2043     UNICODE_STRING lpFileW;
2044     LONG ret;
2045
2046     RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
2047     ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
2048     RtlFreeUnicodeString( &lpFileW );
2049     return ret;
2050 }
2051
2052
2053 /******************************************************************************
2054  * RegUnLoadKeyW [ADVAPI32.@]
2055  *
2056  * Unload a registry key and its subkeys from the registry.
2057  *
2058  * PARAMS
2059  *  hkey     [I] Handle of open key
2060  *  lpSubKey [I] Address of name of subkey to unload
2061  *
2062  * RETURNS
2063  *  Success: ERROR_SUCCESS
2064  *  Failure: nonzero error code from Winerror.h
2065  */
2066 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2067 {
2068     DWORD ret;
2069     HKEY shkey;
2070
2071     TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));
2072
2073     ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
2074     if( ret )
2075         return ERROR_INVALID_PARAMETER;
2076
2077     ret = RtlNtStatusToDosError(NtUnloadKey(shkey));
2078
2079     RegCloseKey(shkey);
2080
2081     return ret;
2082 }
2083
2084
2085 /******************************************************************************
2086  * RegUnLoadKeyA [ADVAPI32.@]
2087  *
2088  * See RegUnLoadKeyW.
2089  */
2090 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2091 {
2092     UNICODE_STRING lpSubKeyW;
2093     LONG ret;
2094
2095     RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2096     ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
2097     RtlFreeUnicodeString( &lpSubKeyW );
2098     return ret;
2099 }
2100
2101
2102 /******************************************************************************
2103  * RegReplaceKeyW [ADVAPI32.@]
2104  *
2105  * Replace the file backing a registry key and all its subkeys with another file.
2106  *
2107  * PARAMS
2108  *  hkey      [I] Handle of open key
2109  *  lpSubKey  [I] Address of name of subkey
2110  *  lpNewFile [I] Address of filename for file with new data
2111  *  lpOldFile [I] Address of filename for backup file
2112  *
2113  * RETURNS
2114  *  Success: ERROR_SUCCESS
2115  *  Failure: nonzero error code from Winerror.h
2116  */
2117 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2118                               LPCWSTR lpOldFile )
2119 {
2120     FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2121           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2122     return ERROR_SUCCESS;
2123 }
2124
2125
2126 /******************************************************************************
2127  * RegReplaceKeyA [ADVAPI32.@]
2128  *
2129  * See RegReplaceKeyW.
2130  */
2131 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2132                               LPCSTR lpOldFile )
2133 {
2134     UNICODE_STRING lpSubKeyW;
2135     UNICODE_STRING lpNewFileW;
2136     UNICODE_STRING lpOldFileW;
2137     LONG ret;
2138
2139     RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
2140     RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
2141     RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
2142     ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
2143     RtlFreeUnicodeString( &lpOldFileW );
2144     RtlFreeUnicodeString( &lpNewFileW );
2145     RtlFreeUnicodeString( &lpSubKeyW );
2146     return ret;
2147 }
2148
2149
2150 /******************************************************************************
2151  * RegSetKeySecurity [ADVAPI32.@]
2152  *
2153  * Set the security of an open registry key.
2154  *
2155  * PARAMS
2156  *  hkey          [I] Open handle of key to set
2157  *  SecurityInfo  [I] Descriptor contents
2158  *  pSecurityDesc [I] Address of descriptor for key
2159  *
2160  * RETURNS
2161  *  Success: ERROR_SUCCESS
2162  *  Failure: nonzero error code from Winerror.h
2163  */
2164 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2165                                PSECURITY_DESCRIPTOR pSecurityDesc )
2166 {
2167     TRACE("(%p,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2168
2169     /* It seems to perform this check before the hkey check */
2170     if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
2171         (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
2172         (SecurityInfo & DACL_SECURITY_INFORMATION) ||
2173         (SecurityInfo & SACL_SECURITY_INFORMATION)) {
2174         /* Param OK */
2175     } else
2176         return ERROR_INVALID_PARAMETER;
2177
2178     if (!pSecurityDesc)
2179         return ERROR_INVALID_PARAMETER;
2180
2181     FIXME(":(%p,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2182
2183     return ERROR_SUCCESS;
2184 }
2185
2186
2187 /******************************************************************************
2188  * RegGetKeySecurity [ADVAPI32.@]
2189  *
2190  * Get a copy of the security descriptor for a given registry key.
2191  *
2192  * PARAMS
2193  *  hkey                   [I]   Open handle of key to set
2194  *  SecurityInformation    [I]   Descriptor contents
2195  *  pSecurityDescriptor    [O]   Address of descriptor for key
2196  *  lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2197  *
2198  * RETURNS
2199  *  Success: ERROR_SUCCESS
2200  *  Failure: Error code
2201  */
2202 LONG WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2203                                PSECURITY_DESCRIPTOR pSecurityDescriptor,
2204                                LPDWORD lpcbSecurityDescriptor )
2205 {
2206     TRACE("(%p,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
2207           lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
2208
2209     /* FIXME: Check for valid SecurityInformation values */
2210
2211     if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
2212         return ERROR_INSUFFICIENT_BUFFER;
2213
2214     FIXME("(%p,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
2215           pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
2216
2217     /* Do not leave security descriptor filled with garbage */
2218     RtlCreateSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2219
2220     return ERROR_SUCCESS;
2221 }
2222
2223
2224 /******************************************************************************
2225  * RegFlushKey [ADVAPI32.@]
2226  * 
2227  * Immediately write a registry key to registry.
2228  *
2229  * PARAMS
2230  *  hkey [I] Handle of key to write
2231  *
2232  * RETURNS
2233  *  Success: ERROR_SUCCESS
2234  *  Failure: Error code
2235  */
2236 DWORD WINAPI RegFlushKey( HKEY hkey )
2237 {
2238     hkey = get_special_root_hkey( hkey );
2239     if (!hkey) return ERROR_INVALID_HANDLE;
2240
2241     return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2242 }
2243
2244
2245 /******************************************************************************
2246  * RegConnectRegistryW [ADVAPI32.@]
2247  *
2248  * Establishe a connection to a predefined registry key on another computer.
2249  *
2250  * PARAMS
2251  *  lpMachineName [I] Address of name of remote computer
2252  *  hHey          [I] Predefined registry handle
2253  *  phkResult     [I] Address of buffer for remote registry handle
2254  *
2255  * RETURNS
2256  *  Success: ERROR_SUCCESS
2257  *  Failure: nonzero error code from Winerror.h
2258  */
2259 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2260                                    PHKEY phkResult )
2261 {
2262     LONG ret;
2263
2264     TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2265
2266     if (!lpMachineName || !*lpMachineName) {
2267         /* Use the local machine name */
2268         ret = RegOpenKeyW( hKey, NULL, phkResult );
2269     }
2270     else {
2271         WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
2272         DWORD len = sizeof(compName) / sizeof(WCHAR);
2273
2274         /* MSDN says lpMachineName must start with \\ : not so */
2275         if( lpMachineName[0] == '\\' &&  lpMachineName[1] == '\\')
2276             lpMachineName += 2;
2277         if (GetComputerNameW(compName, &len))
2278         {
2279             if (!strcmpiW(lpMachineName, compName))
2280                 ret = RegOpenKeyW(hKey, NULL, phkResult);
2281             else
2282             {
2283                 FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2284                 ret = ERROR_BAD_NETPATH;
2285             }
2286         }
2287         else
2288             ret = GetLastError();
2289     }
2290     return ret;
2291 }
2292
2293
2294 /******************************************************************************
2295  * RegConnectRegistryA [ADVAPI32.@]
2296  *
2297  * See RegConnectRegistryW.
2298  */
2299 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2300 {
2301     UNICODE_STRING machineW;
2302     LONG ret;
2303
2304     RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
2305     ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
2306     RtlFreeUnicodeString( &machineW );
2307     return ret;
2308 }
2309
2310
2311 /******************************************************************************
2312  * RegNotifyChangeKeyValue [ADVAPI32.@]
2313  *
2314  * Notify the caller about changes to the attributes or contents of a registry key.
2315  *
2316  * PARAMS
2317  *  hkey            [I] Handle of key to watch
2318  *  fWatchSubTree   [I] Flag for subkey notification
2319  *  fdwNotifyFilter [I] Changes to be reported
2320  *  hEvent          [I] Handle of signaled event
2321  *  fAsync          [I] Flag for asynchronous reporting
2322  *
2323  * RETURNS
2324  *  Success: ERROR_SUCCESS
2325  *  Failure: nonzero error code from Winerror.h
2326  */
2327 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2328                                      DWORD fdwNotifyFilter, HANDLE hEvent,
2329                                      BOOL fAsync )
2330 {
2331     NTSTATUS status;
2332     IO_STATUS_BLOCK iosb;
2333
2334     hkey = get_special_root_hkey( hkey );
2335     if (!hkey) return ERROR_INVALID_HANDLE;
2336
2337     TRACE("(%p,%i,%ld,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2338           hEvent, fAsync);
2339
2340     status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2341                                 fdwNotifyFilter, fAsync, NULL, 0,
2342                                 fWatchSubTree);
2343
2344     if (status && status != STATUS_TIMEOUT)
2345         return RtlNtStatusToDosError( status );
2346
2347     return ERROR_SUCCESS;
2348 }
2349
2350 /******************************************************************************
2351  * RegOpenUserClassesRoot [ADVAPI32.@]
2352  *
2353  * Open the HKEY_CLASSES_ROOT key for a user.
2354  *
2355  * PARAMS
2356  *  hToken     [I] Handle of token representing the user
2357  *  dwOptions  [I] Reserved, nust be 0
2358  *  samDesired [I] Desired access rights
2359  *  phkResult  [O] Destination for the resulting key handle
2360  *
2361  * RETURNS
2362  *  Success: ERROR_SUCCESS
2363  *  Failure: nonzero error code from Winerror.h
2364  * 
2365  * NOTES
2366  *  On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
2367  *  "HKEY_LOCAL_MACHINE\Software\Classes" and the
2368  *  "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2369  */
2370 LONG WINAPI RegOpenUserClassesRoot(
2371     HANDLE hToken,
2372     DWORD dwOptions,
2373     REGSAM samDesired,
2374     PHKEY phkResult
2375 )
2376 {
2377     FIXME("(%p, 0x%lx, 0x%lx, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2378
2379     *phkResult = HKEY_CLASSES_ROOT;
2380     return ERROR_SUCCESS;
2381 }
2382
2383 /******************************************************************************
2384  * load_string [Internal]
2385  *
2386  * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
2387  * avoid importing user32, which is higher level than advapi32. Helper for
2388  * RegLoadMUIString.
2389  */
2390 static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
2391 {
2392     HGLOBAL hMemory;
2393     HRSRC hResource;
2394     WCHAR *pString;
2395     int idxString;
2396
2397     /* Negative values have to be inverted. */
2398     if (HIWORD(resId) == 0xffff)
2399         resId = (UINT)(-((INT)resId));
2400
2401     /* Load the resource into memory and get a pointer to it. */
2402     hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
2403     if (!hResource) return 0;
2404     hMemory = LoadResource(hModule, hResource);
2405     if (!hMemory) return 0;
2406     pString = LockResource(hMemory);
2407
2408     /* Strings are length-prefixed. Lowest nibble of resId is an index. */
2409     idxString = resId & 0xf;
2410     while (idxString--) pString += *pString + 1;
2411
2412     /* If no buffer is given, return length of the string. */
2413     if (!pwszBuffer) return *pString;
2414
2415     /* Else copy over the string, respecting the buffer size. */
2416     cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
2417     if (cMaxChars >= 0) {
2418         memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
2419         pwszBuffer[cMaxChars] = '\0';
2420     }
2421
2422     return cMaxChars;
2423 }
2424
2425 /******************************************************************************
2426  * RegLoadMUIStringW [ADVAPI32.@]
2427  *
2428  * Load the localized version of a string resource from some PE, respective 
2429  * id and path of which are given in the registry value in the format 
2430  * @[path]\dllname,-resourceId
2431  *
2432  * PARAMS
2433  *  hKey       [I] Key, of which to load the string value from.
2434  *  pszValue   [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
2435  *  pszBuffer  [O] Buffer to store the localized string in. 
2436  *  cbBuffer   [I] Size of the destination buffer in bytes.
2437  *  pcbData    [O] Number of bytes written to pszBuffer (optional, may be NULL).
2438  *  dwFlags    [I] None supported yet.
2439  *  pszBaseDir [I] Not supported yet.
2440  *
2441  * RETURNS
2442  *  Success: ERROR_SUCCESS,
2443  *  Failure: nonzero error code from winerror.h
2444  *
2445  * NOTES
2446  *  This is an API of Windows Vista, which wasn't available at the time this code
2447  *  was written. We have to check for the correct behaviour once it's available. 
2448  */
2449 LONG WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2450     LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
2451 {
2452     DWORD dwValueType, cbData;
2453     LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
2454     LONG result;
2455         
2456     TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %ld, pcbData = %p, "
2457           "dwFlags = %ld, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer, 
2458           cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));
2459
2460     /* Parameter sanity checks. */
2461     if (!hKey || !pwszBuffer)
2462         return ERROR_INVALID_PARAMETER;
2463
2464     if (pwszBaseDir && *pwszBaseDir) {
2465         FIXME("BaseDir parameter not yet supported!\n");
2466         return ERROR_INVALID_PARAMETER;
2467     }
2468
2469     /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
2470     result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
2471     if (result != ERROR_SUCCESS) goto cleanup;
2472     if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
2473         result = ERROR_FILE_NOT_FOUND;
2474         goto cleanup;
2475     }
2476     pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2477     if (!pwszTempBuffer) {
2478         result = ERROR_NOT_ENOUGH_MEMORY;
2479         goto cleanup;
2480     }
2481     result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
2482     if (result != ERROR_SUCCESS) goto cleanup;
2483
2484     /* Expand environment variables, if appropriate, or copy the original string over. */
2485     if (dwValueType == REG_EXPAND_SZ) {
2486         cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
2487         if (!cbData) goto cleanup;
2488         pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2489         if (!pwszExpandedBuffer) {
2490             result = ERROR_NOT_ENOUGH_MEMORY;
2491             goto cleanup;
2492         }
2493         ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
2494     } else {
2495         pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
2496         memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
2497     }
2498
2499     /* If the value references a resource based string, parse the value and load the string.
2500      * Else just copy over the original value. */
2501     result = ERROR_SUCCESS;
2502     if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
2503         lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
2504     } else {
2505         WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
2506         UINT uiStringId;
2507         HMODULE hModule;
2508
2509         /* Format of the expanded value is 'path_to_dll,-resId' */
2510         if (!pComma || pComma[1] != '-') {
2511             result = ERROR_BADKEY;
2512             goto cleanup;
2513         }
2514  
2515         uiStringId = atoiW(pComma+2);
2516         *pComma = '\0';
2517
2518         hModule = LoadLibraryW(pwszExpandedBuffer + 1);
2519         if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
2520             result = ERROR_BADKEY;
2521         FreeLibrary(hModule);
2522     }
2523  
2524 cleanup:
2525     HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
2526     HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
2527     return result;
2528 }
2529
2530 /******************************************************************************
2531  * RegLoadMUIStringA [ADVAPI32.@]
2532  *
2533  * See RegLoadMUIStringW
2534  */
2535 LONG WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2536     LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
2537 {
2538     UNICODE_STRING valueW, baseDirW;
2539     WCHAR *pwszBuffer;
2540     DWORD cbData = cbBuffer * sizeof(WCHAR);
2541     LONG result;
2542
2543     valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
2544     if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
2545         !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
2546         !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
2547     {
2548         result = ERROR_NOT_ENOUGH_MEMORY;
2549         goto cleanup;
2550     }
2551
2552     result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags, 
2553                                baseDirW.Buffer);
2554  
2555     if (result == ERROR_SUCCESS) {
2556         cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
2557         if (pcbData)
2558             *pcbData = cbData;
2559     }
2560
2561 cleanup:
2562     HeapFree(GetProcessHeap(), 0, pwszBuffer);
2563     RtlFreeUnicodeString(&baseDirW);
2564     RtlFreeUnicodeString(&valueW);
2565  
2566     return result;
2567 }