~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/advapi32/registry.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.