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

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

Version: ~ [ 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 library is free software; you can redistribute it and/or
 12  * modify it under the terms of the GNU Lesser General Public
 13  * License as published by the Free Software Foundation; either
 14  * version 2.1 of the License, or (at your option) any later version.
 15  *
 16  * This library is distributed in the hope that it will be useful,
 17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19  * Lesser General Public License for more details.
 20  *
 21  * You should have received a copy of the GNU Lesser General Public
 22  * License along with this library; if not, write to the Free Software
 23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 24  */
 25 
 26 #include <stdlib.h>
 27 #include <stdarg.h>
 28 #include <stdio.h>
 29 
 30 #include "ntstatus.h"
 31 #define WIN32_NO_STATUS
 32 #include "windef.h"
 33 #include "winbase.h"
 34 #include "winreg.h"
 35 #include "winerror.h"
 36 #include "winternl.h"
 37 #include "winuser.h"
 38 
 39 #include "wine/unicode.h"
 40 #include "wine/debug.h"
 41 
 42 WINE_DEFAULT_DEBUG_CHANNEL(reg);
 43 
 44 #define HKEY_SPECIAL_ROOT_FIRST   HKEY_CLASSES_ROOT
 45 #define HKEY_SPECIAL_ROOT_LAST    HKEY_DYN_DATA
 46 #define NB_SPECIAL_ROOT_KEYS      ((UINT_PTR)HKEY_SPECIAL_ROOT_LAST - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST + 1)
 47 
 48 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
 49 static BOOL hkcu_cache_disabled;
 50 
 51 static const WCHAR name_CLASSES_ROOT[] =
 52     {'M','a','c','h','i','n','e','\\',
 53      'S','o','f','t','w','a','r','e','\\',
 54      'C','l','a','s','s','e','s',0};
 55 static const WCHAR name_LOCAL_MACHINE[] =
 56     {'M','a','c','h','i','n','e',0};
 57 static const WCHAR name_USERS[] =
 58     {'U','s','e','r',0};
 59 static const WCHAR name_PERFORMANCE_DATA[] =
 60     {'P','e','r','f','D','a','t','a',0};
 61 static const WCHAR name_CURRENT_CONFIG[] =
 62     {'M','a','c','h','i','n','e','\\',
 63      'S','y','s','t','e','m','\\',
 64      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
 65      'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
 66      'C','u','r','r','e','n','t',0};
 67 static const WCHAR name_DYN_DATA[] =
 68     {'D','y','n','D','a','t','a',0};
 69 
 70 static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] =
 71 {
 72     name_CLASSES_ROOT,
 73     NULL,         /* HKEY_CURRENT_USER is determined dynamically */
 74     name_LOCAL_MACHINE,
 75     name_USERS,
 76     name_PERFORMANCE_DATA,
 77     name_CURRENT_CONFIG,
 78     name_DYN_DATA
 79 };
 80 
 81 
 82 /* check if value type needs string conversion (Ansi<->Unicode) */
 83 static inline int is_string( DWORD type )
 84 {
 85     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
 86 }
 87 
 88 /* check if current version is NT or Win95 */
 89 static inline int is_version_nt(void)
 90 {
 91     return !(GetVersion() & 0x80000000);
 92 }
 93 
 94 /* create one of the HKEY_* special root keys */
 95 static HKEY create_special_root_hkey( HANDLE hkey, DWORD access )
 96 {
 97     HKEY ret = 0;
 98     int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
 99 
100     if (hkey == HKEY_CURRENT_USER)
101     {
102         if (RtlOpenCurrentUser( access, &hkey )) return 0;
103         TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
104 
105         /* don't cache the key in the table if caching is disabled */
106         if (hkcu_cache_disabled)
107             return hkey;
108     }
109     else
110     {
111         OBJECT_ATTRIBUTES attr;
112         UNICODE_STRING name;
113 
114         attr.Length = sizeof(attr);
115         attr.RootDirectory = 0;
116         attr.ObjectName = &name;
117         attr.Attributes = 0;
118         attr.SecurityDescriptor = NULL;
119         attr.SecurityQualityOfService = NULL;
120         RtlInitUnicodeString( &name, root_key_names[idx] );
121         if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
122         TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
123     }
124 
125     if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
126         ret = hkey;
127     else
128         NtClose( hkey );  /* somebody beat us to it */
129     return ret;
130 }
131 
132 /* map the hkey from special root to normal key if necessary */
133 static inline HKEY get_special_root_hkey( HKEY hkey )
134 {
135     HKEY ret = hkey;
136 
137     if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
138     {
139         if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
140             ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
141     }
142     return ret;
143 }
144 
145 
146 /******************************************************************************
147  * RegOverridePredefKey   [ADVAPI32.@]
148  */
149 LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
150 {
151     HKEY old_key;
152     int idx;
153 
154     if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST))
155         return ERROR_INVALID_PARAMETER;
156     idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
157 
158     if (override)
159     {
160         NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
161                                              GetCurrentProcess(), (HANDLE *)&override,
162                                              0, 0, DUPLICATE_SAME_ACCESS );
163         if (status) return RtlNtStatusToDosError( status );
164     }
165 
166     old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
167     if (old_key) NtClose( old_key );
168     return ERROR_SUCCESS;
169 }
170 
171 
172 /******************************************************************************
173  * RegCreateKeyExW   [ADVAPI32.@]
174  *
175  * See RegCreateKeyExA.
176  */
177 LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
178                              DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
179                              PHKEY retkey, LPDWORD dispos )
180 {
181     OBJECT_ATTRIBUTES attr;
182     UNICODE_STRING nameW, classW;
183 
184     if (reserved) return ERROR_INVALID_PARAMETER;
185     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
186 
187     attr.Length = sizeof(attr);
188     attr.RootDirectory = hkey;
189     attr.ObjectName = &nameW;
190     attr.Attributes = 0;
191     attr.SecurityDescriptor = NULL;
192     attr.SecurityQualityOfService = NULL;
193     RtlInitUnicodeString( &nameW, name );
194     RtlInitUnicodeString( &classW, class );
195 
196     return RtlNtStatusToDosError( NtCreateKey( (PHANDLE)retkey, access, &attr, 0,
197                                                &classW, options, dispos ) );
198 }
199 
200 
201 /******************************************************************************
202  * RegCreateKeyExA   [ADVAPI32.@]
203  *
204  * Open a registry key, creating it if it doesn't exist.
205  *
206  * PARAMS
207  *  hkey       [I] Handle of the parent registry key
208  *  name       [I] Name of the new key to open or create
209  *  reserved   [I] Reserved, pass 0
210  *  class      [I] The object type of the new key
211  *  options    [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
212  *  access     [I] Access level desired
213  *  sa         [I] Security attributes for the key
214  *  retkey     [O] Destination for the resulting handle
215  *  dispos     [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
216  *
217  * RETURNS
218  *  Success: ERROR_SUCCESS.
219  *  Failure: A standard Win32 error code. retkey remains untouched.
220  *
221  * FIXME
222  *  MAXIMUM_ALLOWED in access mask not supported by server
223  */
224 LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
225                              DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
226                              PHKEY retkey, LPDWORD dispos )
227 {
228     OBJECT_ATTRIBUTES attr;
229     UNICODE_STRING classW;
230     ANSI_STRING nameA, classA;
231     NTSTATUS status;
232 
233     if (reserved) return ERROR_INVALID_PARAMETER;
234     if (!is_version_nt())
235     {
236         access = KEY_ALL_ACCESS;  /* Win95 ignores the access mask */
237         if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
238     }
239     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
240 
241     attr.Length = sizeof(attr);
242     attr.RootDirectory = hkey;
243     attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
244     attr.Attributes = 0;
245     attr.SecurityDescriptor = NULL;
246     attr.SecurityQualityOfService = NULL;
247     RtlInitAnsiString( &nameA, name );
248     RtlInitAnsiString( &classA, class );
249 
250     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
251                                                  &nameA, FALSE )))
252     {
253         if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
254         {
255             status = NtCreateKey( (PHANDLE)retkey, access, &attr, 0, &classW, options, dispos );
256             RtlFreeUnicodeString( &classW );
257         }
258     }
259     return RtlNtStatusToDosError( status );
260 }
261 
262 
263 /******************************************************************************
264  * RegCreateKeyW   [ADVAPI32.@]
265  *
266  * Creates the specified reg key.
267  *
268  * PARAMS
269  *  hKey      [I] Handle to an open key.
270  *  lpSubKey  [I] Name of a key that will be opened or created.
271  *  phkResult [O] Receives a handle to the opened or created key.
272  *
273  * RETURNS
274  *  Success: ERROR_SUCCESS
275  *  Failure: nonzero error code defined in Winerror.h
276  */
277 LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
278 {
279     /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
280     /* but at least my version of NT (4.0 SP5) doesn't do this.  -- AJ */
281     return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
282                             KEY_ALL_ACCESS, NULL, phkResult, NULL );
283 }
284 
285 
286 /******************************************************************************
287  * RegCreateKeyA   [ADVAPI32.@]
288  *
289  * See RegCreateKeyW.
290  */
291 LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
292 {
293     return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
294                             KEY_ALL_ACCESS, NULL, phkResult, NULL );
295 }
296 
297 
298 
299 /******************************************************************************
300  * RegOpenKeyExW   [ADVAPI32.@]
301  * 
302  * See RegOpenKeyExA.
303  */
304 LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
305 {
306     OBJECT_ATTRIBUTES attr;
307     UNICODE_STRING nameW;
308 
309     /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
310     if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
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     else
353     {
354         /* NT+ allows beginning backslash for HKEY_CLASSES_ROOT */
355         if (hkey == HKEY_CLASSES_ROOT && name && *name == '\\') name++;
356     }
357 
358     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
359 
360     attr.Length = sizeof(attr);
361     attr.RootDirectory = hkey;
362     attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
363     attr.Attributes = 0;
364     attr.SecurityDescriptor = NULL;
365     attr.SecurityQualityOfService = NULL;
366 
367     RtlInitAnsiString( &nameA, name );
368     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
369                                                  &nameA, FALSE )))
370     {
371         status = NtOpenKey( (PHANDLE)retkey, access, &attr );
372     }
373     return RtlNtStatusToDosError( status );
374 }
375 
376 
377 /******************************************************************************
378  * RegOpenKeyW   [ADVAPI32.@]
379  *
380  * See RegOpenKeyA.
381  */
382 LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
383 {
384     if (!name || !*name)
385     {
386         *retkey = hkey;
387         return ERROR_SUCCESS;
388     }
389     return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
390 }
391 
392 
393 /******************************************************************************
394  * RegOpenKeyA   [ADVAPI32.@]
395  *           
396  * Open a registry key.
397  *
398  * PARAMS
399  *  hkey    [I] Handle of parent key to open the new key under
400  *  name    [I] Name of the key under hkey to open
401  *  retkey  [O] Destination for the resulting Handle
402  *
403  * RETURNS
404  *  Success: ERROR_SUCCESS
405  *  Failure: A standard Win32 error code. retkey is set to 0.
406  */
407 LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
408 {
409     if (!name || !*name)
410     {
411         *retkey = hkey;
412         return ERROR_SUCCESS;
413     }
414     return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
415 }
416 
417 
418 /******************************************************************************
419  * RegOpenCurrentUser   [ADVAPI32.@]
420  *
421  * Get a handle to the HKEY_CURRENT_USER key for the user 
422  * the current thread is impersonating.
423  *
424  * PARAMS
425  *  access [I] Desired access rights to the key
426  *  retkey [O] Handle to the opened key
427  *
428  * RETURNS
429  *  Success: ERROR_SUCCESS
430  *  Failure: nonzero error code from Winerror.h
431  *
432  * FIXME
433  *  This function is supposed to retrieve a handle to the
434  *  HKEY_CURRENT_USER for the user the current thread is impersonating.
435  *  Since Wine does not currently allow threads to impersonate other users,
436  *  this stub should work fine.
437  */
438 LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
439 {
440     return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
441 }
442 
443 
444 
445 /******************************************************************************
446  * RegEnumKeyExW   [ADVAPI32.@]
447  *
448  * Enumerate subkeys of the specified open registry key.
449  *
450  * PARAMS
451  *  hkey         [I] Handle to key to enumerate
452  *  index        [I] Index of subkey to enumerate
453  *  name         [O] Buffer for subkey name
454  *  name_len     [O] Size of subkey buffer
455  *  reserved     [I] Reserved
456  *  class        [O] Buffer for class string
457  *  class_len    [O] Size of class buffer
458  *  ft           [O] Time key last written to
459  *
460  * RETURNS
461  *  Success: ERROR_SUCCESS
462  *  Failure: System error code. If there are no more subkeys available, the
463  *           function returns ERROR_NO_MORE_ITEMS.
464  */
465 LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len,
466                            LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft )
467 {
468     NTSTATUS status;
469     char buffer[256], *buf_ptr = buffer;
470     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
471     DWORD total_size;
472 
473     TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
474            name_len ? *name_len : 0, reserved, class, class_len, ft );
475 
476     if (reserved) return ERROR_INVALID_PARAMETER;
477     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
478 
479     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
480                              buffer, sizeof(buffer), &total_size );
481 
482     while (status == STATUS_BUFFER_OVERFLOW)
483     {
484         /* retry with a dynamically allocated buffer */
485         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
486         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
487             return ERROR_NOT_ENOUGH_MEMORY;
488         info = (KEY_NODE_INFORMATION *)buf_ptr;
489         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
490                                  buf_ptr, total_size, &total_size );
491     }
492 
493     if (!status)
494     {
495         DWORD len = info->NameLength / sizeof(WCHAR);
496         DWORD cls_len = info->ClassLength / sizeof(WCHAR);
497 
498         if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
499 
500         if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
501             status = STATUS_BUFFER_OVERFLOW;
502         else
503         {
504             *name_len = len;
505             memcpy( name, info->Name, info->NameLength );
506             name[len] = 0;
507             if (class_len)
508             {
509                 *class_len = cls_len;
510                 if (class)
511                 {
512                     memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
513                     class[cls_len] = 0;
514                 }
515             }
516         }
517     }
518 
519     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
520     return RtlNtStatusToDosError( status );
521 }
522 
523 
524 /******************************************************************************
525  * RegEnumKeyExA   [ADVAPI32.@]
526  *
527  * See RegEnumKeyExW.
528  */
529 LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len,
530                            LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft )
531 {
532     NTSTATUS status;
533     char buffer[256], *buf_ptr = buffer;
534     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
535     DWORD total_size;
536 
537     TRACE( "(%p,%d,%p,%p(%u),%p,%p,%p,%p)\n", hkey, index, name, name_len,
538            name_len ? *name_len : 0, reserved, class, class_len, ft );
539 
540     if (reserved) return ERROR_INVALID_PARAMETER;
541     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
542 
543     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
544                              buffer, sizeof(buffer), &total_size );
545 
546     while (status == STATUS_BUFFER_OVERFLOW)
547     {
548         /* retry with a dynamically allocated buffer */
549         if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
550         if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
551             return ERROR_NOT_ENOUGH_MEMORY;
552         info = (KEY_NODE_INFORMATION *)buf_ptr;
553         status = NtEnumerateKey( hkey, index, KeyNodeInformation,
554                                  buf_ptr, total_size, &total_size );
555     }
556 
557     if (!status)
558     {
559         DWORD len, cls_len;
560 
561         RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
562         RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
563                                    info->ClassLength );
564         if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
565 
566         if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
567             status = STATUS_BUFFER_OVERFLOW;
568         else
569         {
570             *name_len = len;
571             RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
572             name[len] = 0;
573             if (class_len)
574             {
575                 *class_len = cls_len;
576                 if (class)
577                 {
578                     RtlUnicodeToMultiByteN( class, cls_len, NULL,
579                                             (WCHAR *)(buf_ptr + info->ClassOffset),
580                                             info->ClassLength );
581                     class[cls_len] = 0;
582                 }
583             }
584         }
585     }
586 
587     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
588     return RtlNtStatusToDosError( status );
589 }
590 
591 
592 /******************************************************************************
593  * RegEnumKeyW   [ADVAPI32.@]
594  *
595  * Enumerates subkeys of the specified open reg key.
596  *
597  * PARAMS
598  *  hKey    [I] Handle to an open key.
599  *  dwIndex [I] Index of the subkey of hKey to retrieve.
600  *  lpName  [O] Name of the subkey.
601  *  cchName [I] Size of lpName in TCHARS.
602  *
603  * RETURNS
604  *  Success: ERROR_SUCCESS
605  *  Failure: system error code. If there are no more subkeys available, the
606  *           function returns ERROR_NO_MORE_ITEMS.
607  */
608 LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
609 {
610     return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
611 }
612 
613 
614 /******************************************************************************
615  * RegEnumKeyA   [ADVAPI32.@]
616  *
617  * See RegEnumKeyW.
618  */
619 LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
620 {
621     return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
622 }
623 
624 
625 /******************************************************************************
626  * RegQueryInfoKeyW   [ADVAPI32.@]
627  *
628  * Retrieves information about the specified registry key.
629  *
630  * PARAMS
631  *    hkey       [I] Handle to key to query
632  *    class      [O] Buffer for class string
633  *    class_len  [O] Size of class string buffer
634  *    reserved   [I] Reserved
635  *    subkeys    [O] Buffer for number of subkeys
636  *    max_subkey [O] Buffer for longest subkey name length
637  *    max_class  [O] Buffer for longest class string length
638  *    values     [O] Buffer for number of value entries
639  *    max_value  [O] Buffer for longest value name length
640  *    max_data   [O] Buffer for longest value data length
641  *    security   [O] Buffer for security descriptor length
642  *    modif      [O] Modification time
643  *
644  * RETURNS
645  *  Success: ERROR_SUCCESS
646  *  Failure: system error code.
647  *
648  * NOTES
649  *  - win95 allows class to be valid and class_len to be NULL
650  *  - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
651  *  - both allow class to be NULL and class_len to be NULL
652  *    (it's hard to test validity, so test !NULL instead)
653  */
654 LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWORD reserved,
655                               LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
656                               LPDWORD values, LPDWORD max_value, LPDWORD max_data,
657                               LPDWORD security, FILETIME *modif )
658 {
659     NTSTATUS status;
660     char buffer[256], *buf_ptr = buffer;
661     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
662     DWORD total_size;
663 
664     TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
665            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
666 
667     if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
668     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
669 
670     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
671     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
672 
673     if (class)
674     {
675         /* retry with a dynamically allocated buffer */
676         while (status == STATUS_BUFFER_OVERFLOW)
677         {
678             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
679             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
680                 return ERROR_NOT_ENOUGH_MEMORY;
681             info = (KEY_FULL_INFORMATION *)buf_ptr;
682             status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
683         }
684 
685         if (status) goto done;
686 
687         if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
688         {
689             status = STATUS_BUFFER_OVERFLOW;
690         }
691         else
692         {
693             memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
694             class[info->ClassLength/sizeof(WCHAR)] = 0;
695         }
696     }
697     else status = STATUS_SUCCESS;
698 
699     if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
700     if (subkeys) *subkeys = info->SubKeys;
701     if (max_subkey) *max_subkey = info->MaxNameLen;
702     if (max_class) *max_class = info->MaxClassLen;
703     if (values) *values = info->Values;
704     if (max_value) *max_value = info->MaxValueNameLen;
705     if (max_data) *max_data = info->MaxValueDataLen;
706     if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
707 
708  done:
709     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
710     return RtlNtStatusToDosError( status );
711 }
712 
713 
714 /******************************************************************************
715  * RegQueryMultipleValuesA   [ADVAPI32.@]
716  *
717  * Retrieves the type and data for a list of value names associated with a key.
718  *
719  * PARAMS
720  *  hKey       [I] Handle to an open key.
721  *  val_list   [O] Array of VALENT structures that describes the entries.
722  *  num_vals   [I] Number of elements in val_list.
723  *  lpValueBuf [O] Pointer to a buffer that receives the data for each value.
724  *  ldwTotsize [I/O] Size of lpValueBuf.
725  *
726  * RETURNS
727  *  Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
728  *  Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
729  *           bytes.
730  */
731 LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals,
732                                      LPSTR lpValueBuf, LPDWORD ldwTotsize )
733 {
734     unsigned int i;
735     DWORD maxBytes = *ldwTotsize;
736     HRESULT status;
737     LPSTR bufptr = lpValueBuf;
738     *ldwTotsize = 0;
739 
740     TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
741 
742     for(i=0; i < num_vals; ++i)
743     {
744 
745         val_list[i].ve_valuelen=0;
746         status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
747         if(status != ERROR_SUCCESS)
748         {
749             return status;
750         }
751 
752         if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
753         {
754             status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
755                                       (LPBYTE)bufptr, &val_list[i].ve_valuelen);
756             if(status != ERROR_SUCCESS)
757             {
758                 return status;
759             }
760 
761             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
762 
763             bufptr += val_list[i].ve_valuelen;
764         }
765 
766         *ldwTotsize += val_list[i].ve_valuelen;
767     }
768     return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
769 }
770 
771 
772 /******************************************************************************
773  * RegQueryMultipleValuesW   [ADVAPI32.@]
774  *
775  * See RegQueryMultipleValuesA.
776  */
777 LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals,
778                                      LPWSTR lpValueBuf, LPDWORD ldwTotsize )
779 {
780     unsigned int i;
781     DWORD maxBytes = *ldwTotsize;
782     HRESULT status;
783     LPSTR bufptr = (LPSTR)lpValueBuf;
784     *ldwTotsize = 0;
785 
786     TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
787 
788     for(i=0; i < num_vals; ++i)
789     {
790         val_list[i].ve_valuelen=0;
791         status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
792         if(status != ERROR_SUCCESS)
793         {
794             return status;
795         }
796 
797         if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
798         {
799             status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
800                                       (LPBYTE)bufptr, &val_list[i].ve_valuelen);
801             if(status != ERROR_SUCCESS)
802             {
803                 return status;
804             }
805 
806             val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
807 
808             bufptr += val_list[i].ve_valuelen;
809         }
810 
811         *ldwTotsize += val_list[i].ve_valuelen;
812     }
813     return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
814 }
815 
816 /******************************************************************************
817  * RegQueryInfoKeyA   [ADVAPI32.@]
818  *
819  * Retrieves information about a registry key.
820  *
821  * PARAMS
822  *  hKey                   [I] Handle to an open key.
823  *  lpClass                [O] Class string of the key.
824  *  lpcClass               [I/O] size of lpClass.
825  *  lpReserved             [I] Reserved; must be NULL.
826  *  lpcSubKeys             [O] Number of subkeys contained by the key.
827  *  lpcMaxSubKeyLen        [O] Size of the key's subkey with the longest name.
828  *  lpcMaxClassLen         [O] Size of the longest string specifying a subkey
829  *                             class in TCHARS.
830  *  lpcValues              [O] Number of values associated with the key.
831  *  lpcMaxValueNameLen     [O] Size of the key's longest value name in TCHARS.
832  *  lpcMaxValueLen         [O] Longest data component among the key's values
833  *  lpcbSecurityDescriptor [O] Size of the key's security descriptor.
834  *  lpftLastWriteTime      [O] FILETIME structure that is the last write time.
835  *
836  *  RETURNS
837  *   Success: ERROR_SUCCESS
838  *   Failure: nonzero error code from Winerror.h
839  */
840 LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
841                               LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
842                               LPDWORD values, LPDWORD max_value, LPDWORD max_data,
843                               LPDWORD security, FILETIME *modif )
844 {
845     NTSTATUS status;
846     char buffer[256], *buf_ptr = buffer;
847     KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
848     DWORD total_size, len;
849 
850     TRACE( "(%p,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0,
851            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
852 
853     if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
854     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
855 
856     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
857     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
858 
859     if (class || class_len)
860     {
861         /* retry with a dynamically allocated buffer */
862         while (status == STATUS_BUFFER_OVERFLOW)
863         {
864             if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
865             if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
866                 return ERROR_NOT_ENOUGH_MEMORY;
867             info = (KEY_FULL_INFORMATION *)buf_ptr;
868             status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
869         }
870 
871         if (status) goto done;
872 
873         RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
874         if (class_len)
875         {
876             if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
877             *class_len = len;
878         }
879         if (class && !status)
880         {
881             RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
882                                     info->ClassLength );
883             class[len] = 0;
884         }
885     }
886     else status = STATUS_SUCCESS;
887 
888     if (subkeys) *subkeys = info->SubKeys;
889     if (max_subkey) *max_subkey = info->MaxNameLen;
890     if (max_class) *max_class = info->MaxClassLen;
891     if (values) *values = info->Values;
892     if (max_value) *max_value = info->MaxValueNameLen;
893     if (max_data) *max_data = info->MaxValueDataLen;
894     if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
895 
896  done:
897     if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
898     return RtlNtStatusToDosError( status );
899 }
900 
901 
902 /******************************************************************************
903  * RegCloseKey   [ADVAPI32.@]
904  *
905  * Close an open registry key.
906  *
907  * PARAMS
908  *  hkey [I] Handle of key to close
909  *
910  * RETURNS
911  *  Success: ERROR_SUCCESS
912  *  Failure: Error code
913  */
914 LSTATUS WINAPI RegCloseKey( HKEY hkey )
915 {
916     if (!hkey) return ERROR_INVALID_HANDLE;
917     if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
918     return RtlNtStatusToDosError( NtClose( hkey ) );
919 }
920 
921 
922 /******************************************************************************
923  * RegDeleteKeyW   [ADVAPI32.@]
924  *
925  * See RegDeleteKeyA.
926  */
927 LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
928 {
929     DWORD ret;
930     HKEY tmp;
931 
932     if (!name) return ERROR_INVALID_PARAMETER;
933 
934     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
935 
936     if (!(ret = RegOpenKeyExW( hkey, name, 0, DELETE, &tmp )))
937     {
938         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
939         RegCloseKey( tmp );
940     }
941     TRACE("%s ret=%08x\n", debugstr_w(name), ret);
942     return ret;
943 }
944 
945 
946 /******************************************************************************
947  * RegDeleteKeyA   [ADVAPI32.@]
948  *
949  * Delete a registry key.
950  *
951  * PARAMS
952  *  hkey   [I] Handle to parent key containing the key to delete
953  *  name   [I] Name of the key user hkey to delete
954  *
955  * NOTES
956  *
957  * MSDN is wrong when it says that hkey must be opened with the DELETE access
958  * right. In reality, it opens a new handle with DELETE access.
959  *
960  * RETURNS
961  *  Success: ERROR_SUCCESS
962  *  Failure: Error code
963  */
964 LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
965 {
966     DWORD ret;
967     HKEY tmp;
968 
969     if (!name) return ERROR_INVALID_PARAMETER;
970 
971     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;