registry.c 55.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Unit tests for registry functions
 *
 * Copyright (c) 2002 Alexandre Julliard
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20 21
 */

#include <assert.h>
22
#include <stdarg.h>
23
#include <stdio.h>
24
#include "wine/test.h"
25
#include "windef.h"
26
#include "winbase.h"
27
#include "winreg.h"
28
#include "winsvc.h"
29 30 31
#include "winerror.h"

static HKEY hkey_main;
32
static DWORD GLE;
33

34 35 36
static const char * sTestpath1 = "%LONGSYSTEMVAR%\\subdir1";
static const char * sTestpath2 = "%FOO%\\subdir1";

37 38
static HMODULE hadvapi32;
static DWORD (WINAPI *pRegGetValueA)(HKEY,LPCSTR,LPCSTR,DWORD,LPDWORD,PVOID,LPDWORD);
39
static DWORD (WINAPI *pRegDeleteTreeA)(HKEY,LPCSTR);
40

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112


/* Debugging functions from wine/libs/wine/debug.c */

/* allocate some tmp string space */
/* FIXME: this is not 100% thread-safe */
static char *get_temp_buffer( int size )
{
    static char *list[32];
    static long pos;
    char *ret;
    int idx;

    idx = ++pos % (sizeof(list)/sizeof(list[0]));
    if ((ret = realloc( list[idx], size ))) list[idx] = ret;
    return ret;
}

static const char *wine_debugstr_an( const char *str, int n )
{
    static const char hex[16] = "0123456789abcdef";
    char *dst, *res;
    size_t size;

    if (!((ULONG_PTR)str >> 16))
    {
        if (!str) return "(null)";
        res = get_temp_buffer( 6 );
        sprintf( res, "#%04x", LOWORD(str) );
        return res;
    }
    if (n == -1) n = strlen(str);
    if (n < 0) n = 0;
    size = 10 + min( 300, n * 4 );
    dst = res = get_temp_buffer( size );
    *dst++ = '"';
    while (n-- > 0 && dst <= res + size - 9)
    {
        unsigned char c = *str++;
        switch (c)
        {
        case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
        case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
        case '\t': *dst++ = '\\'; *dst++ = 't'; break;
        case '"':  *dst++ = '\\'; *dst++ = '"'; break;
        case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
        default:
            if (c >= ' ' && c <= 126)
                *dst++ = c;
            else
            {
                *dst++ = '\\';
                *dst++ = 'x';
                *dst++ = hex[(c >> 4) & 0x0f];
                *dst++ = hex[c & 0x0f];
            }
        }
    }
    *dst++ = '"';
    if (n > 0)
    {
        *dst++ = '.';
        *dst++ = '.';
        *dst++ = '.';
    }
    *dst++ = 0;
    return res;
}

static const char *wine_debugstr_wn( const WCHAR *str, int n )
{
    char *dst, *res;
113
    size_t size;
114 115 116 117 118 119 120 121 122 123

    if (!HIWORD(str))
    {
        if (!str) return "(null)";
        res = get_temp_buffer( 6 );
        sprintf( res, "#%04x", LOWORD(str) );
        return res;
    }
    if (n == -1) n = lstrlenW(str);
    if (n < 0) n = 0;
124
    size = 12 + min( 300, n * 5);
125 126 127
    dst = res = get_temp_buffer( n * 5 + 7 );
    *dst++ = 'L';
    *dst++ = '"';
128
    while (n-- > 0 && dst <= res + size - 10)
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
    {
        WCHAR c = *str++;
        switch (c)
        {
        case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
        case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
        case '\t': *dst++ = '\\'; *dst++ = 't'; break;
        case '"':  *dst++ = '\\'; *dst++ = '"'; break;
        case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
        default:
            if (c >= ' ' && c <= 126)
                *dst++ = (char)c;
            else
            {
                *dst++ = '\\';
                sprintf(dst,"%04x",c);
                dst+=4;
            }
        }
    }
    *dst++ = '"';
150
    if (n > 0)
151 152 153 154 155 156 157 158 159 160
    {
        *dst++ = '.';
        *dst++ = '.';
        *dst++ = '.';
    }
    *dst = 0;
    return res;
}


161 162 163 164 165 166 167 168 169 170 171
#define ADVAPI32_GET_PROC(func) \
    p ## func = (void*)GetProcAddress(hadvapi32, #func); \
    if(!p ## func) \
      trace("GetProcAddress(%s) failed\n", #func);

static void InitFunctionPtrs(void)
{
    hadvapi32 = GetModuleHandleA("advapi32.dll");

    /* This function was introduced with Windows 2003 SP1 */
    ADVAPI32_GET_PROC(RegGetValueA)
172
    ADVAPI32_GET_PROC(RegDeleteTreeA)
173 174
}

175 176 177
/* delete key and all its subkeys */
static DWORD delete_key( HKEY hkey )
{
178
    char name[MAX_PATH];
179 180
    DWORD ret;

181
    while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
182
    {
183
        HKEY tmp;
184
        if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
185 186 187 188 189
        {
            ret = delete_key( tmp );
            RegCloseKey( tmp );
        }
        if (ret) break;
190 191
    }
    if (ret != ERROR_NO_MORE_ITEMS) return ret;
192
    RegDeleteKeyA( hkey, "" );
193 194 195 196 197
    return 0;
}

static void setup_main_key(void)
{
198
    if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main )) delete_key( hkey_main );
199

200
    assert (!RegCreateKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main ));
201 202
}

203 204
static void test_hkey_main_Value_A(LPCSTR name, LPCSTR string,
                                   DWORD full_byte_len)
205 206
{
    DWORD ret, type, cbData;
207 208 209 210 211 212 213 214 215 216
    DWORD str_byte_len;
    LPSTR value;
    static const char nA[]={'N', 0};

    type=0xdeadbeef;
    cbData=0xdeadbeef;
    /* When successful RegQueryValueExA() leaves GLE as is,
     * so we must reset it to detect unimplemented functions.
     */
    SetLastError(0xdeadbeef);
217 218
    ret = RegQueryValueExA(hkey_main, name, NULL, &type, NULL, &cbData);
    GLE = GetLastError();
219
    ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%d\n", ret, GLE);
220 221
    /* It is wrong for the Ansi version to not be implemented */
    ok(GLE == 0xdeadbeef, "RegQueryValueExA set GLE = %u\n", GLE);
222 223
    if(GLE == ERROR_CALL_NOT_IMPLEMENTED) return;

224
    str_byte_len = (string ? lstrlenA(string) : 0) + 1;
225
    ok(type == REG_SZ, "RegQueryValueExA returned type %d\n", type);
226
    ok(cbData == full_byte_len || cbData == str_byte_len /* Win9x */,
227
        "cbData=%d instead of %d or %d\n", cbData, full_byte_len, str_byte_len);
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

    value = HeapAlloc(GetProcessHeap(), 0, (cbData+2)*sizeof(*value));
    strcpy(value, nA);
    type=0xdeadbeef;
    ret = RegQueryValueExA(hkey_main, name, NULL, &type, (BYTE*)value, &cbData);
    GLE = GetLastError();
    ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%d\n", ret, GLE);
    if (!string)
    {
        /* When cbData == 0, RegQueryValueExA() should not modify the buffer */
        ok(strcmp(value, nA) == 0 || (cbData == 1 && *value == '\0') /* Win9x */,
           "RegQueryValueExA failed: '%s' != '%s'\n", value, string);
    }
    else
    {
243 244 245
        ok(memcmp(value, string, cbData) == 0, "RegQueryValueExA failed: %s/%d != %s/%d\n",
           wine_debugstr_an(value, cbData), cbData,
           wine_debugstr_an(string, full_byte_len), full_byte_len);
246 247
    }
    HeapFree(GetProcessHeap(), 0, value);
248 249
}

250 251
static void test_hkey_main_Value_W(LPCWSTR name, LPCWSTR string,
                                   DWORD full_byte_len)
252 253
{
    DWORD ret, type, cbData;
254 255 256 257 258 259 260 261 262
    LPWSTR value;
    static const WCHAR nW[]={'N', 0};

    type=0xdeadbeef;
    cbData=0xdeadbeef;
    /* When successful RegQueryValueExW() leaves GLE as is,
     * so we must reset it to detect unimplemented functions.
     */
    SetLastError(0xdeadbeef);
263 264
    ret = RegQueryValueExW(hkey_main, name, NULL, &type, NULL, &cbData);
    GLE = GetLastError();
265
    ok(ret == ERROR_SUCCESS, "RegQueryValueExW failed: %d, GLE=%d\n", ret, GLE);
266 267 268 269 270
    if(GLE == ERROR_CALL_NOT_IMPLEMENTED)
    {
        win_skip("RegQueryValueExW() is not implemented\n");
        return;
    }
271

272
    ok(type == REG_SZ, "RegQueryValueExW returned type %d\n", type);
273 274 275 276 277 278 279 280 281 282 283 284 285 286
    ok(cbData == full_byte_len,
        "cbData=%d instead of %d\n", cbData, full_byte_len);

    value = HeapAlloc(GetProcessHeap(), 0, (cbData+2)*sizeof(*value));
    lstrcpyW(value, nW);
    type=0xdeadbeef;
    ret = RegQueryValueExW(hkey_main, name, NULL, &type, (BYTE*)value, &cbData);
    GLE = GetLastError();
    ok(ret == ERROR_SUCCESS, "RegQueryValueExW failed: %d, GLE=%d\n", ret, GLE);
    if (!string)
    {
        /* When cbData == 0, RegQueryValueExW() should not modify the buffer */
        string=nW;
    }
287
    ok(memcmp(value, string, cbData) == 0, "RegQueryValueExW failed: %s/%d != %s/%d\n",
288
       wine_debugstr_wn(value, cbData / sizeof(WCHAR)), cbData,
289
       wine_debugstr_wn(string, full_byte_len / sizeof(WCHAR)), full_byte_len);
290
    HeapFree(GetProcessHeap(), 0, value);
291 292 293 294 295 296
}

static void test_set_value(void)
{
    DWORD ret;

297 298
    static const WCHAR name1W[] =   {'C','l','e','a','n','S','i','n','g','l','e','S','t','r','i','n','g', 0};
    static const WCHAR name2W[] =   {'S','o','m','e','I','n','t','r','a','Z','e','r','o','e','d','S','t','r','i','n','g', 0};
299
    static const WCHAR emptyW[] = {0};
300
    static const WCHAR string1W[] = {'T','h','i','s','N','e','v','e','r','B','r','e','a','k','s', 0};
301
    static const WCHAR string2W[] = {'T','h','i','s', 0 ,'B','r','e','a','k','s', 0 , 0 ,'A', 0 , 0 , 0 , 'L','o','t', 0 , 0 , 0 , 0, 0};
302
    static const WCHAR substring2W[] = {'T','h','i','s',0};
303

304 305
    static const char name1A[] =   "CleanSingleString";
    static const char name2A[] =   "SomeIntraZeroedString";
306
    static const char emptyA[] = "";
307 308
    static const char string1A[] = "ThisNeverBreaks";
    static const char string2A[] = "This\0Breaks\0\0A\0\0\0Lot\0\0\0\0";
309 310
    static const char substring2A[] = "This";

311 312 313 314 315 316
    if (0)
    {
        /* Crashes on NT4, Windows 2000 and XP SP1 */
        ret = RegSetValueA(hkey_main, NULL, REG_SZ, NULL, 0);
        ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have failed with ERROR_INVALID_PARAMETER instead of %d\n", ret);
    }
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341

    ret = RegSetValueA(hkey_main, NULL, REG_SZ, string1A, sizeof(string1A));
    ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %d, GLE=%d\n", ret, GetLastError());
    test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
    test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));

    /* RegSetValueA ignores the size passed in */
    ret = RegSetValueA(hkey_main, NULL, REG_SZ, string1A, 4);
    ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %d, GLE=%d\n", ret, GetLastError());
    test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
    test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));

    /* stops at first null */
    ret = RegSetValueA(hkey_main, NULL, REG_SZ, string2A, sizeof(string2A));
    ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %d, GLE=%d\n", ret, GetLastError());
    test_hkey_main_Value_A(NULL, substring2A, sizeof(substring2A));
    test_hkey_main_Value_W(NULL, substring2W, sizeof(substring2W));

    /* only REG_SZ is supported */
    ret = RegSetValueA(hkey_main, NULL, REG_BINARY, string2A, sizeof(string2A));
    ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
    ret = RegSetValueA(hkey_main, NULL, REG_EXPAND_SZ, string2A, sizeof(string2A));
    ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
    ret = RegSetValueA(hkey_main, NULL, REG_MULTI_SZ, string2A, sizeof(string2A));
    ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
342

343 344 345 346 347 348 349 350 351 352 353 354 355 356
    /* Test RegSetValueExA with a 'zero-byte' string (as Office 2003 does).
     * Surprisingly enough we're supposed to get zero bytes out of it.
     */
    ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)emptyA, 0);
    ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
    test_hkey_main_Value_A(name1A, NULL, 0);
    test_hkey_main_Value_W(name1W, NULL, 0);

    /* test RegSetValueExA with an empty string */
    ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)emptyA, sizeof(emptyA));
    ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
    test_hkey_main_Value_A(name1A, emptyA, sizeof(emptyA));
    test_hkey_main_Value_W(name1W, emptyW, sizeof(emptyW));

357 358 359 360 361 362
    /* test RegSetValueExA with off-by-one size */
    ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)string1A, sizeof(string1A)-sizeof(string1A[0]));
    ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
    test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
    test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));

363
    /* test RegSetValueExA with normal string */
364
    ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)string1A, sizeof(string1A));
365
    ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
366 367
    test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
    test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
368 369

    /* test RegSetValueExA with intrazeroed string */
370
    ret = RegSetValueExA(hkey_main, name2A, 0, REG_SZ, (const BYTE *)string2A, sizeof(string2A));
371
    ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
372 373
    test_hkey_main_Value_A(name2A, string2A, sizeof(string2A));
    test_hkey_main_Value_W(name2W, string2W, sizeof(string2W));
374 375 376 377

    /* 9x doesn't support W-calls, so don't test them then */
    if(GLE == ERROR_CALL_NOT_IMPLEMENTED) return; 

378 379 380 381 382 383
    if (0)
    {
        /* Crashes on NT4, Windows 2000 and XP SP1 */
        ret = RegSetValueW(hkey_main, NULL, REG_SZ, NULL, 0);
        ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have failed with ERROR_INVALID_PARAMETER instead of %d\n", ret);
    }
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409

    ret = RegSetValueW(hkey_main, NULL, REG_SZ, string1W, sizeof(string1W));
    ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %d, GLE=%d\n", ret, GetLastError());
    test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
    test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));

    /* RegSetValueA ignores the size passed in */
    ret = RegSetValueW(hkey_main, NULL, REG_SZ, string1W, 4 * sizeof(string1W[0]));
    ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %d, GLE=%d\n", ret, GetLastError());
    test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
    test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));

    /* stops at first null */
    ret = RegSetValueW(hkey_main, NULL, REG_SZ, string2W, sizeof(string2W));
    ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %d, GLE=%d\n", ret, GetLastError());
    test_hkey_main_Value_A(NULL, substring2A, sizeof(substring2A));
    test_hkey_main_Value_W(NULL, substring2W, sizeof(substring2W));

    /* only REG_SZ is supported */
    ret = RegSetValueW(hkey_main, NULL, REG_BINARY, string2W, sizeof(string2W));
    ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
    ret = RegSetValueW(hkey_main, NULL, REG_EXPAND_SZ, string2W, sizeof(string2W));
    ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
    ret = RegSetValueW(hkey_main, NULL, REG_MULTI_SZ, string2W, sizeof(string2W));
    ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);

410 411 412 413 414 415
    /* test RegSetValueExW with off-by-one size */
    ret = RegSetValueExW(hkey_main, name1W, 0, REG_SZ, (const BYTE *)string1W, sizeof(string1W)-sizeof(string1W[0]));
    ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %d, GLE=%d\n", ret, GetLastError());
    test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
    test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));

416
    /* test RegSetValueExW with normal string */
417
    ret = RegSetValueExW(hkey_main, name1W, 0, REG_SZ, (const BYTE *)string1W, sizeof(string1W));
418
    ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %d, GLE=%d\n", ret, GetLastError());
419 420
    test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
    test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
421 422

    /* test RegSetValueExW with intrazeroed string */
423
    ret = RegSetValueExW(hkey_main, name2W, 0, REG_SZ, (const BYTE *)string2W, sizeof(string2W));
424
    ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %d, GLE=%d\n", ret, GetLastError());
425 426
    test_hkey_main_Value_A(name2A, string2A, sizeof(string2A));
    test_hkey_main_Value_W(name2W, string2W, sizeof(string2W));
427 428
}

429 430
static void create_test_entries(void)
{
431
    static const DWORD qw[2] = { 0x12345678, 0x87654321 };
432

433 434 435
    SetEnvironmentVariableA("LONGSYSTEMVAR", "bar");
    SetEnvironmentVariableA("FOO", "ImARatherLongButIndeedNeededString");

436
    ok(!RegSetValueExA(hkey_main,"TP1_EXP_SZ",0,REG_EXPAND_SZ, (const BYTE *)sTestpath1, strlen(sTestpath1)+1), 
437
        "RegSetValueExA failed\n");
438
    ok(!RegSetValueExA(hkey_main,"TP1_SZ",0,REG_SZ, (const BYTE *)sTestpath1, strlen(sTestpath1)+1), 
439
        "RegSetValueExA failed\n");
440 441
    ok(!RegSetValueExA(hkey_main,"TP1_ZB_SZ",0,REG_SZ, NULL, 0),
       "RegSetValueExA failed\n");
442
    ok(!RegSetValueExA(hkey_main,"TP2_EXP_SZ",0,REG_EXPAND_SZ, (const BYTE *)sTestpath2, strlen(sTestpath2)+1), 
443
        "RegSetValueExA failed\n");
444
    ok(!RegSetValueExA(hkey_main,"DWORD",0,REG_DWORD, (const BYTE *)qw, 4),
445
        "RegSetValueExA failed\n");
446
    ok(!RegSetValueExA(hkey_main,"BIN32",0,REG_BINARY, (const BYTE *)qw, 4),
447
        "RegSetValueExA failed\n");
448
    ok(!RegSetValueExA(hkey_main,"BIN64",0,REG_BINARY, (const BYTE *)qw, 8),
449
        "RegSetValueExA failed\n");
450 451
}
        
452 453 454
static void test_enum_value(void)
{
    DWORD res;
455
    HKEY test_key;
456 457 458 459 460 461 462
    char value[20], data[20];
    WCHAR valueW[20], dataW[20];
    DWORD val_count, data_count, type;
    static const WCHAR foobarW[] = {'f','o','o','b','a','r',0};
    static const WCHAR testW[] = {'T','e','s','t',0};
    static const WCHAR xxxW[] = {'x','x','x','x','x','x','x','x',0};

463 464
    /* create the working key for new 'Test' value */
    res = RegCreateKeyA( hkey_main, "TestKey", &test_key );
465
    ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res);
466

467
    /* check NULL data with zero length */
468
    res = RegSetValueExA( test_key, "Test", 0, REG_SZ, NULL, 0 );
469
    if (GetVersion() & 0x80000000)
470
        ok( res == ERROR_INVALID_PARAMETER, "RegSetValueExA returned %d\n", res );
471
    else
472
        ok( !res, "RegSetValueExA returned %d\n", res );
473
    res = RegSetValueExA( test_key, "Test", 0, REG_EXPAND_SZ, NULL, 0 );
474
    ok( ERROR_SUCCESS == res || ERROR_INVALID_PARAMETER == res, "RegSetValueExA returned %d\n", res );
475
    res = RegSetValueExA( test_key, "Test", 0, REG_BINARY, NULL, 0 );
476
    ok( ERROR_SUCCESS == res || ERROR_INVALID_PARAMETER == res, "RegSetValueExA returned %d\n", res );
477

478
    res = RegSetValueExA( test_key, "Test", 0, REG_SZ, (const BYTE *)"foobar", 7 );
479
    ok( res == 0, "RegSetValueExA failed error %d\n", res );
480 481 482 483 484 485 486

    /* overflow both name and data */
    val_count = 2;
    data_count = 2;
    type = 1234;
    strcpy( value, "xxxxxxxxxx" );
    strcpy( data, "xxxxxxxxxx" );
487
    res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
488 489 490 491
    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
    ok( val_count == 2, "val_count set to %d\n", val_count );
    ok( data_count == 7, "data_count set to %d instead of 7\n", data_count );
    ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
492 493
    ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
    ok( !strcmp( data, "xxxxxxxxxx" ), "data set to '%s'\n", data );
494 495 496 497 498 499 500

    /* overflow name */
    val_count = 3;
    data_count = 20;
    type = 1234;
    strcpy( value, "xxxxxxxxxx" );
    strcpy( data, "xxxxxxxxxx" );
501
    res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
502
    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
503
    /* Win9x returns 2 as specified by MSDN but NT returns 3... */
504 505 506
    ok( val_count == 2 || val_count == 3, "val_count set to %d\n", val_count );
    ok( data_count == 7, "data_count set to %d instead of 7\n", data_count );
    ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
Austin English's avatar
Austin English committed
507
    /* v5.1.2600.0 (XP Home and Professional) does not touch value or data in this case */
508 509 510 511
    ok( !strcmp( value, "Te" ) || !strcmp( value, "xxxxxxxxxx" ), 
        "value set to '%s' instead of 'Te' or 'xxxxxxxxxx'\n", value );
    ok( !strcmp( data, "foobar" ) || !strcmp( data, "xxxxxxx" ), 
        "data set to '%s' instead of 'foobar' or 'xxxxxxx'\n", data );
512 513 514 515 516 517 518

    /* overflow empty name */
    val_count = 0;
    data_count = 20;
    type = 1234;
    strcpy( value, "xxxxxxxxxx" );
    strcpy( data, "xxxxxxxxxx" );
519
    res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
520 521 522 523
    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
    ok( val_count == 0, "val_count set to %d\n", val_count );
    ok( data_count == 7, "data_count set to %d instead of 7\n", data_count );
    ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
524
    ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
525 526 527
    /* v5.1.2600.0 (XP Home and Professional) does not touch data in this case */
    ok( !strcmp( data, "foobar" ) || !strcmp( data, "xxxxxxx" ), 
        "data set to '%s' instead of 'foobar' or 'xxxxxxx'\n", data );
528 529 530 531 532 533 534

    /* overflow data */
    val_count = 20;
    data_count = 2;
    type = 1234;
    strcpy( value, "xxxxxxxxxx" );
    strcpy( data, "xxxxxxxxxx" );
535
    res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
536 537 538 539
    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
    ok( val_count == 20, "val_count set to %d\n", val_count );
    ok( data_count == 7, "data_count set to %d instead of 7\n", data_count );
    ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
540 541
    ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
    ok( !strcmp( data, "xxxxxxxxxx" ), "data set to '%s'\n", data );
542 543 544 545 546 547 548

    /* no overflow */
    val_count = 20;
    data_count = 20;
    type = 1234;
    strcpy( value, "xxxxxxxxxx" );
    strcpy( data, "xxxxxxxxxx" );
549
    res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
550 551 552 553
    ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res );
    ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
    ok( data_count == 7, "data_count set to %d instead of 7\n", data_count );
    ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
554 555
    ok( !strcmp( value, "Test" ), "value is '%s' instead of Test\n", value );
    ok( !strcmp( data, "foobar" ), "data is '%s' instead of foobar\n", data );
556 557 558

    /* Unicode tests */

559
    SetLastError(0xdeadbeef);
560
    res = RegSetValueExW( test_key, testW, 0, REG_SZ, (const BYTE *)foobarW, 7*sizeof(WCHAR) );
561
    if (res==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
562
    {
563
        win_skip("RegSetValueExW is not implemented\n");
564 565
        goto cleanup;
    }
566
    ok( res == 0, "RegSetValueExW failed error %d\n", res );
567 568 569 570 571 572 573

    /* overflow both name and data */
    val_count = 2;
    data_count = 2;
    type = 1234;
    memcpy( valueW, xxxW, sizeof(xxxW) );
    memcpy( dataW, xxxW, sizeof(xxxW) );
574
    res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
575 576 577 578
    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
    ok( val_count == 2, "val_count set to %d\n", val_count );
    ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
    ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
579 580
    ok( !memcmp( valueW, xxxW, sizeof(xxxW) ), "value modified\n" );
    ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data modified\n" );
581 582 583 584 585 586 587

    /* overflow name */
    val_count = 3;
    data_count = 20;
    type = 1234;
    memcpy( valueW, xxxW, sizeof(xxxW) );
    memcpy( dataW, xxxW, sizeof(xxxW) );
588
    res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
589 590 591 592
    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
    ok( val_count == 3, "val_count set to %d\n", val_count );
    ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
    ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
593 594
    ok( !memcmp( valueW, xxxW, sizeof(xxxW) ), "value modified\n" );
    ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data modified\n" );
595 596 597 598 599 600 601

    /* overflow data */
    val_count = 20;
    data_count = 2;
    type = 1234;
    memcpy( valueW, xxxW, sizeof(xxxW) );
    memcpy( dataW, xxxW, sizeof(xxxW) );
602
    res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
603 604 605 606
    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
    ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
    ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
    ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
607 608
    ok( !memcmp( valueW, testW, sizeof(testW) ), "value is not 'Test'\n" );
    ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data modified\n" );
609 610 611 612 613 614 615

    /* no overflow */
    val_count = 20;
    data_count = 20;
    type = 1234;
    memcpy( valueW, xxxW, sizeof(xxxW) );
    memcpy( dataW, xxxW, sizeof(xxxW) );
616
    res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
617 618 619 620
    ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res );
    ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
    ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
    ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
621 622
    ok( !memcmp( valueW, testW, sizeof(testW) ), "value is not 'Test'\n" );
    ok( !memcmp( dataW, foobarW, sizeof(foobarW) ), "data is not 'foobar'\n" );
623 624 625 626

cleanup:
    RegDeleteKeyA(test_key, "");
    RegCloseKey(test_key);
627 628
}

629
static void test_query_value_ex(void)
630 631 632 633
{
    DWORD ret;
    DWORD size;
    DWORD type;
634
    BYTE buffer[10];
635
    
636
    ret = RegQueryValueExA(hkey_main, "TP1_SZ", NULL, &type, NULL, &size);
637 638 639
    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
    ok(size == strlen(sTestpath1) + 1, "(%d,%d)\n", (DWORD)strlen(sTestpath1) + 1, size);
    ok(type == REG_SZ, "type %d is not REG_SZ\n", type);
640 641 642

    type = 0xdeadbeef;
    size = 0xdeadbeef;
643
    ret = RegQueryValueExA(HKEY_CLASSES_ROOT, "Nonexistent Value", NULL, &type, NULL, &size);
644
    ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
645
    /* the type parameter is cleared on Win9x, but is set to a random value on
646 647 648
     * NT, so don't do that test there. The size parameter is left untouched on Win9x
     * but cleared on NT+, this can be tested on all platforms.
     */
649
    if (GetVersion() & 0x80000000)
650
    {
651
        ok(type == 0, "type should have been set to 0 instead of 0x%x\n", type);
652 653
        ok(size == 0xdeadbeef, "size should have been left untouched (0xdeadbeef)\n");
    }
654
    else
655
    {
656
        trace("test_query_value_ex: type set to: 0x%08x\n", type);
657 658
        ok(size == 0, "size should have been set to 0 instead of %d\n", size);
    }
659 660

    size = sizeof(buffer);
661
    ret = RegQueryValueExA(HKEY_CLASSES_ROOT, "Nonexistent Value", NULL, &type, buffer, &size);
662 663
    ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
    ok(size == sizeof(buffer), "size shouldn't have been changed to %d\n", size);
664 665 666 667

    size = 4;
    ret = RegQueryValueExA(hkey_main, "BIN32", NULL, &size, buffer, &size);
    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
668 669
}

670 671 672 673 674 675 676 677
static void test_get_value(void)
{
    DWORD ret;
    DWORD size;
    DWORD type;
    DWORD dw, qw[2];
    CHAR buf[80];
    CHAR expanded[] = "bar\\subdir1";
678
    CHAR expanded2[] = "ImARatherLongButIndeedNeededString\\subdir1";
679
   
680
    if(!pRegGetValueA)
681
    {
682
        win_skip("RegGetValue not available on this platform\n");
683 684
        return;
    }
685

686 687 688 689
    /* Invalid parameter */
    ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD, &type, &dw, NULL);
    ok(ret == ERROR_INVALID_PARAMETER, "ret=%d\n", ret);

690 691 692
    /* Query REG_DWORD using RRF_RT_REG_DWORD (ok) */
    size = type = dw = 0xdeadbeef;
    ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD, &type, &dw, &size);
693 694 695 696
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
    ok(size == 4, "size=%d\n", size);
    ok(type == REG_DWORD, "type=%d\n", type);
    ok(dw == 0x12345678, "dw=%d\n", dw);
697 698 699

    /* Query by subkey-name */
    ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD, NULL, NULL, NULL);
700
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
701 702 703 704

    /* Query REG_DWORD using RRF_RT_REG_BINARY (restricted) */
    size = type = dw = 0xdeadbeef;
    ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_BINARY, &type, &dw, &size);
705
    ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
706
    /* Although the function failed all values are retrieved */
707 708 709
    ok(size == 4, "size=%d\n", size);
    ok(type == REG_DWORD, "type=%d\n", type);
    ok(dw == 0x12345678, "dw=%d\n", dw);
710 711 712 713

    /* Test RRF_ZEROONFAILURE */
    type = dw = 0xdeadbeef; size = 4;
    ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_SZ|RRF_ZEROONFAILURE, &type, &dw, &size);
714
    ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
715
    /* Again all values are retrieved ... */
716 717
    ok(size == 4, "size=%d\n", size);
    ok(type == REG_DWORD, "type=%d\n", type);
718
    /* ... except the buffer, which is zeroed out */
719
    ok(dw == 0, "dw=%d\n", dw);
720

721 722 723 724 725 726 727
    /* Test RRF_ZEROONFAILURE with a NULL buffer... */
    type = size = 0xbadbeef;
    ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_SZ|RRF_ZEROONFAILURE, &type, NULL, &size);
    ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
    ok(size == 4, "size=%d\n", size);
    ok(type == REG_DWORD, "type=%d\n", type);

728 729 730
    /* Query REG_DWORD using RRF_RT_DWORD (ok) */
    size = type = dw = 0xdeadbeef;
    ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_DWORD, &type, &dw, &size);
731 732 733 734
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
    ok(size == 4, "size=%d\n", size);
    ok(type == REG_DWORD, "type=%d\n", type);
    ok(dw == 0x12345678, "dw=%d\n", dw);
735 736 737 738

    /* Query 32-bit REG_BINARY using RRF_RT_DWORD (ok) */
    size = type = dw = 0xdeadbeef;
    ret = pRegGetValueA(hkey_main, NULL, "BIN32", RRF_RT_DWORD, &type, &dw, &size);
739 740 741 742
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
    ok(size == 4, "size=%d\n", size);
    ok(type == REG_BINARY, "type=%d\n", type);
    ok(dw == 0x12345678, "dw=%d\n", dw);
743 744 745 746
    
    /* Query 64-bit REG_BINARY using RRF_RT_DWORD (type mismatch) */
    qw[0] = qw[1] = size = type = 0xdeadbeef;
    ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_DWORD, &type, qw, &size);
747 748 749
    ok(ret == ERROR_DATATYPE_MISMATCH, "ret=%d\n", ret);
    ok(size == 8, "size=%d\n", size);
    ok(type == REG_BINARY, "type=%d\n", type);
750
    ok(qw[0] == 0x12345678 && 
751
       qw[1] == 0x87654321, "qw={%d,%d}\n", qw[0], qw[1]);
752 753 754 755
    
    /* Query 64-bit REG_BINARY using 32-bit buffer (buffer too small) */
    type = dw = 0xdeadbeef; size = 4;
    ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_REG_BINARY, &type, &dw, &size);
756 757 758
    ok(ret == ERROR_MORE_DATA, "ret=%d\n", ret);
    ok(dw == 0xdeadbeef, "dw=%d\n", dw);
    ok(size == 8, "size=%d\n", size);
759 760 761 762

    /* Query 64-bit REG_BINARY using RRF_RT_QWORD (ok) */
    qw[0] = qw[1] = size = type = 0xdeadbeef;
    ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_QWORD, &type, qw, &size);
763 764 765
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
    ok(size == 8, "size=%d\n", size);
    ok(type == REG_BINARY, "type=%d\n", type);
766
    ok(qw[0] == 0x12345678 &&
767
       qw[1] == 0x87654321, "qw={%d,%d}\n", qw[0], qw[1]);
768

769
    /* Query REG_SZ using RRF_RT_REG_SZ (ok) */
770
    buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
771
    ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ, &type, buf, &size);
772 773 774
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
    ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
    ok(type == REG_SZ, "type=%d\n", type);
775
    ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
776

777 778 779 780 781
    /* Query REG_SZ using RRF_RT_REG_SZ and no buffer (ok) */
    type = 0xdeadbeef; size = 0;
    ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ, &type, NULL, &size);
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
    /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
782
    ok(size == strlen(sTestpath1)+1 || broken(size == strlen(sTestpath1)+2),
783 784 785
       "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
    ok(type == REG_SZ, "type=%d\n", type);

786 787 788 789 790 791 792
    /* Query REG_SZ using RRF_RT_REG_SZ on a zero-byte value (ok) */
    strcpy(buf, sTestpath1);
    type = 0xdeadbeef;
    size = sizeof(buf);
    ret = pRegGetValueA(hkey_main, NULL, "TP1_ZB_SZ", RRF_RT_REG_SZ, &type, buf, &size);
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
    /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
793 794 795
    ok(size == 0 ||
       size == 1, /* win2k3 */
       "size=%d\n", size);
796
    ok(type == REG_SZ, "type=%d\n", type);
797 798 799
    ok(!strcmp(sTestpath1, buf) ||
       !strcmp(buf, ""),
       "Expected \"%s\" or \"\", got \"%s\"\n", sTestpath1, buf);
800

801
    /* Query REG_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (ok) */
802
    buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
803
    ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ|RRF_NOEXPAND, &type, buf, &size);
804 805 806
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
    ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
    ok(type == REG_SZ, "type=%d\n", type);
807 808
    ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);

809
    /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ and no buffer (ok, expands) */
810
    size = 0;
811
    ret = pRegGetValueA(hkey_main, NULL, "TP2_EXP_SZ", RRF_RT_REG_SZ, NULL, NULL, &size);
812
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
813 814 815
    ok((size == strlen(expanded2)+1) || /* win2k3 SP1 */
       (size == strlen(expanded2)+2) || /* win2k3 SP2 */
       (size == strlen(sTestpath2)+1),
816
        "strlen(expanded2)=%d, strlen(sTestpath2)=%d, size=%d\n", lstrlenA(expanded2), lstrlenA(sTestpath2), size);
817

818
    /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ (ok, expands) */
819
    buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
820
    ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_SZ, &type, buf, &size);
821
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
822
    /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath1 length + 1 here. */
823
    ok(size == strlen(expanded)+1 || broken(size == strlen(sTestpath1)+1),
824 825
        "strlen(expanded)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded), lstrlenA(sTestpath1), size);
    ok(type == REG_SZ, "type=%d\n", type);
826
    ok(!strcmp(expanded, buf), "expanded=\"%s\" buf=\"%s\"\n", expanded, buf);
827 828 829 830 831 832

    /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ (ok, expands a lot) */
    buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
    ret = pRegGetValueA(hkey_main, NULL, "TP2_EXP_SZ", RRF_RT_REG_SZ, &type, buf, &size);
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
    /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath2 length + 1 here. */
833
    ok(size == strlen(expanded2)+1 || broken(size == strlen(sTestpath2)+1),
834 835 836 837
        "strlen(expanded2)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded2), lstrlenA(sTestpath2), size);
    ok(type == REG_SZ, "type=%d\n", type);
    ok(!strcmp(expanded2, buf), "expanded2=\"%s\" buf=\"%s\"\n", expanded2, buf);

838 839 840
    /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND (ok, doesn't expand) */
    buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
    ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND, &type, buf, &size);
841 842 843
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
    ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
    ok(type == REG_EXPAND_SZ, "type=%d\n", type);
844
    ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
845 846 847 848 849 850

    /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND and no buffer (ok, doesn't expand) */
    size = 0xbadbeef;
    ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND, NULL, NULL, &size);
    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
    /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
851
    ok(size == strlen(sTestpath1)+1 || broken(size == strlen(sTestpath1)+2),
852 853
       "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);

854 855
    /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (type mismatch) */
    ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_SZ|RRF_NOEXPAND, NULL, NULL, NULL);
856
    ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
857 858 859

    /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ (not allowed without RRF_NOEXPAND) */
    ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ, NULL, NULL, NULL);
860
    ok(ret == ERROR_INVALID_PARAMETER, "ret=%d\n", ret);
861 862
} 

863
static void test_reg_open_key(void)
864 865 866 867 868 869 870
{
    DWORD ret = 0;
    HKEY hkResult = NULL;
    HKEY hkPreserve = NULL;

    /* successful open */
    ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
871
    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
872 873 874
    ok(hkResult != NULL, "expected hkResult != NULL\n");
    hkPreserve = hkResult;

875 876 877 878 879 880
    /* these tests fail on Win9x, but we want to be compatible with NT, so
     * run them if we can */
    if (!(GetVersion() & 0x80000000))
    {
        /* open same key twice */
        ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
881
        ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
882 883 884 885 886 887 888 889 890
        ok(hkResult != hkPreserve, "epxected hkResult != hkPreserve\n");
        ok(hkResult != NULL, "hkResult != NULL\n");
        RegCloseKey(hkResult);
    
        /* open nonexistent key
        * check that hkResult is set to NULL
        */
        hkResult = hkPreserve;
        ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Nonexistent", &hkResult);
891
        ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
892 893 894 895 896
        ok(hkResult == NULL, "expected hkResult == NULL\n");
    
        /* open the same nonexistent key again to make sure the key wasn't created */
        hkResult = hkPreserve;
        ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Nonexistent", &hkResult);
897
        ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
898 899 900 901 902 903 904
        ok(hkResult == NULL, "expected hkResult == NULL\n");
    
        /* send in NULL lpSubKey
        * check that hkResult receives the value of hKey
        */
        hkResult = hkPreserve;
        ret = RegOpenKeyA(HKEY_CURRENT_USER, NULL, &hkResult);
905
        ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
906 907 908 909 910
        ok(hkResult == HKEY_CURRENT_USER, "expected hkResult == HKEY_CURRENT_USER\n");
    
        /* send empty-string in lpSubKey */
        hkResult = hkPreserve;
        ret = RegOpenKeyA(HKEY_CURRENT_USER, "", &hkResult);
911
        ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
912 913 914 915 916 917 918
        ok(hkResult == HKEY_CURRENT_USER, "expected hkResult == HKEY_CURRENT_USER\n");
    
        /* send in NULL lpSubKey and NULL hKey
        * hkResult is set to NULL
        */
        hkResult = hkPreserve;
        ret = RegOpenKeyA(NULL, NULL, &hkResult);
919
        ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
920 921
        ok(hkResult == NULL, "expected hkResult == NULL\n");
    }
922 923 924 925 926 927

    /* only send NULL hKey
     * the value of hkResult remains unchanged
     */
    hkResult = hkPreserve;
    ret = RegOpenKeyA(NULL, "Software\\Wine\\Test", &hkResult);
928
    ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 95 returns BADKEY */
929
       "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
930 931 932 933 934
    ok(hkResult == hkPreserve, "expected hkResult == hkPreserve\n");
    RegCloseKey(hkResult);

    /* send in NULL hkResult */
    ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", NULL);
935
    ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", ret);
936 937 938 939 940

    /*  beginning backslash character */
    ret = RegOpenKeyA(HKEY_CURRENT_USER, "\\Software\\Wine\\Test", &hkResult);
       ok(ret == ERROR_BAD_PATHNAME || /* NT/2k/XP */
           ret == ERROR_FILE_NOT_FOUND /* Win9x,ME */
941
           , "expected ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret);
942 943
}

944
static void test_reg_create_key(void)
945 946 947 948
{
    LONG ret;
    HKEY hkey1, hkey2;
    ret = RegCreateKeyExA(hkey_main, "Subkey1", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
949
    ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
950 951 952
    /* should succeed: all versions of Windows ignore the access rights
     * to the parent handle */
    ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey2, NULL);
953
    ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
954 955

    /* clean up */
956 957
    RegDeleteKey(hkey2, "");
    RegDeleteKey(hkey1, "");
958 959 960 961

    /*  beginning backslash character */
    ret = RegCreateKeyExA(hkey_main, "\\Subkey3", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
    if (!(GetVersion() & 0x80000000))
962
        ok(ret == ERROR_BAD_PATHNAME, "expected ERROR_BAD_PATHNAME, got %d\n", ret);
963
    else {
964
        ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
965 966
        RegDeleteKey(hkey1, NULL);
    }
967 968
}

969
static void test_reg_close_key(void)
970 971 972 973 974 975 976 977 978
{
    DWORD ret = 0;
    HKEY hkHandle;

    /* successfully close key
     * hkHandle remains changed after call to RegCloseKey
     */
    ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkHandle);
    ret = RegCloseKey(hkHandle);
979
    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
980 981

    /* try to close the key twice */
982
    ret = RegCloseKey(hkHandle); /* Windows 95 doesn't mind. */
983
    ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_SUCCESS,
984
       "expected ERROR_INVALID_HANDLE or ERROR_SUCCESS, got %d\n", ret);
985
    
986 987
    /* try to close a NULL handle */
    ret = RegCloseKey(NULL);
988
    ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 95 returns BADKEY */
989
       "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
990 991 992 993 994 995 996 997 998 999

    /* Check to see if we didn't potentially close our main handle, which could happen on win98 as
     * win98 doesn't give a new handle when the same key is opened.
     * Not re-opening will make some next tests fail.
     */
    if (hkey_main == hkHandle)
    {
        trace("The main handle is most likely closed, so re-opening\n");
        RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main );
    }
1000 1001
}

1002
static void test_reg_delete_key(void)
1003 1004 1005 1006
{
    DWORD ret;

    ret = RegDeleteKey(hkey_main, NULL);
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022

    /* There is a bug in NT4 and W2K that doesn't check if the subkey is NULL. If
     * there are also no subkeys available it will delete the key pointed to by hkey_main.
     * Not re-creating will make some next tests fail.
     */
    if (ret == ERROR_SUCCESS)
    {
        trace("We are probably running on NT4 or W2K as the main key is deleted,"
            " re-creating the main key\n");
        setup_main_key();
    }
    else
        ok(ret == ERROR_INVALID_PARAMETER ||
           ret == ERROR_ACCESS_DENIED ||
           ret == ERROR_BADKEY, /* Win95 */
           "ret=%d\n", ret);
1023 1024
}

1025
static void test_reg_save_key(void)
1026 1027 1028 1029
{
    DWORD ret;

    ret = RegSaveKey(hkey_main, "saved_key", NULL);
1030
    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1031 1032
}

1033
static void test_reg_load_key(void)
1034 1035 1036 1037 1038
{
    DWORD ret;
    HKEY hkHandle;

    ret = RegLoadKey(HKEY_LOCAL_MACHINE, "Test", "saved_key");
1039
    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1040 1041

    ret = RegOpenKey(HKEY_LOCAL_MACHINE, "Test", &hkHandle);
1042
    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1043

James Hawkins's avatar
James Hawkins committed
1044 1045 1046
    RegCloseKey(hkHandle);
}

1047
static void test_reg_unload_key(void)
James Hawkins's avatar
James Hawkins committed
1048 1049 1050 1051
{
    DWORD ret;

    ret = RegUnLoadKey(HKEY_LOCAL_MACHINE, "Test");
1052
    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
James Hawkins's avatar
James Hawkins committed
1053

1054
    DeleteFile("saved_key");
Ivan Leo Puoti's avatar
Ivan Leo Puoti committed
1055
    DeleteFile("saved_key.LOG");
1056 1057
}

1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
static BOOL set_privileges(LPCSTR privilege, BOOL set)
{
    TOKEN_PRIVILEGES tp;
    HANDLE hToken;
    LUID luid;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
        return FALSE;

    if(!LookupPrivilegeValue(NULL, privilege, &luid))
    {
        CloseHandle(hToken);
        return FALSE;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    
    if (set)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
    if (GetLastError() != ERROR_SUCCESS)
    {
        CloseHandle(hToken);
        return FALSE;
    }

    CloseHandle(hToken);
    return TRUE;
}

1092 1093 1094 1095 1096 1097
/* tests that show that RegConnectRegistry and 
   OpenSCManager accept computer names without the
   \\ prefix (what MSDN says).   */
static void test_regconnectregistry( void)
{
    CHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
1098
    CHAR netwName[MAX_COMPUTERNAME_LENGTH + 3]; /* 2 chars for double backslash */
1099 1100 1101 1102 1103 1104
    DWORD len = sizeof(compName) ;
    BOOL ret;
    LONG retl;
    HKEY hkey;
    SC_HANDLE schnd;

1105
    SetLastError(0xdeadbeef);
1106
    ret = GetComputerNameA(compName, &len);
1107
    ok( ret, "GetComputerName failed err = %d\n", GetLastError());
1108 1109
    if( !ret) return;

1110 1111 1112
    lstrcpyA(netwName, "\\\\");
    lstrcpynA(netwName+2, compName, MAX_COMPUTERNAME_LENGTH + 1);

1113
    retl = RegConnectRegistryA( compName, HKEY_LOCAL_MACHINE, &hkey);
1114 1115 1116 1117
    ok( !retl ||
        retl == ERROR_DLL_INIT_FAILED ||
        retl == ERROR_BAD_NETPATH, /* some win2k */
        "RegConnectRegistryA failed err = %d\n", retl);
1118 1119 1120
    if( !retl) RegCloseKey( hkey);

    retl = RegConnectRegistryA( netwName, HKEY_LOCAL_MACHINE, &hkey);
1121 1122 1123 1124
    ok( !retl ||
        retl == ERROR_DLL_INIT_FAILED ||
        retl == ERROR_BAD_NETPATH, /* some win2k */
        "RegConnectRegistryA failed err = %d\n", retl);
1125 1126
    if( !retl) RegCloseKey( hkey);

1127
    SetLastError(0xdeadbeef);
1128
    schnd = OpenSCManagerA( compName, NULL, GENERIC_READ); 
1129 1130
    if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
    {
1131
        win_skip("OpenSCManagerA is not implemented\n");
1132 1133 1134 1135
        return;
    }

    ok( schnd != NULL, "OpenSCManagerA failed err = %d\n", GetLastError());
1136 1137
    CloseServiceHandle( schnd);

1138
    SetLastError(0xdeadbeef);
1139
    schnd = OpenSCManagerA( netwName, NULL, GENERIC_READ); 
1140
    ok( schnd != NULL, "OpenSCManagerA failed err = %d\n", GetLastError());
1141 1142 1143 1144
    CloseServiceHandle( schnd);

}

1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
static void test_reg_query_value(void)
{
    HKEY subkey;
    CHAR val[MAX_PATH];
    WCHAR valW[5];
    LONG size, ret;

    static const WCHAR expected[] = {'d','a','t','a',0};

    ret = RegCreateKeyA(hkey_main, "subkey", &subkey);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);

    ret = RegSetValueA(subkey, NULL, REG_SZ, "data", 4);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);

    /* try an invalid hkey */
    SetLastError(0xdeadbeef);
    size = MAX_PATH;
    ret = RegQueryValueA((HKEY)0xcafebabe, "subkey", val, &size);
1164 1165
    ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 98 returns BADKEY */
       "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
1166 1167 1168 1169 1170 1171
    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());

    /* try a NULL hkey */
    SetLastError(0xdeadbeef);
    size = MAX_PATH;
    ret = RegQueryValueA(NULL, "subkey", val, &size);
1172 1173
    ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 98 returns BADKEY */
       "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());

    /* try a NULL value */
    size = MAX_PATH;
    ret = RegQueryValueA(hkey_main, "subkey", NULL, &size);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ok(size == 5, "Expected 5, got %d\n", size);

    /* try a NULL size */
    SetLastError(0xdeadbeef);
    val[0] = '\0';
    ret = RegQueryValueA(hkey_main, "subkey", val, NULL);
    ok(ret == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", ret);
    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
    ok(lstrlenA(val) == 0, "Expected val to be untouched, got %s\n", val);

    /* try a NULL value and size */
    ret = RegQueryValueA(hkey_main, "subkey", NULL, NULL);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);

    /* try a size too small */
    SetLastError(0xdeadbeef);
    val[0] = '\0';
    size = 1;
    ret = RegQueryValueA(hkey_main, "subkey", val, &size);
    ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret);
    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
    ok(lstrlenA(val) == 0, "Expected val to be untouched, got %s\n", val);
    ok(size == 5, "Expected 5, got %d\n", size);

    /* successfully read the value using 'subkey' */
    size = MAX_PATH;
    ret = RegQueryValueA(hkey_main, "subkey", val, &size);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ok(!lstrcmpA(val, "data"), "Expected 'data', got '%s'\n", val);
    ok(size == 5, "Expected 5, got %d\n", size);

    /* successfully read the value using the subkey key */
    size = MAX_PATH;
    ret = RegQueryValueA(subkey, NULL, val, &size);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ok(!lstrcmpA(val, "data"), "Expected 'data', got '%s'\n", val);
    ok(size == 5, "Expected 5, got %d\n", size);

    /* unicode - try size too small */
    SetLastError(0xdeadbeef);
    valW[0] = '\0';
    size = 0;
    ret = RegQueryValueW(subkey, NULL, valW, &size);
1223 1224
    if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
    {
1225
        win_skip("RegQueryValueW is not implemented\n");
1226 1227
        goto cleanup;
    }
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249
    ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret);
    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
    ok(lstrlenW(valW) == 0, "Expected valW to be untouched\n");
    ok(size == sizeof(expected), "Got wrong size: %d\n", size);

    /* unicode - try size in WCHARS */
    SetLastError(0xdeadbeef);
    size = sizeof(valW) / sizeof(WCHAR);
    ret = RegQueryValueW(subkey, NULL, valW, &size);
    ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret);
    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
    ok(lstrlenW(valW) == 0, "Expected valW to be untouched\n");
    ok(size == sizeof(expected), "Got wrong size: %d\n", size);

    /* unicode - successfully read the value */
    size = sizeof(valW);
    ret = RegQueryValueW(subkey, NULL, valW, &size);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ok(!lstrcmpW(valW, expected), "Got wrong value\n");
    ok(size == sizeof(expected), "Got wrong size: %d\n", size);

    /* unicode - set the value without a NULL terminator */
1250
    ret = RegSetValueW(subkey, NULL, REG_SZ, expected, sizeof(expected)-sizeof(WCHAR));
1251 1252 1253 1254 1255 1256
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);

    /* unicode - read the unterminated value, value is terminated for us */
    memset(valW, 'a', sizeof(valW));
    size = sizeof(valW);
    ret = RegQueryValueW(subkey, NULL, valW, &size);
1257 1258 1259
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ok(!lstrcmpW(valW, expected), "Got wrong value\n");
    ok(size == sizeof(expected), "Got wrong size: %d\n", size);
1260

1261
cleanup:
1262
    RegDeleteKeyA(subkey, "");
1263
    RegCloseKey(subkey);
1264 1265
}

1266 1267 1268 1269 1270 1271 1272
static void test_reg_delete_tree(void)
{
    CHAR buffer[MAX_PATH];
    HKEY subkey, subkey2;
    LONG size, ret;

    if(!pRegDeleteTreeA) {
1273
        win_skip("Skipping RegDeleteTreeA tests, function not present\n");
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
        return;
    }

    ret = RegCreateKeyA(hkey_main, "subkey", &subkey);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ret = RegSetValueA(subkey, NULL, REG_SZ, "data", 4);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ret = RegSetValueA(subkey2, NULL, REG_SZ, "data2", 5);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ret = RegCloseKey(subkey2);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);

    ret = pRegDeleteTreeA(subkey, "subkey2");
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
        "subkey2 was not deleted\n");
    size = MAX_PATH;
    ok(!RegQueryValueA(subkey, NULL, buffer, &size),
        "Default value of subkey not longer present\n");

    ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ret = RegCloseKey(subkey2);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ret = pRegDeleteTreeA(hkey_main, "subkey\\subkey2");
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
        "subkey2 was not deleted\n");
    ok(!RegQueryValueA(subkey, NULL, buffer, &size),
        "Default value of subkey not longer present\n");

1307 1308 1309 1310 1311 1312 1313 1314 1315 1316
    ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ret = RegCloseKey(subkey2);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ret = RegCreateKeyA(subkey, "subkey3", &subkey2);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ret = RegCloseKey(subkey2);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ret = RegSetValueA(subkey, "value", REG_SZ, "data2", 5);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1317 1318 1319 1320
    ret = pRegDeleteTreeA(subkey, NULL);
    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
    ok(!RegOpenKeyA(hkey_main, "subkey", &subkey),
        "subkey was deleted\n");
1321 1322 1323 1324 1325
    ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
        "subkey2 was not deleted\n");
    ok(RegOpenKeyA(subkey, "subkey3", &subkey2),
        "subkey3 was not deleted\n");
    size = MAX_PATH;
1326 1327 1328 1329 1330
    ret = RegQueryValueA(subkey, NULL, buffer, &size);
    ok(ret == ERROR_SUCCESS,
        "Default value of subkey is not present\n");
    ok(!lstrlenA(buffer),
        "Expected length 0 got length %u(%s)\n", lstrlenA(buffer), buffer);
1331 1332 1333
    size = MAX_PATH;
    ok(RegQueryValueA(subkey, "value", buffer, &size),
        "Value is still present\n");
1334 1335 1336 1337 1338 1339

    ret = pRegDeleteTreeA(hkey_main, "not-here");
    ok(ret == ERROR_FILE_NOT_FOUND,
        "Expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
}

1340 1341
START_TEST(registry)
{
1342 1343 1344
    /* Load pointers for functions that are not available in all Windows versions */
    InitFunctionPtrs();

1345
    setup_main_key();
1346
    test_set_value();
1347
    create_test_entries();
1348
    test_enum_value();
1349
    test_query_value_ex();
1350
    test_get_value();
1351
    test_reg_open_key();
1352
    test_reg_create_key();
1353
    test_reg_close_key();
1354
    test_reg_delete_key();
1355
    test_reg_query_value();
1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367

    /* SaveKey/LoadKey require the SE_BACKUP_NAME privilege to be set */
    if (set_privileges(SE_BACKUP_NAME, TRUE) &&
        set_privileges(SE_RESTORE_NAME, TRUE))
    {
        test_reg_save_key();
        test_reg_load_key();
        test_reg_unload_key();

        set_privileges(SE_BACKUP_NAME, FALSE);
        set_privileges(SE_RESTORE_NAME, FALSE);
    }
1368

1369 1370
    test_reg_delete_tree();

1371 1372
    /* cleanup */
    delete_key( hkey_main );
1373 1374
    
    test_regconnectregistry();
1375
}