registry.c 90 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * Registry management
 *
 * Copyright (C) 1999 Alexandre Julliard
 *
 * Based on misc/registry.c code
 * Copyright (C) 1996 Marcus Meissner
 * Copyright (C) 1998 Matthew Becker
 * Copyright (C) 1999 Sylvain St-Germain
 *
 * This file is concerned about handle management and interaction with the Wine server.
 * Registry file I/O is in misc/registry.c.
13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 34
#include "ntstatus.h"
#define WIN32_NO_STATUS
35
#include "windef.h"
36 37 38
#include "winbase.h"
#include "winreg.h"
#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 48 49 50 51 52 53 54
/* allowed bits for access mask */
#define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)

#define HKEY_SPECIAL_ROOT_FIRST   HKEY_CLASSES_ROOT
#define HKEY_SPECIAL_ROOT_LAST    HKEY_DYN_DATA
#define NB_SPECIAL_ROOT_KEYS      ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)

static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
55
static BOOL hkcu_cache_disabled;
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

static const WCHAR name_CLASSES_ROOT[] =
    {'M','a','c','h','i','n','e','\\',
     'S','o','f','t','w','a','r','e','\\',
     'C','l','a','s','s','e','s',0};
static const WCHAR name_LOCAL_MACHINE[] =
    {'M','a','c','h','i','n','e',0};
static const WCHAR name_USERS[] =
    {'U','s','e','r',0};
static const WCHAR name_PERFORMANCE_DATA[] =
    {'P','e','r','f','D','a','t','a',0};
static const WCHAR name_CURRENT_CONFIG[] =
    {'M','a','c','h','i','n','e','\\',
     'S','y','s','t','e','m','\\',
     'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
71
     'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
72 73 74 75
     'C','u','r','r','e','n','t',0};
static const WCHAR name_DYN_DATA[] =
    {'D','y','n','D','a','t','a',0};

76
static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] =
77
{
78 79 80 81 82 83 84
    name_CLASSES_ROOT,
    NULL,         /* HKEY_CURRENT_USER is determined dynamically */
    name_LOCAL_MACHINE,
    name_USERS,
    name_PERFORMANCE_DATA,
    name_CURRENT_CONFIG,
    name_DYN_DATA
85 86
};

87 88

/* check if value type needs string conversion (Ansi<->Unicode) */
89
static inline int is_string( DWORD type )
90 91 92 93
{
    return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
}

94
/* check if current version is NT or Win95 */
95
static inline int is_version_nt(void)
96 97 98
{
    return !(GetVersion() & 0x80000000);
}
99

100
/* create one of the HKEY_* special root keys */
101
static HKEY create_special_root_hkey( HANDLE hkey, DWORD access )
102 103
{
    HKEY ret = 0;
104
    int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
105 106 107 108

    if (hkey == HKEY_CURRENT_USER)
    {
        if (RtlOpenCurrentUser( access, &hkey )) return 0;
109
        TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
110 111 112 113

        /* don't cache the key in the table if caching is disabled */
        if (hkcu_cache_disabled)
            return hkey;
114 115 116 117
    }
    else
    {
        OBJECT_ATTRIBUTES attr;
118
        UNICODE_STRING name;
119 120 121

        attr.Length = sizeof(attr);
        attr.RootDirectory = 0;
122
        attr.ObjectName = &name;
123 124 125
        attr.Attributes = 0;
        attr.SecurityDescriptor = NULL;
        attr.SecurityQualityOfService = NULL;
126
        RtlInitUnicodeString( &name, root_key_names[idx] );
127
        if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
128
        TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
129 130
    }

131
    if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
132 133 134 135 136 137 138
        ret = hkey;
    else
        NtClose( hkey );  /* somebody beat us to it */
    return ret;
}

/* map the hkey from special root to normal key if necessary */
139
static inline HKEY get_special_root_hkey( HKEY hkey )
140 141 142 143 144
{
    HKEY ret = hkey;

    if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
    {
145
        if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
146 147 148 149 150
            ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
    }
    return ret;
}

151

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
/******************************************************************************
 * RegOverridePredefKey   [ADVAPI32.@]
 */
LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override )
{
    HKEY old_key;
    int idx;

    if ((hkey < HKEY_SPECIAL_ROOT_FIRST) || (hkey > HKEY_SPECIAL_ROOT_LAST))
        return ERROR_INVALID_PARAMETER;
    idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;

    if (override)
    {
        NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), override,
                                             GetCurrentProcess(), (HANDLE *)&override,
                                             0, 0, DUPLICATE_SAME_ACCESS );
        if (status) return RtlNtStatusToDosError( status );
    }

    old_key = InterlockedExchangePointer( (void **)&special_root_keys[idx], override );
    if (old_key) NtClose( old_key );
    return ERROR_SUCCESS;
}


178
/******************************************************************************
179
 * RegCreateKeyExW   [ADVAPI32.@]
180
 *
Jon Griffiths's avatar
Jon Griffiths committed
181
 * See RegCreateKeyExA.
182
 */
183
LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class,
184 185
                             DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
                             PHKEY retkey, LPDWORD dispos )
186
{
187 188
    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING nameW, classW;
189 190

    if (reserved) return ERROR_INVALID_PARAMETER;
191
    if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
192
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
193

194 195 196 197 198 199 200 201 202
    attr.Length = sizeof(attr);
    attr.RootDirectory = hkey;
    attr.ObjectName = &nameW;
    attr.Attributes = 0;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;
    RtlInitUnicodeString( &nameW, name );
    RtlInitUnicodeString( &classW, class );

203
    return RtlNtStatusToDosError( NtCreateKey( (PHANDLE)retkey, access, &attr, 0,
204
                                               &classW, options, dispos ) );
205 206 207 208
}


/******************************************************************************
209
 * RegCreateKeyExA   [ADVAPI32.@]
210
 *
Jon Griffiths's avatar
Jon Griffiths committed
211 212 213
 * Open a registry key, creating it if it doesn't exist.
 *
 * PARAMS
214 215 216 217 218 219 220 221 222
 *  hkey       [I] Handle of the parent registry key
 *  name       [I] Name of the new key to open or create
 *  reserved   [I] Reserved, pass 0
 *  class      [I] The object type of the new key
 *  options    [I] Flags controlling the key creation (REG_OPTION_* flags from "winnt.h")
 *  access     [I] Access level desired
 *  sa         [I] Security attributes for the key
 *  retkey     [O] Destination for the resulting handle
 *  dispos     [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
Jon Griffiths's avatar
Jon Griffiths committed
223 224
 *
 * RETURNS
225 226
 *  Success: ERROR_SUCCESS.
 *  Failure: A standard Win32 error code. retkey remains untouched.
Jon Griffiths's avatar
Jon Griffiths committed
227 228
 *
 * FIXME
229
 *  MAXIMUM_ALLOWED in access mask not supported by server
230
 */
231
LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class,
232 233
                             DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa,
                             PHKEY retkey, LPDWORD dispos )
234
{
235
    OBJECT_ATTRIBUTES attr;
236
    UNICODE_STRING classW;
237 238
    ANSI_STRING nameA, classA;
    NTSTATUS status;
239 240

    if (reserved) return ERROR_INVALID_PARAMETER;
241 242 243 244 245
    if (!is_version_nt())
    {
        access = KEY_ALL_ACCESS;  /* Win95 ignores the access mask */
        if (name && *name == '\\') name++; /* win9x,ME ignores one (and only one) beginning backslash */
    }
246
    else if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
247
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
248

249 250
    attr.Length = sizeof(attr);
    attr.RootDirectory = hkey;
251
    attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
252 253 254 255 256 257
    attr.Attributes = 0;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;
    RtlInitAnsiString( &nameA, name );
    RtlInitAnsiString( &classA, class );

258 259
    if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
                                                 &nameA, FALSE )))
260
    {
261 262
        if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
        {
263
            status = NtCreateKey( (PHANDLE)retkey, access, &attr, 0, &classW, options, dispos );
264 265
            RtlFreeUnicodeString( &classW );
        }
266
    }
267
    return RtlNtStatusToDosError( status );
268 269 270 271
}


/******************************************************************************
272 273 274 275 276 277 278 279 280 281 282 283
 * RegCreateKeyW   [ADVAPI32.@]
 *
 * Creates the specified reg key.
 *
 * PARAMS
 *  hKey      [I] Handle to an open key.
 *  lpSubKey  [I] Name of a key that will be opened or created.
 *  phkResult [O] Receives a handle to the opened or created key.
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code defined in Winerror.h
284
 */
285
LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult )
286 287 288
{
    /* FIXME: previous implementation converted ERROR_INVALID_HANDLE to ERROR_BADKEY, */
    /* but at least my version of NT (4.0 SP5) doesn't do this.  -- AJ */
289 290
    return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
                            KEY_ALL_ACCESS, NULL, phkResult, NULL );
291 292 293 294
}


/******************************************************************************
295 296
 * RegCreateKeyA   [ADVAPI32.@]
 *
297
 * See RegCreateKeyW.
298
 */
299
LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult )
300
{
301 302
    return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
                            KEY_ALL_ACCESS, NULL, phkResult, NULL );
303 304 305 306 307
}



/******************************************************************************
308 309
 * RegOpenKeyExW   [ADVAPI32.@]
 * 
Jon Griffiths's avatar
Jon Griffiths committed
310
 * See RegOpenKeyExA.
311
 */
312
LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
313
{
314 315 316
    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING nameW;

317 318
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

319 320 321 322 323 324 325
    attr.Length = sizeof(attr);
    attr.RootDirectory = hkey;
    attr.ObjectName = &nameW;
    attr.Attributes = 0;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;
    RtlInitUnicodeString( &nameW, name );
326
    return RtlNtStatusToDosError( NtOpenKey( (PHANDLE)retkey, access, &attr ) );
327 328 329 330
}


/******************************************************************************
331
 * RegOpenKeyExA   [ADVAPI32.@]
Jon Griffiths's avatar
Jon Griffiths committed
332 333 334 335
 *
 * Open a registry key.
 *
 * PARAMS
336 337 338 339 340
 *  hkey       [I] Handle of open key
 *  name       [I] Name of subkey to open
 *  reserved   [I] Reserved - must be zero
 *  access     [I] Security access mask
 *  retkey     [O] Handle to open key
Jon Griffiths's avatar
Jon Griffiths committed
341 342
 *
 * RETURNS
343 344
 *  Success: ERROR_SUCCESS
 *  Failure: A standard Win32 error code. retkey is set to 0.
Jon Griffiths's avatar
Jon Griffiths committed
345 346
 *
 * NOTES
347 348
 *  Unlike RegCreateKeyExA(), this function will not create the key if it
 *  does not exist.
349
 */
350
LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey )
351
{
352 353 354 355
    OBJECT_ATTRIBUTES attr;
    STRING nameA;
    NTSTATUS status;

356 357
    if (!is_version_nt()) access = KEY_ALL_ACCESS;  /* Win95 ignores the access mask */

358 359
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

360 361
    attr.Length = sizeof(attr);
    attr.RootDirectory = hkey;
362
    attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
363 364 365 366 367
    attr.Attributes = 0;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;

    RtlInitAnsiString( &nameA, name );
368 369
    if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
                                                 &nameA, FALSE )))
370
    {
371
        status = NtOpenKey( (PHANDLE)retkey, access, &attr );
372 373
    }
    return RtlNtStatusToDosError( status );
374 375 376 377
}


/******************************************************************************
378
 * RegOpenKeyW   [ADVAPI32.@]
379
 *
Jon Griffiths's avatar
Jon Griffiths committed
380
 * See RegOpenKeyA.
381
 */
382
LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey )
383
{
James Hawkins's avatar
James Hawkins committed
384 385 386 387 388
    if (!name || !*name)
    {
        *retkey = hkey;
        return ERROR_SUCCESS;
    }
389 390 391 392 393
    return RegOpenKeyExW( hkey, name, 0, KEY_ALL_ACCESS, retkey );
}


/******************************************************************************
394
 * RegOpenKeyA   [ADVAPI32.@]
Jon Griffiths's avatar
Jon Griffiths committed
395 396 397 398
 *           
 * Open a registry key.
 *
 * PARAMS
399 400 401
 *  hkey    [I] Handle of parent key to open the new key under
 *  name    [I] Name of the key under hkey to open
 *  retkey  [O] Destination for the resulting Handle
Jon Griffiths's avatar
Jon Griffiths committed
402 403
 *
 * RETURNS
404 405
 *  Success: ERROR_SUCCESS
 *  Failure: A standard Win32 error code. retkey is set to 0.
406
 */
407
LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
408
{
James Hawkins's avatar
James Hawkins committed
409 410 411 412 413
    if (!name || !*name)
    {
        *retkey = hkey;
        return ERROR_SUCCESS;
    }
414 415 416 417
    return RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, retkey );
}


418
/******************************************************************************
419
 * RegOpenCurrentUser   [ADVAPI32.@]
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
 *
 * Get a handle to the HKEY_CURRENT_USER key for the user 
 * the current thread is impersonating.
 *
 * PARAMS
 *  access [I] Desired access rights to the key
 *  retkey [O] Handle to the opened key
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
 *
 * FIXME
 *  This function is supposed to retrieve a handle to the
 *  HKEY_CURRENT_USER for the user the current thread is impersonating.
 *  Since Wine does not currently allow threads to impersonate other users,
 *  this stub should work fine.
437
 */
438
LSTATUS WINAPI RegOpenCurrentUser( REGSAM access, PHKEY retkey )
439 440 441 442 443
{
    return RegOpenKeyExA( HKEY_CURRENT_USER, "", 0, access, retkey );
}


444 445

/******************************************************************************
446
 * RegEnumKeyExW   [ADVAPI32.@]
447
 *
448 449
 * Enumerate subkeys of the specified open registry key.
 *
450
 * PARAMS
451 452 453 454 455 456 457 458 459 460 461 462 463
 *  hkey         [I] Handle to key to enumerate
 *  index        [I] Index of subkey to enumerate
 *  name         [O] Buffer for subkey name
 *  name_len     [O] Size of subkey buffer
 *  reserved     [I] Reserved
 *  class        [O] Buffer for class string
 *  class_len    [O] Size of class buffer
 *  ft           [O] Time key last written to
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: System error code. If there are no more subkeys available, the
 *           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 469 470 471
    NTSTATUS status;
    char buffer[256], *buf_ptr = buffer;
    KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
    DWORD total_size;
472

473
    TRACE( "(%p,%d,%p,%p(%d),%p,%p,%p,%p)\n", hkey, index, name, name_len,
474 475 476
           name_len ? *name_len : -1, reserved, class, class_len, ft );

    if (reserved) return ERROR_INVALID_PARAMETER;
477
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
478

479 480
    status = NtEnumerateKey( hkey, index, KeyNodeInformation,
                             buffer, sizeof(buffer), &total_size );
481

482 483 484 485 486 487 488 489 490 491
    while (status == STATUS_BUFFER_OVERFLOW)
    {
        /* retry with a dynamically allocated buffer */
        if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
        if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
            return ERROR_NOT_ENOUGH_MEMORY;
        info = (KEY_NODE_INFORMATION *)buf_ptr;
        status = NtEnumerateKey( hkey, index, KeyNodeInformation,
                                 buf_ptr, total_size, &total_size );
    }
492

493
    if (!status)
494
    {
495 496 497
        DWORD len = info->NameLength / sizeof(WCHAR);
        DWORD cls_len = info->ClassLength / sizeof(WCHAR);

498
        if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
499

500
        if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
            status = STATUS_BUFFER_OVERFLOW;
        else
        {
            *name_len = len;
            memcpy( name, info->Name, info->NameLength );
            name[len] = 0;
            if (class_len)
            {
                *class_len = cls_len;
                if (class)
                {
                    memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
                    class[cls_len] = 0;
                }
            }
        }
517
    }
518 519 520

    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
    return RtlNtStatusToDosError( status );
521 522 523 524
}


/******************************************************************************
525 526
 * RegEnumKeyExA   [ADVAPI32.@]
 *
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 533 534 535
    NTSTATUS status;
    char buffer[256], *buf_ptr = buffer;
    KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
    DWORD total_size;
536

537
    TRACE( "(%p,%d,%p,%p(%d),%p,%p,%p,%p)\n", hkey, index, name, name_len,
538 539 540
           name_len ? *name_len : -1, reserved, class, class_len, ft );

    if (reserved) return ERROR_INVALID_PARAMETER;
541
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
542

543 544
    status = NtEnumerateKey( hkey, index, KeyNodeInformation,
                             buffer, sizeof(buffer), &total_size );
545

546 547 548 549 550 551 552 553 554 555
    while (status == STATUS_BUFFER_OVERFLOW)
    {
        /* retry with a dynamically allocated buffer */
        if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
        if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
            return ERROR_NOT_ENOUGH_MEMORY;
        info = (KEY_NODE_INFORMATION *)buf_ptr;
        status = NtEnumerateKey( hkey, index, KeyNodeInformation,
                                 buf_ptr, total_size, &total_size );
    }
556

557
    if (!status)
558
    {
559
        DWORD len, cls_len;
560

561 562 563
        RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
        RtlUnicodeToMultiByteSize( &cls_len, (WCHAR *)(buf_ptr + info->ClassOffset),
                                   info->ClassLength );
564
        if (ft) *ft = *(FILETIME *)&info->LastWriteTime;
565

566
        if (len >= *name_len || (class && class_len && (cls_len >= *class_len)))
567 568 569 570
            status = STATUS_BUFFER_OVERFLOW;
        else
        {
            *name_len = len;
571
            RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
572 573 574 575 576 577
            name[len] = 0;
            if (class_len)
            {
                *class_len = cls_len;
                if (class)
                {
578 579 580
                    RtlUnicodeToMultiByteN( class, cls_len, NULL,
                                            (WCHAR *)(buf_ptr + info->ClassOffset),
                                            info->ClassLength );
581 582 583 584
                    class[cls_len] = 0;
                }
            }
        }
585
    }
586 587 588

    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
    return RtlNtStatusToDosError( status );
589 590 591 592
}


/******************************************************************************
593 594
 * RegEnumKeyW   [ADVAPI32.@]
 *
Lei Zhang's avatar
Lei Zhang committed
595
 * Enumerates subkeys of the specified open reg key.
596 597 598 599 600 601 602 603 604 605 606
 *
 * PARAMS
 *  hKey    [I] Handle to an open key.
 *  dwIndex [I] Index of the subkey of hKey to retrieve.
 *  lpName  [O] Name of the subkey.
 *  cchName [I] Size of lpName in TCHARS.
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: system error code. If there are no more subkeys available, the
 *           function returns ERROR_NO_MORE_ITEMS.
607
 */
608
LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len )
609 610 611 612 613 614
{
    return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
}


/******************************************************************************
615 616
 * RegEnumKeyA   [ADVAPI32.@]
 *
617
 * See RegEnumKeyW.
618
 */
619
LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
620 621 622 623 624 625
{
    return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL );
}


/******************************************************************************
626
 * RegQueryInfoKeyW   [ADVAPI32.@]
627
 *
628 629
 * Retrieves information about the specified registry key.
 *
630 631 632 633 634 635 636 637 638 639 640 641 642 643
 * PARAMS
 *    hkey       [I] Handle to key to query
 *    class      [O] Buffer for class string
 *    class_len  [O] Size of class string buffer
 *    reserved   [I] Reserved
 *    subkeys    [O] Buffer for number of subkeys
 *    max_subkey [O] Buffer for longest subkey name length
 *    max_class  [O] Buffer for longest class string length
 *    values     [O] Buffer for number of value entries
 *    max_value  [O] Buffer for longest value name length
 *    max_data   [O] Buffer for longest value data length
 *    security   [O] Buffer for security descriptor length
 *    modif      [O] Modification time
 *
644 645 646 647 648 649 650 651 652
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: system error code.
 *
 * NOTES
 *  - win95 allows class to be valid and class_len to be NULL
 *  - winnt returns ERROR_INVALID_PARAMETER if class is valid and class_len is NULL
 *  - both allow class to be NULL and class_len to be NULL
 *    (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 656 657
                              LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
                              LPDWORD values, LPDWORD max_value, LPDWORD max_data,
                              LPDWORD security, FILETIME *modif )
658
{
659 660 661 662
    NTSTATUS status;
    char buffer[256], *buf_ptr = buffer;
    KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer;
    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 666
           reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );

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 674

    if (class)
    {
675 676
        /* retry with a dynamically allocated buffer */
        while (status == STATUS_BUFFER_OVERFLOW)
677
        {
678 679 680 681 682 683 684
            if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
            if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
                return ERROR_NOT_ENOUGH_MEMORY;
            info = (KEY_FULL_INFORMATION *)buf_ptr;
            status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
        }

685 686 687
        if (status) goto done;

        if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len))
688
        {
689 690 691 692 693 694
            status = STATUS_BUFFER_OVERFLOW;
        }
        else
        {
            memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength );
            class[info->ClassLength/sizeof(WCHAR)] = 0;
695 696
        }
    }
697
    else status = STATUS_SUCCESS;
698

699 700 701 702 703 704 705
    if (class_len) *class_len = info->ClassLength / sizeof(WCHAR);
    if (subkeys) *subkeys = info->SubKeys;
    if (max_subkey) *max_subkey = info->MaxNameLen;
    if (max_class) *max_class = info->MaxClassLen;
    if (values) *values = info->Values;
    if (max_value) *max_value = info->MaxValueNameLen;
    if (max_data) *max_data = info->MaxValueDataLen;
706
    if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
707

708
 done:
709 710
    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
    return RtlNtStatusToDosError( status );
711 712 713
}


714
/******************************************************************************
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
 * RegQueryMultipleValuesA   [ADVAPI32.@]
 *
 * Retrieves the type and data for a list of value names associated with a key.
 *
 * PARAMS
 *  hKey       [I] Handle to an open key.
 *  val_list   [O] Array of VALENT structures that describes the entries.
 *  num_vals   [I] Number of elements in val_list.
 *  lpValueBuf [O] Pointer to a buffer that receives the data for each value.
 *  ldwTotsize [I/O] Size of lpValueBuf.
 *
 * RETURNS
 *  Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied.
 *  Failure: nonzero error code from Winerror.h ldwTotsize contains num needed
 *           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 736 737 738 739
    DWORD maxBytes = *ldwTotsize;
    HRESULT status;
    LPSTR bufptr = lpValueBuf;
    *ldwTotsize = 0;

740
    TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
741 742 743 744 745 746 747 748 749 750 751 752 753 754

    for(i=0; i < num_vals; ++i)
    {

        val_list[i].ve_valuelen=0;
        status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
        if(status != ERROR_SUCCESS)
        {
            return status;
        }

        if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
        {
            status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
755
                                      (LPBYTE)bufptr, &val_list[i].ve_valuelen);
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
            if(status != ERROR_SUCCESS)
            {
                return status;
            }

            val_list[i].ve_valueptr = (DWORD_PTR)bufptr;

            bufptr += val_list[i].ve_valuelen;
        }

        *ldwTotsize += val_list[i].ve_valuelen;
    }
    return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
}


/******************************************************************************
773 774
 * RegQueryMultipleValuesW   [ADVAPI32.@]
 *
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 782 783 784 785
    DWORD maxBytes = *ldwTotsize;
    HRESULT status;
    LPSTR bufptr = (LPSTR)lpValueBuf;
    *ldwTotsize = 0;

786
    TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
787 788 789 790 791 792 793 794 795 796 797 798 799

    for(i=0; i < num_vals; ++i)
    {
        val_list[i].ve_valuelen=0;
        status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen);
        if(status != ERROR_SUCCESS)
        {
            return status;
        }

        if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
        {
            status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type,
800
                                      (LPBYTE)bufptr, &val_list[i].ve_valuelen);
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
            if(status != ERROR_SUCCESS)
            {
                return status;
            }

            val_list[i].ve_valueptr = (DWORD_PTR)bufptr;

            bufptr += val_list[i].ve_valuelen;
        }

        *ldwTotsize += val_list[i].ve_valuelen;
    }
    return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA;
}

816
/******************************************************************************
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
 * RegQueryInfoKeyA   [ADVAPI32.@]
 *
 * Retrieves information about a registry key.
 *
 * PARAMS
 *  hKey                   [I] Handle to an open key.
 *  lpClass                [O] Class string of the key.
 *  lpcClass               [I/O] size of lpClass.
 *  lpReserved             [I] Reserved; must be NULL.
 *  lpcSubKeys             [O] Number of subkeys contained by the key.
 *  lpcMaxSubKeyLen        [O] Size of the key's subkey with the longest name.
 *  lpcMaxClassLen         [O] Size of the longest string specifying a subkey
 *                             class in TCHARS.
 *  lpcValues              [O] Number of values associated with the key.
 *  lpcMaxValueNameLen     [O] Size of the key's longest value name in TCHARS.
 *  lpcMaxValueLen         [O] Longest data component among the key's values
 *  lpcbSecurityDescriptor [O] Size of the key's security descriptor.
Lei Zhang's avatar
Lei Zhang committed
834
 *  lpftLastWriteTime      [O] FILETIME structure that is the last write time.
835 836 837 838
 *
 *  RETURNS
 *   Success: ERROR_SUCCESS
 *   Failure: nonzero error code from Winerror.h
839
 */
840
LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWORD reserved,
841 842 843
                              LPDWORD subkeys, LPDWORD max_subkey, LPDWORD max_class,
                              LPDWORD values, LPDWORD max_value, LPDWORD max_data,
                              LPDWORD security, FILETIME *modif )
844
{
845 846 847
    NTSTATUS status;
    char buffer[256], *buf_ptr = buffer;
    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 852
           reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );

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 862 863 864 865 866 867 868 869 870
        /* retry with a dynamically allocated buffer */
        while (status == STATUS_BUFFER_OVERFLOW)
        {
            if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
            if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
                return ERROR_NOT_ENOUGH_MEMORY;
            info = (KEY_FULL_INFORMATION *)buf_ptr;
            status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size );
        }

871 872
        if (status) goto done;

873
        RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->ClassOffset), info->ClassLength);
874
        if (class_len)
875
        {
876 877 878 879 880
            if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW;
            *class_len = len;
        }
        if (class && !status)
        {
881 882
            RtlUnicodeToMultiByteN( class, len, NULL, (WCHAR *)(buf_ptr + info->ClassOffset),
                                    info->ClassLength );
883
            class[len] = 0;
884 885
        }
    }
886
    else status = STATUS_SUCCESS;
887

888 889 890 891 892 893
    if (subkeys) *subkeys = info->SubKeys;
    if (max_subkey) *max_subkey = info->MaxNameLen;
    if (max_class) *max_class = info->MaxClassLen;
    if (values) *values = info->Values;
    if (max_value) *max_value = info->MaxValueNameLen;
    if (max_data) *max_data = info->MaxValueDataLen;
894
    if (modif) *modif = *(FILETIME *)&info->LastWriteTime;
895

896
 done:
897 898
    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
    return RtlNtStatusToDosError( status );
899 900 901 902
}


/******************************************************************************
903
 * RegCloseKey   [ADVAPI32.@]
904
 *
Jon Griffiths's avatar
Jon Griffiths committed
905
 * Close an open registry key.
906 907
 *
 * PARAMS
908
 *  hkey [I] Handle of key to close
909 910
 *
 * RETURNS
911 912
 *  Success: ERROR_SUCCESS
 *  Failure: Error code
913
 */
914
LSTATUS WINAPI RegCloseKey( HKEY hkey )
915
{
James Hawkins's avatar
James Hawkins committed
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
 *
Jon Griffiths's avatar
Jon Griffiths committed
925
 * See RegDeleteKeyA.
926
 */
927
LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
928 929
{
    DWORD ret;
930
    HKEY tmp;
931

932 933
    if (!name) return ERROR_INVALID_PARAMETER;

934 935
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

936
    if (!(ret = RegOpenKeyExW( hkey, name, 0, DELETE, &tmp )))
937
    {
938 939 940
        ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
        RegCloseKey( tmp );
    }
941
    TRACE("%s ret=%08x\n", debugstr_w(name), ret);
942
    return ret;
943 944 945 946
}


/******************************************************************************
947
 * RegDeleteKeyA   [ADVAPI32.@]
Jon Griffiths's avatar
Jon Griffiths committed
948 949 950 951
 *
 * Delete a registry key.
 *
 * PARAMS
952 953
 *  hkey   [I] Handle to parent key containing the key to delete
 *  name   [I] Name of the key user hkey to delete
Jon Griffiths's avatar
Jon Griffiths committed
954
 *
955 956 957 958 959
 * NOTES
 *
 * MSDN is wrong when it says that hkey must be opened with the DELETE access
 * right. In reality, it opens a new handle with DELETE access.
 *
Jon Griffiths's avatar
Jon Griffiths committed
960
 * RETURNS
961 962
 *  Success: ERROR_SUCCESS
 *  Failure: Error code
963
 */
964
LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
965 966
{
    DWORD ret;
967
    HKEY tmp;
968

969 970
    if (!name) return ERROR_INVALID_PARAMETER;

971 972
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

973
    if (!(ret = RegOpenKeyExA( hkey, name, 0, DELETE, &tmp )))
974 975 976 977 978
    {
        if (!is_version_nt()) /* win95 does recursive key deletes */
        {
            CHAR name[MAX_PATH];

979
            while(!RegEnumKeyA(tmp, 0, name, sizeof(name)))
980 981 982 983 984
            {
                if(RegDeleteKeyA(tmp, name))  /* recurse */
                    break;
            }
        }
985 986 987
        ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
        RegCloseKey( tmp );
    }
988
    TRACE("%s ret=%08x\n", debugstr_a(name), ret);
989
    return ret;
990 991 992 993 994
}



/******************************************************************************
995
 * RegSetValueExW   [ADVAPI32.@]
996
 *
Jon Griffiths's avatar
Jon Griffiths committed
997
 * Set the data and contents of a registry value.
998 999
 *
 * PARAMS
1000 1001 1002 1003 1004 1005
 *  hkey       [I] Handle of key to set value for
 *  name       [I] Name of value to set
 *  reserved   [I] Reserved, must be zero
 *  type       [I] Type of the value being set
 *  data       [I] The new contents of the value to set
 *  count      [I] Size of data
1006 1007
 *
 * RETURNS
1008 1009
 *  Success: ERROR_SUCCESS
 *  Failure: Error code
1010
 */
1011
LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
1012
                            DWORD type, CONST BYTE *data, DWORD count )
1013
{
1014
    UNICODE_STRING nameW;
1015

1016 1017
    /* no need for version check, not implemented on win9x anyway */
    if (count && is_string(type))
1018 1019 1020 1021 1022 1023
    {
        LPCWSTR str = (LPCWSTR)data;
        /* if user forgot to count terminating null, add it (yes NT does this) */
        if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
            count += sizeof(WCHAR);
    }
1024
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1025

1026 1027
    RtlInitUnicodeString( &nameW, name );
    return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
1028 1029 1030 1031
}


/******************************************************************************
1032 1033
 * RegSetValueExA   [ADVAPI32.@]
 *
1034
 * See RegSetValueExW.
1035 1036 1037 1038
 *
 * NOTES
 *  win95 does not care about count for REG_SZ and finds out the len by itself (js)
 *  NT does definitely care (aj)
1039
 */
1040
LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1041
                            CONST BYTE *data, DWORD count )
1042
{
1043 1044 1045
    ANSI_STRING nameA;
    WCHAR *dataW = NULL;
    NTSTATUS status;
1046

1047
    if (!is_version_nt())  /* win95 */
1048
    {
1049 1050 1051
        if (type == REG_SZ)
        {
            if (!data) return ERROR_INVALID_PARAMETER;
Mike McCormack's avatar
Mike McCormack committed
1052
            count = strlen((const char *)data) + 1;
1053
        }
1054 1055
    }
    else if (count && is_string(type))
1056 1057 1058 1059
    {
        /* if user forgot to count terminating null, add it (yes NT does this) */
        if (data[count-1] && !data[count]) count++;
    }
1060

1061 1062
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

1063
    if (is_string( type )) /* need to convert to Unicode */
1064
    {
1065
        DWORD lenW;
Mike McCormack's avatar
Mike McCormack committed
1066
        RtlMultiByteToUnicodeSize( &lenW, (const char *)data, count );
1067
        if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
Mike McCormack's avatar
Mike McCormack committed
1068
        RtlMultiByteToUnicodeN( dataW, lenW, NULL, (const char *)data, count );
1069
        count = lenW;
1070 1071
        data = (BYTE *)dataW;
    }
1072

1073
    RtlInitAnsiString( &nameA, name );
1074 1075
    if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
                                                 &nameA, FALSE )))
1076
    {
1077
        status = NtSetValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString, 0, type, data, count );
1078
    }
1079
    HeapFree( GetProcessHeap(), 0, dataW );
1080
    return RtlNtStatusToDosError( status );
1081 1082 1083 1084
}


/******************************************************************************
1085 1086 1087 1088 1089 1090 1091 1092 1093
 * RegSetValueW   [ADVAPI32.@]
 *
 * Sets the data for the default or unnamed value of a reg key.
 *
 * PARAMS
 *  hKey     [I] Handle to an open key.
 *  lpSubKey [I] Name of a subkey of hKey.
 *  dwType   [I] Type of information to store.
 *  lpData   [I] String that contains the data to set for the default value.
1094
 *  cbData   [I] Ignored.
1095 1096 1097 1098
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
1099
 */
1100
LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR name, DWORD type, LPCWSTR data, DWORD count )
1101 1102 1103 1104
{
    HKEY subkey = hkey;
    DWORD ret;

1105
    TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(name), type, debugstr_w(data), count );
1106

1107
    if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1108 1109 1110 1111 1112 1113

    if (name && name[0])  /* need to create the subkey */
    {
        if ((ret = RegCreateKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
    }

Eric Pouech's avatar
Eric Pouech committed
1114
    ret = RegSetValueExW( subkey, NULL, 0, REG_SZ, (const BYTE*)data,
1115
                          (strlenW( data ) + 1) * sizeof(WCHAR) );
1116 1117 1118 1119 1120 1121
    if (subkey != hkey) RegCloseKey( subkey );
    return ret;
}


/******************************************************************************
1122 1123
 * RegSetValueA   [ADVAPI32.@]
 *
1124
 * See RegSetValueW.
1125
 */
1126
LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1127 1128 1129 1130
{
    HKEY subkey = hkey;
    DWORD ret;

1131
    TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(name), type, debugstr_a(data), count );
1132

1133
    if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER;
1134 1135 1136 1137 1138

    if (name && name[0])  /* need to create the subkey */
    {
        if ((ret = RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
    }
Eric Pouech's avatar
Eric Pouech committed
1139
    ret = RegSetValueExA( subkey, NULL, 0, REG_SZ, (const BYTE*)data, strlen(data)+1 );
1140 1141 1142 1143 1144 1145 1146
    if (subkey != hkey) RegCloseKey( subkey );
    return ret;
}



/******************************************************************************
1147
 * RegQueryValueExW   [ADVAPI32.@]
1148
 *
Jon Griffiths's avatar
Jon Griffiths committed
1149
 * See RegQueryValueExA.
1150
 */
1151
LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWORD type,
1152
                              LPBYTE data, LPDWORD count )
1153
{
1154 1155 1156
    NTSTATUS status;
    UNICODE_STRING name_str;
    DWORD total_size;
1157
    char buffer[256], *buf_ptr = buffer;
1158
    KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1159
    static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1160

1161
    TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1162 1163
          hkey, debugstr_w(name), reserved, type, data, count,
          (count && data) ? *count : 0 );
1164

1165
    if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1166
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1167

1168 1169 1170
    RtlInitUnicodeString( &name_str, name );

    if (data) total_size = min( sizeof(buffer), *count + info_size );
1171 1172 1173 1174 1175
    else
    {
        total_size = info_size;
        if (count) *count = 0;
    }
1176 1177 1178 1179

    status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
                              buffer, total_size, &total_size );
    if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1180 1181

    if (data)
1182
    {
1183 1184
        /* retry with a dynamically allocated buffer */
        while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count)
1185
        {
1186 1187
            if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
            if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1188 1189 1190 1191
                return ERROR_NOT_ENOUGH_MEMORY;
            info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
            status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
                                      buf_ptr, total_size, &total_size );
1192 1193 1194 1195 1196 1197 1198 1199
        }

        if (!status)
        {
            memcpy( data, buf_ptr + info_size, total_size - info_size );
            /* if the type is REG_SZ and data is not 0-terminated
             * and there is enough space in the buffer NT appends a \0 */
            if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type))
1200
            {
1201 1202
                WCHAR *ptr = (WCHAR *)(data + total_size - info_size);
                if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1203 1204
            }
        }
1205
        else if (status != STATUS_BUFFER_OVERFLOW) goto done;
1206
    }
1207
    else status = STATUS_SUCCESS;
1208 1209 1210 1211 1212

    if (type) *type = info->Type;
    if (count) *count = total_size - info_size;

 done:
1213
    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1214
    return RtlNtStatusToDosError(status);
1215 1216 1217 1218
}


/******************************************************************************
1219
 * RegQueryValueExA   [ADVAPI32.@]
1220
 *
Jon Griffiths's avatar
Jon Griffiths committed
1221 1222 1223
 * Get the type and contents of a specified value under with a key.
 *
 * PARAMS
1224 1225 1226 1227 1228 1229
 *  hkey      [I]   Handle of the key to query
 *  name      [I]   Name of value under hkey to query
 *  reserved  [I]   Reserved - must be NULL
 *  type      [O]   Destination for the value type, or NULL if not required
 *  data      [O]   Destination for the values contents, or NULL if not required
 *  count     [I/O] Size of data, updated with the number of bytes returned
Jon Griffiths's avatar
Jon Griffiths committed
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
 *
 * RETURNS
 *  Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
 *  Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
 *           ERROR_INVALID_PARAMETER, if any other parameter is invalid.
 *           ERROR_MORE_DATA, if on input *count is too small to hold the contents.
 *                     
 * NOTES
 *   MSDN states that if data is too small it is partially filled. In reality 
 *   it remains untouched.
1240
 */
1241
LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1242
                              LPBYTE data, LPDWORD count )
1243
{
1244 1245
    NTSTATUS status;
    ANSI_STRING nameA;
1246
    DWORD total_size, datalen = 0;
1247
    char buffer[256], *buf_ptr = buffer;
1248
    KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1249
    static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
1250

1251
    TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
1252 1253
          hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );

1254
    if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1255
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1256

1257
    if (count) datalen = *count;
1258 1259 1260 1261 1262
    if (!data && count) *count = 0;

    /* this matches Win9x behaviour - NT sets *type to a random value */
    if (type) *type = REG_NONE;

1263
    RtlInitAnsiString( &nameA, name );
1264 1265
    if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
                                                &nameA, FALSE )))
1266
        return RtlNtStatusToDosError(status);
1267

1268 1269
    status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
                              KeyValuePartialInformation, buffer, sizeof(buffer), &total_size );
1270
    if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1271

1272 1273 1274
    /* we need to fetch the contents for a string type even if not requested,
     * because we need to compute the length of the ASCII string. */
    if (data || is_string(info->Type))
1275
    {
1276 1277
        /* retry with a dynamically allocated buffer */
        while (status == STATUS_BUFFER_OVERFLOW)
1278
        {
1279 1280
            if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
            if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
1281
            {
1282
                status = STATUS_NO_MEMORY;
1283 1284 1285
                goto done;
            }
            info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
1286 1287
            status = NtQueryValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString,
                                    KeyValuePartialInformation, buf_ptr, total_size, &total_size );
1288 1289
        }

1290 1291 1292
        if (status) goto done;

        if (is_string(info->Type))
1293
        {
1294 1295 1296 1297
            DWORD len;

            RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
                                       total_size - info_size );
1298
            if (data && len)
1299
            {
1300
                if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
1301
                else
1302
                {
Mike McCormack's avatar
Mike McCormack committed
1303
                    RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
1304
                                            total_size - info_size );
1305 1306
                    /* if the type is REG_SZ and data is not 0-terminated
                     * and there is enough space in the buffer NT appends a \0 */
1307
                    if (len < datalen && data[len-1]) data[len] = 0;
1308
                }
1309
            }
1310 1311 1312 1313
            total_size = len + info_size;
        }
        else if (data)
        {
1314
            if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
1315
            else memcpy( data, buf_ptr + info_size, total_size - info_size );
1316
        }
1317
    }
1318
    else status = STATUS_SUCCESS;
1319

1320 1321 1322 1323
    if (type) *type = info->Type;
    if (count) *count = total_size - info_size;

 done:
1324
    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
1325
    return RtlNtStatusToDosError(status);
1326 1327 1328 1329
}


/******************************************************************************
1330 1331 1332 1333 1334
 * RegQueryValueW   [ADVAPI32.@]
 *
 * Retrieves the data associated with the default or unnamed value of a key.
 *
 * PARAMS
1335 1336 1337
 *  hkey      [I] Handle to an open key.
 *  name      [I] Name of the subkey of hKey.
 *  data      [O] Receives the string associated with the default value
1338
 *                of the key.
1339
 *  count     [I/O] Size of lpValue in bytes.
1340 1341 1342 1343
 *
 *  RETURNS
 *   Success: ERROR_SUCCESS
 *   Failure: nonzero error code from Winerror.h
1344
 */
1345
LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count )
1346 1347 1348 1349
{
    DWORD ret;
    HKEY subkey = hkey;

1350
    TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 );
1351 1352 1353 1354 1355

    if (name && name[0])
    {
        if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
    }
Mike McCormack's avatar
Mike McCormack committed
1356
    ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1357 1358 1359 1360 1361
    if (subkey != hkey) RegCloseKey( subkey );
    if (ret == ERROR_FILE_NOT_FOUND)
    {
        /* return empty string if default value not found */
        if (data) *data = 0;
1362
        if (count) *count = sizeof(WCHAR);
1363 1364 1365 1366 1367 1368 1369
        ret = ERROR_SUCCESS;
    }
    return ret;
}


/******************************************************************************
1370 1371
 * RegQueryValueA   [ADVAPI32.@]
 *
1372
 * See RegQueryValueW.
1373
 */
1374
LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
1375 1376 1377 1378
{
    DWORD ret;
    HKEY subkey = hkey;

1379
    TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 );
1380 1381 1382 1383 1384

    if (name && name[0])
    {
        if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
    }
Mike McCormack's avatar
Mike McCormack committed
1385
    ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397
    if (subkey != hkey) RegCloseKey( subkey );
    if (ret == ERROR_FILE_NOT_FOUND)
    {
        /* return empty string if default value not found */
        if (data) *data = 0;
        if (count) *count = 1;
        ret = ERROR_SUCCESS;
    }
    return ret;
}


1398 1399 1400 1401 1402
/******************************************************************************
 * ADVAPI_ApplyRestrictions   [internal]
 *
 * Helper function for RegGetValueA/W.
 */
1403 1404
static VOID ADVAPI_ApplyRestrictions( DWORD dwFlags, DWORD dwType,
                                      DWORD cbData, PLONG ret )
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430
{
    /* Check if the type is restricted by the passed flags */
    if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
    {
        DWORD dwMask = 0;

        switch (dwType)
        {
        case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
        case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
        case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
        case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
        case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
        case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
        case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
        }

        if (dwFlags & dwMask)
        {
            /* Type is not restricted, check for size mismatch */
            if (dwType == REG_BINARY)
            {
                DWORD cbExpect = 0;

                if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD)
                    cbExpect = 4;
Andrew Talbot's avatar
Andrew Talbot committed
1431
                else if ((dwFlags & RRF_RT_QWORD) == RRF_RT_QWORD)
1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445
                    cbExpect = 8;

                if (cbExpect && cbData != cbExpect)
                    *ret = ERROR_DATATYPE_MISMATCH;
            }
        }
        else *ret = ERROR_UNSUPPORTED_TYPE;
    }
}


/******************************************************************************
 * RegGetValueW   [ADVAPI32.@]
 *
1446 1447
 * Retrieves the type and data for a value name associated with a key,
 * optionally expanding its content and restricting its type.
1448 1449 1450 1451 1452 1453 1454 1455
 *
 * PARAMS
 *  hKey      [I] Handle to an open key.
 *  pszSubKey [I] Name of the subkey of hKey.
 *  pszValue  [I] Name of value under hKey/szSubKey to query.
 *  dwFlags   [I] Flags restricting the value type to retrieve.
 *  pdwType   [O] Destination for the values type, may be NULL.
 *  pvData    [O] Destination for the values content, may be NULL.
1456 1457 1458
 *  pcbData   [I/O] Size of pvData, updated with the size in bytes required to
 *                  retrieve the whole content, including the trailing '\0'
 *                  for strings.
1459 1460 1461 1462 1463 1464
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
 *
 * NOTES
1465 1466
 *  - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
 *    expanded and pdwType is set to REG_SZ instead.
1467 1468 1469
 *  - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ 
 *    without RRF_NOEXPAND is thus not allowed.
 */
1470
LSTATUS WINAPI RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
1471 1472 1473 1474 1475 1476 1477
                          DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
                          LPDWORD pcbData )
{
    DWORD dwType, cbData = pcbData ? *pcbData : 0;
    PVOID pvBuf = NULL;
    LONG ret;

1478
    TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n", 
1479 1480 1481
          hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
          pvData, pcbData, cbData);

1482 1483
    if (pvData && !pcbData)
        return ERROR_INVALID_PARAMETER;
1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
    if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
        return ERROR_INVALID_PARAMETER;

    if (pszSubKey && pszSubKey[0])
    {
        ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
        if (ret != ERROR_SUCCESS) return ret;
    }

    ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
    
    /* If we are going to expand we need to read in the whole the value even
     * if the passed buffer was too small as the expanded string might be
     * smaller than the unexpanded one and could fit into cbData bytes. */
    if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1499
        dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1500 1501
    {
        do {
1502
            HeapFree(GetProcessHeap(), 0, pvBuf);
1503 1504 1505 1506 1507 1508 1509 1510
            
            pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
            if (!pvBuf)
            {
                ret = ERROR_NOT_ENOUGH_MEMORY;
                break;
            }

1511
            if (ret == ERROR_MORE_DATA || !pvData)
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528
                ret = RegQueryValueExW(hKey, pszValue, NULL, 
                                       &dwType, pvBuf, &cbData);
            else
            {
                /* Even if cbData was large enough we have to copy the 
                 * string since ExpandEnvironmentStrings can't handle
                 * overlapping buffers. */
                CopyMemory(pvBuf, pvData, cbData);
            }

            /* Both the type or the value itself could have been modified in
             * between so we have to keep retrying until the buffer is large
             * enough or we no longer have to expand the value. */
        } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);

        if (ret == ERROR_SUCCESS)
        {
1529
            /* Recheck dwType in case it changed since the first call */
1530 1531 1532
            if (dwType == REG_EXPAND_SZ)
            {
                cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
1533
                                                   pcbData ? *pcbData : 0) * sizeof(WCHAR);
1534
                dwType = REG_SZ;
1535
                if(pvData && pcbData && cbData > *pcbData)
1536 1537
                    ret = ERROR_MORE_DATA;
            }
1538
            else if (pvData)
1539 1540 1541
                CopyMemory(pvData, pvBuf, *pcbData);
        }

1542
        HeapFree(GetProcessHeap(), 0, pvBuf);
1543 1544 1545 1546 1547 1548 1549
    }

    if (pszSubKey && pszSubKey[0])
        RegCloseKey(hKey);

    ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);

1550
    if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
        ZeroMemory(pvData, *pcbData);

    if (pdwType) *pdwType = dwType;
    if (pcbData) *pcbData = cbData;

    return ret;
}


/******************************************************************************
 * RegGetValueA   [ADVAPI32.@]
 *
 * See RegGetValueW.
 */
1565
LSTATUS WINAPI RegGetValueA( HKEY hKey, LPCSTR pszSubKey, LPCSTR pszValue,
1566 1567 1568 1569 1570 1571 1572
                          DWORD dwFlags, LPDWORD pdwType, PVOID pvData, 
                          LPDWORD pcbData )
{
    DWORD dwType, cbData = pcbData ? *pcbData : 0;
    PVOID pvBuf = NULL;
    LONG ret;

1573
    TRACE("(%p,%s,%s,%d,%p,%p,%p=%d)\n", 
1574 1575 1576
          hKey, pszSubKey, pszValue, dwFlags, pdwType, pvData, pcbData,
          cbData);

1577 1578
    if (pvData && !pcbData)
        return ERROR_INVALID_PARAMETER;
1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593
    if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
        return ERROR_INVALID_PARAMETER;

    if (pszSubKey && pszSubKey[0])
    {
        ret = RegOpenKeyExA(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
        if (ret != ERROR_SUCCESS) return ret;
    }

    ret = RegQueryValueExA(hKey, pszValue, NULL, &dwType, pvData, &cbData);

    /* If we are going to expand we need to read in the whole the value even
     * if the passed buffer was too small as the expanded string might be
     * smaller than the unexpanded one and could fit into cbData bytes. */
    if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
1594
        dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND))
1595 1596
    {
        do {
1597
            HeapFree(GetProcessHeap(), 0, pvBuf);
1598 1599 1600 1601 1602 1603 1604 1605

            pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
            if (!pvBuf)
            {
                ret = ERROR_NOT_ENOUGH_MEMORY;
                break;
            }

1606
            if (ret == ERROR_MORE_DATA || !pvData)
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623
                ret = RegQueryValueExA(hKey, pszValue, NULL, 
                                       &dwType, pvBuf, &cbData);
            else
            {
                /* Even if cbData was large enough we have to copy the 
                 * string since ExpandEnvironmentStrings can't handle
                 * overlapping buffers. */
                CopyMemory(pvBuf, pvData, cbData);
            }

            /* Both the type or the value itself could have been modified in
             * between so we have to keep retrying until the buffer is large
             * enough or we no longer have to expand the value. */
        } while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);

        if (ret == ERROR_SUCCESS)
        {
1624
            /* Recheck dwType in case it changed since the first call */
1625 1626 1627 1628 1629
            if (dwType == REG_EXPAND_SZ)
            {
                cbData = ExpandEnvironmentStringsA(pvBuf, pvData,
                                                   pcbData ? *pcbData : 0);
                dwType = REG_SZ;
1630
                if(pvData && pcbData && cbData > *pcbData)
1631 1632
                    ret = ERROR_MORE_DATA;
            }
1633
            else if (pvData)
1634 1635 1636
                CopyMemory(pvData, pvBuf, *pcbData);
        }

1637
        HeapFree(GetProcessHeap(), 0, pvBuf);
1638 1639 1640 1641 1642 1643 1644
    }

    if (pszSubKey && pszSubKey[0])
        RegCloseKey(hKey);

    ADVAPI_ApplyRestrictions(dwFlags, dwType, cbData, &ret);

1645
    if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
1646 1647 1648 1649 1650 1651 1652 1653 1654
        ZeroMemory(pvData, *pcbData);

    if (pdwType) *pdwType = dwType;
    if (pcbData) *pcbData = cbData;

    return ret;
}


1655
/******************************************************************************
1656
 * RegEnumValueW   [ADVAPI32.@]
1657
 *
1658 1659
 * Enumerates the values for the specified open registry key.
 *
1660
 * PARAMS
1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672
 *  hkey       [I] Handle to key to query
 *  index      [I] Index of value to query
 *  value      [O] Value string
 *  val_count  [I/O] Size of value buffer (in wchars)
 *  reserved   [I] Reserved
 *  type       [O] Type code
 *  data       [O] Value data
 *  count      [I/O] Size of data buffer (in bytes)
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
1673 1674
 */

1675
LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_count,
1676
                           LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1677
{
1678 1679 1680 1681
    NTSTATUS status;
    DWORD total_size;
    char buffer[256], *buf_ptr = buffer;
    KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1682
    static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1683

1684
    TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1685 1686 1687
          hkey, index, value, val_count, reserved, type, data, count );

    /* NT only checks count, not val_count */
1688
    if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1689
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1690

1691 1692 1693
    total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
    if (data) total_size += *count;
    total_size = min( sizeof(buffer), total_size );
1694

1695 1696 1697
    status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
                                  buffer, total_size, &total_size );
    if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1698

1699
    if (value || data)
1700
    {
1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718
        /* retry with a dynamically allocated buffer */
        while (status == STATUS_BUFFER_OVERFLOW)
        {
            if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
            if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
                return ERROR_NOT_ENOUGH_MEMORY;
            info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
            status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
                                          buf_ptr, total_size, &total_size );
        }

        if (status) goto done;

        if (value)
        {
            if (info->NameLength/sizeof(WCHAR) >= *val_count)
            {
                status = STATUS_BUFFER_OVERFLOW;
1719
                goto overflow;
1720 1721 1722 1723 1724 1725 1726
            }
            memcpy( value, info->Name, info->NameLength );
            *val_count = info->NameLength / sizeof(WCHAR);
            value[*val_count] = 0;
        }

        if (data)
1727
        {
1728
            if (total_size - info->DataOffset > *count)
1729
            {
1730
                status = STATUS_BUFFER_OVERFLOW;
1731
                goto overflow;
1732 1733 1734 1735 1736 1737 1738 1739
            }
            memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
            if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
            {
                /* if the type is REG_SZ and data is not 0-terminated
                 * and there is enough space in the buffer NT appends a \0 */
                WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
                if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
1740 1741 1742
            }
        }
    }
1743
    else status = STATUS_SUCCESS;
1744

1745
 overflow:
1746 1747 1748 1749 1750 1751
    if (type) *type = info->Type;
    if (count) *count = info->DataLength;

 done:
    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
    return RtlNtStatusToDosError(status);
1752 1753 1754 1755
}


/******************************************************************************
1756 1757
 * RegEnumValueA   [ADVAPI32.@]
 *
1758
 * See RegEnumValueW.
1759
 */
1760
LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1761
                           LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1762
{
1763 1764 1765 1766
    NTSTATUS status;
    DWORD total_size;
    char buffer[256], *buf_ptr = buffer;
    KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
1767
    static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );
1768

1769
    TRACE("(%p,%d,%p,%p,%p,%p,%p,%p)\n",
1770 1771 1772
          hkey, index, value, val_count, reserved, type, data, count );

    /* NT only checks count, not val_count */
1773
    if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
1774
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
1775

1776 1777 1778
    total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
    if (data) total_size += *count;
    total_size = min( sizeof(buffer), total_size );
1779

1780 1781 1782
    status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
                                  buffer, total_size, &total_size );
    if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
1783

1784 1785 1786
    /* we need to fetch the contents for a string type even if not requested,
     * because we need to compute the length of the ASCII string. */
    if (value || data || is_string(info->Type))
1787
    {
1788 1789
        /* retry with a dynamically allocated buffer */
        while (status == STATUS_BUFFER_OVERFLOW)
1790
        {
1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802
            if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
            if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
                return ERROR_NOT_ENOUGH_MEMORY;
            info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
            status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
                                          buf_ptr, total_size, &total_size );
        }

        if (status) goto done;

        if (is_string(info->Type))
        {
1803 1804 1805
            DWORD len;
            RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
                                       total_size - info->DataOffset );
1806 1807
            if (data && len)
            {
1808 1809
                if (len > *count) status = STATUS_BUFFER_OVERFLOW;
                else
1810
                {
Mike McCormack's avatar
Mike McCormack committed
1811
                    RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
1812 1813 1814 1815
                                            total_size - info->DataOffset );
                    /* if the type is REG_SZ and data is not 0-terminated
                     * and there is enough space in the buffer NT appends a \0 */
                    if (len < *count && data[len-1]) data[len] = 0;
1816
                }
1817
            }
1818 1819 1820 1821 1822 1823
            info->DataLength = len;
        }
        else if (data)
        {
            if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
            else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
1824
        }
1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847

        if (value && !status)
        {
            DWORD len;

            RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
            if (len >= *val_count)
            {
                status = STATUS_BUFFER_OVERFLOW;
                if (*val_count)
                {
                    len = *val_count - 1;
                    RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
                    value[len] = 0;
                }
            }
            else
            {
                RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
                value[len] = 0;
                *val_count = len;
            }
        }
1848
    }
1849
    else status = STATUS_SUCCESS;
1850

1851 1852 1853 1854 1855 1856
    if (type) *type = info->Type;
    if (count) *count = info->DataLength;

 done:
    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
    return RtlNtStatusToDosError(status);
1857 1858 1859 1860 1861
}



/******************************************************************************
1862
 * RegDeleteValueW   [ADVAPI32.@]
1863
 *
Jon Griffiths's avatar
Jon Griffiths committed
1864
 * See RegDeleteValueA.
1865
 */
1866
LSTATUS WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
1867
{
1868
    UNICODE_STRING nameW;
1869 1870 1871

    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

1872 1873
    RtlInitUnicodeString( &nameW, name );
    return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
1874 1875 1876 1877
}


/******************************************************************************
1878
 * RegDeleteValueA   [ADVAPI32.@]
Jon Griffiths's avatar
Jon Griffiths committed
1879 1880 1881 1882 1883 1884 1885 1886
 *
 * Delete a value from the registry.
 *
 * PARAMS
 *  hkey [I] Registry handle of the key holding the value
 *  name [I] Name of the value under hkey to delete
 *
 * RETURNS
1887 1888
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
1889
 */
1890
LSTATUS WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
1891
{
1892 1893
    STRING nameA;
    NTSTATUS status;
1894

1895 1896
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

1897
    RtlInitAnsiString( &nameA, name );
1898 1899 1900
    if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
                                                 &nameA, FALSE )))
        status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
1901
    return RtlNtStatusToDosError( status );
1902 1903 1904 1905
}


/******************************************************************************
1906
 * RegLoadKeyW   [ADVAPI32.@]
1907
 *
1908 1909 1910
 * Create a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and store
 * registration information from a specified file into that subkey.
 *
1911
 * PARAMS
1912 1913 1914 1915 1916
 *  hkey      [I] Handle of open key
 *  subkey    [I] Address of name of subkey
 *  filename  [I] Address of filename for registry information
 *
 * RETURNS
1917
 *  Success: ERROR_SUCCESS
1918
 *  Failure: nonzero error code from Winerror.h
1919
 */
1920
LSTATUS WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
1921
{
James Hawkins's avatar
James Hawkins committed
1922 1923
    OBJECT_ATTRIBUTES destkey, file;
    UNICODE_STRING subkeyW, filenameW;
1924
    NTSTATUS status;
James Hawkins's avatar
James Hawkins committed
1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943

    if (!(hkey = get_special_root_hkey(hkey))) return ERROR_INVALID_HANDLE;

    destkey.Length = sizeof(destkey);
    destkey.RootDirectory = hkey;               /* root key: HKLM or HKU */
    destkey.ObjectName = &subkeyW;              /* name of the key */
    destkey.Attributes = 0;
    destkey.SecurityDescriptor = NULL;
    destkey.SecurityQualityOfService = NULL;
    RtlInitUnicodeString(&subkeyW, subkey);

    file.Length = sizeof(file);
    file.RootDirectory = NULL;
    file.ObjectName = &filenameW;               /* file containing the hive */
    file.Attributes = OBJ_CASE_INSENSITIVE;
    file.SecurityDescriptor = NULL;
    file.SecurityQualityOfService = NULL;
    RtlDosPathNameToNtPathName_U(filename, &filenameW, NULL, NULL);

1944 1945 1946
    status = NtLoadKey(&destkey, &file);
    RtlFreeUnicodeString(&filenameW);
    return RtlNtStatusToDosError( status );
1947 1948 1949 1950
}


/******************************************************************************
1951 1952
 * RegLoadKeyA   [ADVAPI32.@]
 *
1953
 * See RegLoadKeyW.
1954
 */
1955
LSTATUS WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
1956
{
James Hawkins's avatar
James Hawkins committed
1957 1958 1959
    UNICODE_STRING subkeyW, filenameW;
    STRING subkeyA, filenameA;
    NTSTATUS status;
1960
    LONG ret;
1961

James Hawkins's avatar
James Hawkins committed
1962 1963
    RtlInitAnsiString(&subkeyA, subkey);
    RtlInitAnsiString(&filenameA, filename);
1964

1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975
    RtlInitUnicodeString(&subkeyW, NULL);
    RtlInitUnicodeString(&filenameW, NULL);
    if (!(status = RtlAnsiStringToUnicodeString(&subkeyW, &subkeyA, TRUE)) &&
        !(status = RtlAnsiStringToUnicodeString(&filenameW, &filenameA, TRUE)))
    {
        ret = RegLoadKeyW(hkey, subkeyW.Buffer, filenameW.Buffer);
    }
    else ret = RtlNtStatusToDosError(status);
    RtlFreeUnicodeString(&subkeyW);
    RtlFreeUnicodeString(&filenameW);
    return ret;
1976 1977 1978 1979
}


/******************************************************************************
1980
 * RegSaveKeyW   [ADVAPI32.@]
1981
 *
1982 1983
 * Save a key and all of its subkeys and values to a new file in the standard format.
 *
1984
 * PARAMS
1985 1986 1987 1988 1989 1990 1991
 *  hkey   [I] Handle of key where save begins
 *  lpFile [I] Address of filename to save to
 *  sa     [I] Address of security structure
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
1992
 */
1993
LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa )
1994
{
1995 1996 1997
    static const WCHAR format[] =
        {'r','e','g','%','0','4','x','.','t','m','p',0};
    WCHAR buffer[MAX_PATH];
1998
    int count = 0;
1999
    LPWSTR nameW;
2000
    DWORD ret, err;
2001
    HANDLE handle;
2002

2003
    TRACE( "(%p,%s,%p)\n", hkey, debugstr_w(file), sa );
2004 2005

    if (!file || !*file) return ERROR_INVALID_PARAMETER;
2006
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2007 2008

    err = GetLastError();
2009 2010
    GetFullPathNameW( file, sizeof(buffer)/sizeof(WCHAR), buffer, &nameW );

2011 2012
    for (;;)
    {
2013 2014
        snprintfW( nameW, 16, format, count++ );
        handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
2015
                            CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
2016
        if (handle != INVALID_HANDLE_VALUE) break;
2017
        if ((ret = GetLastError()) != ERROR_FILE_EXISTS) goto done;
2018 2019 2020

        /* Something gone haywire ? Please report if this happens abnormally */
        if (count >= 100)
2021
            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);
2022 2023
    }

2024
    ret = RtlNtStatusToDosError(NtSaveKey(hkey, handle));
2025

2026 2027 2028
    CloseHandle( handle );
    if (!ret)
    {
2029
        if (!MoveFileExW( buffer, file, MOVEFILE_REPLACE_EXISTING ))
2030
        {
2031 2032
            ERR( "Failed to move %s to %s\n", debugstr_w(buffer),
	        debugstr_w(file) );
2033 2034 2035
            ret = GetLastError();
        }
    }
2036
    if (ret) DeleteFileW( buffer );
2037 2038 2039 2040 2041 2042 2043 2044

done:
    SetLastError( err );  /* restore last error code */
    return ret;
}


/******************************************************************************
2045 2046
 * RegSaveKeyA  [ADVAPI32.@]
 *
2047
 * See RegSaveKeyW.
2048
 */
2049
LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
2050
{
2051 2052 2053 2054 2055 2056 2057 2058
    UNICODE_STRING *fileW = &NtCurrentTeb()->StaticUnicodeString;
    NTSTATUS status;
    STRING fileA;

    RtlInitAnsiString(&fileA, file);
    if ((status = RtlAnsiStringToUnicodeString(fileW, &fileA, FALSE)))
        return RtlNtStatusToDosError( status );
    return RegSaveKeyW(hkey, fileW->Buffer, sa);
2059
}
2060 2061 2062


/******************************************************************************
2063
 * RegRestoreKeyW [ADVAPI32.@]
2064
 *
2065 2066
 * Read the registry information from a file and copy it over a key.
 *
2067
 * PARAMS
2068 2069 2070 2071 2072 2073 2074
 *  hkey    [I] Handle of key where restore begins
 *  lpFile  [I] Address of filename containing saved tree
 *  dwFlags [I] Optional flags
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
2075
 */
2076
LSTATUS WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2077
{
2078
    TRACE("(%p,%s,%d)\n",hkey,debugstr_w(lpFile),dwFlags);
2079 2080 2081 2082 2083

    /* It seems to do this check before the hkey check */
    if (!lpFile || !*lpFile)
        return ERROR_INVALID_PARAMETER;

2084
    FIXME("(%p,%s,%d): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2085 2086 2087 2088 2089 2090 2091 2092

    /* Check for file existence */

    return ERROR_SUCCESS;
}


/******************************************************************************
2093
 * RegRestoreKeyA [ADVAPI32.@]
2094
 *
2095
 * See RegRestoreKeyW.
2096
 */
2097
LSTATUS WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2098
{
2099 2100 2101 2102 2103 2104
    UNICODE_STRING lpFileW;
    LONG ret;

    RtlCreateUnicodeStringFromAsciiz( &lpFileW, lpFile );
    ret = RegRestoreKeyW( hkey, lpFileW.Buffer, dwFlags );
    RtlFreeUnicodeString( &lpFileW );
2105 2106 2107 2108 2109
    return ret;
}


/******************************************************************************
2110
 * RegUnLoadKeyW [ADVAPI32.@]
2111
 *
2112 2113
 * Unload a registry key and its subkeys from the registry.
 *
2114
 * PARAMS
2115 2116 2117 2118 2119 2120
 *  hkey     [I] Handle of open key
 *  lpSubKey [I] Address of name of subkey to unload
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
2121
 */
2122
LSTATUS WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
2123
{
2124 2125
    DWORD ret;
    HKEY shkey;
2126 2127
    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING subkey;
2128 2129 2130 2131 2132 2133 2134

    TRACE("(%p,%s)\n",hkey, debugstr_w(lpSubKey));

    ret = RegOpenKeyW(hkey,lpSubKey,&shkey);
    if( ret )
        return ERROR_INVALID_PARAMETER;

2135 2136 2137
    RtlInitUnicodeString(&subkey, lpSubKey);
    InitializeObjectAttributes(&attr, &subkey, OBJ_CASE_INSENSITIVE, shkey, NULL);
    ret = RtlNtStatusToDosError(NtUnloadKey(&attr));
2138

2139 2140 2141
    RegCloseKey(shkey);

    return ret;
2142 2143 2144 2145
}


/******************************************************************************
2146
 * RegUnLoadKeyA [ADVAPI32.@]
2147
 *
2148
 * See RegUnLoadKeyW.
2149
 */
2150
LSTATUS WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
2151
{
2152 2153 2154 2155 2156 2157
    UNICODE_STRING lpSubKeyW;
    LONG ret;

    RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
    ret = RegUnLoadKeyW( hkey, lpSubKeyW.Buffer );
    RtlFreeUnicodeString( &lpSubKeyW );
2158 2159 2160 2161 2162
    return ret;
}


/******************************************************************************
2163
 * RegReplaceKeyW [ADVAPI32.@]
2164
 *
2165 2166
 * Replace the file backing a registry key and all its subkeys with another file.
 *
2167
 * PARAMS
2168 2169 2170 2171 2172 2173 2174 2175
 *  hkey      [I] Handle of open key
 *  lpSubKey  [I] Address of name of subkey
 *  lpNewFile [I] Address of filename for file with new data
 *  lpOldFile [I] Address of filename for backup file
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
2176
 */
2177
LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2178 2179
                              LPCWSTR lpOldFile )
{
2180
    FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2181 2182 2183 2184 2185 2186
          debugstr_w(lpNewFile),debugstr_w(lpOldFile));
    return ERROR_SUCCESS;
}


/******************************************************************************
2187
 * RegReplaceKeyA [ADVAPI32.@]
2188
 *
2189
 * See RegReplaceKeyW.
2190
 */
2191
LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2192 2193
                              LPCSTR lpOldFile )
{
2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205
    UNICODE_STRING lpSubKeyW;
    UNICODE_STRING lpNewFileW;
    UNICODE_STRING lpOldFileW;
    LONG ret;

    RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey );
    RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile );
    RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile );
    ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer );
    RtlFreeUnicodeString( &lpOldFileW );
    RtlFreeUnicodeString( &lpNewFileW );
    RtlFreeUnicodeString( &lpSubKeyW );
2206 2207 2208 2209 2210
    return ret;
}


/******************************************************************************
2211
 * RegSetKeySecurity [ADVAPI32.@]
2212
 *
2213 2214
 * Set the security of an open registry key.
 *
2215
 * PARAMS
2216 2217 2218 2219 2220 2221 2222
 *  hkey          [I] Open handle of key to set
 *  SecurityInfo  [I] Descriptor contents
 *  pSecurityDesc [I] Address of descriptor for key
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
2223
 */
2224
LSTATUS WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
2225 2226
                               PSECURITY_DESCRIPTOR pSecurityDesc )
{
2227
    TRACE("(%p,%d,%p)\n",hkey,SecurityInfo,pSecurityDesc);
2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240

    /* It seems to perform this check before the hkey check */
    if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
        (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
        (SecurityInfo & DACL_SECURITY_INFORMATION) ||
        (SecurityInfo & SACL_SECURITY_INFORMATION)) {
        /* Param OK */
    } else
        return ERROR_INVALID_PARAMETER;

    if (!pSecurityDesc)
        return ERROR_INVALID_PARAMETER;

2241
    FIXME(":(%p,%d,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
2242 2243 2244 2245 2246 2247

    return ERROR_SUCCESS;
}


/******************************************************************************
2248
 * RegGetKeySecurity [ADVAPI32.@]
Jon Griffiths's avatar
Jon Griffiths committed
2249 2250
 *
 * Get a copy of the security descriptor for a given registry key.
2251 2252
 *
 * PARAMS
2253 2254 2255 2256
 *  hkey                   [I]   Open handle of key to set
 *  SecurityInformation    [I]   Descriptor contents
 *  pSecurityDescriptor    [O]   Address of descriptor for key
 *  lpcbSecurityDescriptor [I/O] Address of size of buffer and description
2257 2258
 *
 * RETURNS
2259 2260
 *  Success: ERROR_SUCCESS
 *  Failure: Error code
2261
 */
2262
LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInformation,
2263 2264 2265
                               PSECURITY_DESCRIPTOR pSecurityDescriptor,
                               LPDWORD lpcbSecurityDescriptor )
{
2266
    TRACE("(%p,%d,%p,%d)\n",hkey,SecurityInformation,pSecurityDescriptor,
2267
          *lpcbSecurityDescriptor);
2268

2269
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
2270

2271 2272 2273
    return RtlNtStatusToDosError( NtQuerySecurityObject( hkey,
                SecurityInformation, pSecurityDescriptor,
                *lpcbSecurityDescriptor, lpcbSecurityDescriptor ) );
2274 2275 2276 2277
}


/******************************************************************************
2278
 * RegFlushKey [ADVAPI32.@]
Jon Griffiths's avatar
Jon Griffiths committed
2279 2280
 * 
 * Immediately write a registry key to registry.
2281 2282
 *
 * PARAMS
2283
 *  hkey [I] Handle of key to write
2284 2285
 *
 * RETURNS
2286 2287
 *  Success: ERROR_SUCCESS
 *  Failure: Error code
2288
 */
2289
LSTATUS WINAPI RegFlushKey( HKEY hkey )
2290
{
2291 2292 2293 2294
    hkey = get_special_root_hkey( hkey );
    if (!hkey) return ERROR_INVALID_HANDLE;

    return RtlNtStatusToDosError( NtFlushKey( hkey ) );
2295 2296 2297 2298
}


/******************************************************************************
2299
 * RegConnectRegistryW [ADVAPI32.@]
2300
 *
Lei Zhang's avatar
Lei Zhang committed
2301
 * Establish a connection to a predefined registry key on another computer.
2302
 *
2303
 * PARAMS
2304 2305 2306 2307 2308 2309 2310
 *  lpMachineName [I] Address of name of remote computer
 *  hHey          [I] Predefined registry handle
 *  phkResult     [I] Address of buffer for remote registry handle
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
2311
 */
2312
LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
2313
                                   PHKEY phkResult )
2314
{
2315 2316
    LONG ret;

2317
    TRACE("(%s,%p,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
2318 2319 2320

    if (!lpMachineName || !*lpMachineName) {
        /* Use the local machine name */
2321
        ret = RegOpenKeyW( hKey, NULL, phkResult );
2322
    }
2323
    else {
2324 2325
        WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
        DWORD len = sizeof(compName) / sizeof(WCHAR);
2326

2327 2328 2329
        /* MSDN says lpMachineName must start with \\ : not so */
        if( lpMachineName[0] == '\\' &&  lpMachineName[1] == '\\')
            lpMachineName += 2;
2330 2331
        if (GetComputerNameW(compName, &len))
        {
2332
            if (!strcmpiW(lpMachineName, compName))
2333 2334 2335
                ret = RegOpenKeyW(hKey, NULL, phkResult);
            else
            {
2336
                FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName));
2337 2338 2339 2340 2341 2342 2343
                ret = ERROR_BAD_NETPATH;
            }
        }
        else
            ret = GetLastError();
    }
    return ret;
2344 2345 2346 2347
}


/******************************************************************************
2348
 * RegConnectRegistryA [ADVAPI32.@]
2349
 *
2350
 * See RegConnectRegistryW.
2351
 */
2352
LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey )
2353
{
2354 2355 2356 2357 2358 2359
    UNICODE_STRING machineW;
    LONG ret;

    RtlCreateUnicodeStringFromAsciiz( &machineW, machine );
    ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey );
    RtlFreeUnicodeString( &machineW );
2360 2361 2362 2363 2364
    return ret;
}


/******************************************************************************
2365
 * RegNotifyChangeKeyValue [ADVAPI32.@]
2366
 *
2367 2368
 * Notify the caller about changes to the attributes or contents of a registry key.
 *
2369
 * PARAMS
2370 2371 2372 2373 2374 2375 2376 2377 2378
 *  hkey            [I] Handle of key to watch
 *  fWatchSubTree   [I] Flag for subkey notification
 *  fdwNotifyFilter [I] Changes to be reported
 *  hEvent          [I] Handle of signaled event
 *  fAsync          [I] Flag for asynchronous reporting
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
2379
 */
2380
LSTATUS WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
2381 2382 2383
                                     DWORD fdwNotifyFilter, HANDLE hEvent,
                                     BOOL fAsync )
{
2384 2385
    NTSTATUS status;
    IO_STATUS_BLOCK iosb;
2386

2387 2388
    hkey = get_special_root_hkey( hkey );
    if (!hkey) return ERROR_INVALID_HANDLE;
2389

2390
    TRACE("(%p,%i,%d,%p,%i)\n", hkey, fWatchSubTree, fdwNotifyFilter,
2391
          hEvent, fAsync);
2392

2393
    status = NtNotifyChangeKey( hkey, hEvent, NULL, NULL, &iosb,
2394 2395
                                fdwNotifyFilter, fAsync, NULL, 0,
                                fWatchSubTree);
2396

2397 2398 2399 2400
    if (status && status != STATUS_TIMEOUT)
        return RtlNtStatusToDosError( status );

    return ERROR_SUCCESS;
2401
}
2402 2403 2404

/******************************************************************************
 * RegOpenUserClassesRoot [ADVAPI32.@]
Jon Griffiths's avatar
Jon Griffiths committed
2405 2406
 *
 * Open the HKEY_CLASSES_ROOT key for a user.
2407 2408
 *
 * PARAMS
2409
 *  hToken     [I] Handle of token representing the user
Lei Zhang's avatar
Lei Zhang committed
2410
 *  dwOptions  [I] Reserved, must be 0
2411 2412
 *  samDesired [I] Desired access rights
 *  phkResult  [O] Destination for the resulting key handle
2413
 *
2414 2415 2416 2417
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
 * 
Jon Griffiths's avatar
Jon Griffiths committed
2418
 * NOTES
2419 2420 2421
 *  On Windows 2000 and upwards the HKEY_CLASSES_ROOT key is a view of the
 *  "HKEY_LOCAL_MACHINE\Software\Classes" and the
 *  "HKEY_CURRENT_USER\Software\Classes" keys merged together.
2422
 */
2423
LSTATUS WINAPI RegOpenUserClassesRoot(
2424 2425 2426 2427 2428 2429
    HANDLE hToken,
    DWORD dwOptions,
    REGSAM samDesired,
    PHKEY phkResult
)
{
2430
    FIXME("(%p, 0x%x, 0x%x, %p) semi-stub\n", hToken, dwOptions, samDesired, phkResult);
2431 2432 2433 2434

    *phkResult = HKEY_CLASSES_ROOT;
    return ERROR_SUCCESS;
}
2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501

/******************************************************************************
 * load_string [Internal]
 *
 * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
 * avoid importing user32, which is higher level than advapi32. Helper for
 * RegLoadMUIString.
 */
static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
{
    HGLOBAL hMemory;
    HRSRC hResource;
    WCHAR *pString;
    int idxString;

    /* Negative values have to be inverted. */
    if (HIWORD(resId) == 0xffff)
        resId = (UINT)(-((INT)resId));

    /* Load the resource into memory and get a pointer to it. */
    hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
    if (!hResource) return 0;
    hMemory = LoadResource(hModule, hResource);
    if (!hMemory) return 0;
    pString = LockResource(hMemory);

    /* Strings are length-prefixed. Lowest nibble of resId is an index. */
    idxString = resId & 0xf;
    while (idxString--) pString += *pString + 1;

    /* If no buffer is given, return length of the string. */
    if (!pwszBuffer) return *pString;

    /* Else copy over the string, respecting the buffer size. */
    cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
    if (cMaxChars >= 0) {
        memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
        pwszBuffer[cMaxChars] = '\0';
    }

    return cMaxChars;
}

/******************************************************************************
 * RegLoadMUIStringW [ADVAPI32.@]
 *
 * Load the localized version of a string resource from some PE, respective 
 * id and path of which are given in the registry value in the format 
 * @[path]\dllname,-resourceId
 *
 * PARAMS
 *  hKey       [I] Key, of which to load the string value from.
 *  pszValue   [I] The value to be loaded (Has to be of REG_EXPAND_SZ or REG_SZ type).
 *  pszBuffer  [O] Buffer to store the localized string in. 
 *  cbBuffer   [I] Size of the destination buffer in bytes.
 *  pcbData    [O] Number of bytes written to pszBuffer (optional, may be NULL).
 *  dwFlags    [I] None supported yet.
 *  pszBaseDir [I] Not supported yet.
 *
 * RETURNS
 *  Success: ERROR_SUCCESS,
 *  Failure: nonzero error code from winerror.h
 *
 * NOTES
 *  This is an API of Windows Vista, which wasn't available at the time this code
 *  was written. We have to check for the correct behaviour once it's available. 
 */
2502
LSTATUS WINAPI RegLoadMUIStringW(HKEY hKey, LPCWSTR pwszValue, LPWSTR pwszBuffer, DWORD cbBuffer,
2503 2504 2505 2506 2507 2508
    LPDWORD pcbData, DWORD dwFlags, LPCWSTR pwszBaseDir)
{
    DWORD dwValueType, cbData;
    LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
    LONG result;
        
2509 2510
    TRACE("(hKey = %p, pwszValue = %s, pwszBuffer = %p, cbBuffer = %d, pcbData = %p, "
          "dwFlags = %d, pwszBaseDir = %s) stub\n", hKey, debugstr_w(pwszValue), pwszBuffer, 
2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587
          cbBuffer, pcbData, dwFlags, debugstr_w(pwszBaseDir));

    /* Parameter sanity checks. */
    if (!hKey || !pwszBuffer)
        return ERROR_INVALID_PARAMETER;

    if (pwszBaseDir && *pwszBaseDir) {
        FIXME("BaseDir parameter not yet supported!\n");
        return ERROR_INVALID_PARAMETER;
    }

    /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
    result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, NULL, &cbData);
    if (result != ERROR_SUCCESS) goto cleanup;
    if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) {
        result = ERROR_FILE_NOT_FOUND;
        goto cleanup;
    }
    pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
    if (!pwszTempBuffer) {
        result = ERROR_NOT_ENOUGH_MEMORY;
        goto cleanup;
    }
    result = RegQueryValueExW(hKey, pwszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
    if (result != ERROR_SUCCESS) goto cleanup;

    /* Expand environment variables, if appropriate, or copy the original string over. */
    if (dwValueType == REG_EXPAND_SZ) {
        cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
        if (!cbData) goto cleanup;
        pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
        if (!pwszExpandedBuffer) {
            result = ERROR_NOT_ENOUGH_MEMORY;
            goto cleanup;
        }
        ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
    } else {
        pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
        memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
    }

    /* If the value references a resource based string, parse the value and load the string.
     * Else just copy over the original value. */
    result = ERROR_SUCCESS;
    if (*pwszExpandedBuffer != '@') { /* '@' is the prefix for resource based string entries. */
        lstrcpynW(pwszBuffer, pwszExpandedBuffer, cbBuffer / sizeof(WCHAR));
    } else {
        WCHAR *pComma = strrchrW(pwszExpandedBuffer, ',');
        UINT uiStringId;
        HMODULE hModule;

        /* Format of the expanded value is 'path_to_dll,-resId' */
        if (!pComma || pComma[1] != '-') {
            result = ERROR_BADKEY;
            goto cleanup;
        }
 
        uiStringId = atoiW(pComma+2);
        *pComma = '\0';

        hModule = LoadLibraryW(pwszExpandedBuffer + 1);
        if (!hModule || !load_string(hModule, uiStringId, pwszBuffer, cbBuffer/sizeof(WCHAR)))
            result = ERROR_BADKEY;
        FreeLibrary(hModule);
    }
 
cleanup:
    HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
    HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
    return result;
}

/******************************************************************************
 * RegLoadMUIStringA [ADVAPI32.@]
 *
 * See RegLoadMUIStringW
 */
2588
LSTATUS WINAPI RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszBuffer, DWORD cbBuffer,
2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620
    LPDWORD pcbData, DWORD dwFlags, LPCSTR pszBaseDir)
{
    UNICODE_STRING valueW, baseDirW;
    WCHAR *pwszBuffer;
    DWORD cbData = cbBuffer * sizeof(WCHAR);
    LONG result;

    valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
    if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
        !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszBaseDir) ||
        !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
    {
        result = ERROR_NOT_ENOUGH_MEMORY;
        goto cleanup;
    }

    result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, dwFlags, 
                               baseDirW.Buffer);
 
    if (result == ERROR_SUCCESS) {
        cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, cbBuffer, NULL, NULL);
        if (pcbData)
            *pcbData = cbData;
    }

cleanup:
    HeapFree(GetProcessHeap(), 0, pwszBuffer);
    RtlFreeUnicodeString(&baseDirW);
    RtlFreeUnicodeString(&valueW);
 
    return result;
}
2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636

/******************************************************************************
 * RegDisablePredefinedCache [ADVAPI32.@]
 *
 * Disables the caching of the HKEY_CLASSES_ROOT key for the process.
 *
 * PARAMS
 *  None.
 *
 * RETURNS
 *  Success: ERROR_SUCCESS
 *  Failure: nonzero error code from Winerror.h
 * 
 * NOTES
 *  This is useful for services that use impersonation.
 */
2637
LSTATUS WINAPI RegDisablePredefinedCache(void)
2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651
{
    HKEY hkey_current_user;
    int idx = (UINT_PTR)HKEY_CURRENT_USER - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;

    /* prevent caching of future requests */
    hkcu_cache_disabled = TRUE;

    hkey_current_user = InterlockedExchangePointer( (void **)&special_root_keys[idx], NULL );

    if (hkey_current_user)
        NtClose( hkey_current_user );

    return ERROR_SUCCESS;
}
2652 2653 2654 2655 2656

/******************************************************************************
 * RegDeleteTreeW [ADVAPI32.@]
 *
 */
2657
LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728
{
    LONG ret;
    DWORD dwMaxSubkeyLen, dwMaxValueLen;
    DWORD dwMaxLen, dwSize;
    WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
    HKEY hSubKey = hKey;

    TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));

    if(lpszSubKey)
    {
        ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
        if (ret) return ret;
    }

    /* Get highest length for keys, values */
    ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
            &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
    if (ret) goto cleanup;

    dwMaxSubkeyLen++;
    dwMaxValueLen++;
    dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
    if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
    {
        /* Name too big: alloc a buffer for it */
        if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
        {
            ret = ERROR_NOT_ENOUGH_MEMORY;
            goto cleanup;
        }
    }


    /* Recursively delete all the subkeys */
    while (TRUE)
    {
        dwSize = dwMaxLen;
        if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
                          NULL, NULL, NULL)) break;

        ret = RegDeleteTreeW(hSubKey, lpszName);
        if (ret) goto cleanup;
    }

    if (lpszSubKey)
        ret = RegDeleteKeyW(hKey, lpszSubKey);
    else
        while (TRUE)
        {
            dwSize = dwMaxLen;
            if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
                  NULL, NULL, NULL, NULL)) break;

            ret = RegDeleteValueW(hKey, lpszName);
            if (ret) goto cleanup;
        }

cleanup:
    /* Free buffer if allocated */
    if (lpszName != szNameBuf)
        HeapFree( GetProcessHeap(), 0, lpszName);
    if(lpszSubKey)
        RegCloseKey(hSubKey);
    return ret;
}

/******************************************************************************
 * RegDeleteTreeA [ADVAPI32.@]
 *
 */
2729
LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
2730 2731 2732 2733 2734 2735 2736 2737 2738 2739
{
    LONG ret;
    UNICODE_STRING lpszSubKeyW;

    if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
    else lpszSubKeyW.Buffer = NULL;
    ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
    RtlFreeUnicodeString( &lpszSubKeyW );
    return ret;
}