diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c index c32e419345..0ae4233a2f 100644 --- a/dlls/advapi32/tests/registry.c +++ b/dlls/advapi32/tests/registry.c @@ -61,6 +61,8 @@ static void setup_main_key(void) static void create_test_entries(void) { + DWORD qw[2] = { 0x12345678, 0x87654321 }; + SetEnvironmentVariableA("LONGSYSTEMVAR", "bar"); SetEnvironmentVariableA("FOO", "ImARatherLongButIndeedNeededString"); @@ -70,6 +72,12 @@ static void create_test_entries(void) "RegSetValueExA failed\n"); ok(!RegSetValueExA(hkey_main,"Test3",0,REG_EXPAND_SZ, sTestpath2, strlen(sTestpath2)+1), "RegSetValueExA failed\n"); + ok(!RegSetValueExA(hkey_main,"DWORD",0,REG_DWORD, (PVOID)qw, 4), + "RegSetValueExA failed\n"); + ok(!RegSetValueExA(hkey_main,"BIN32",0,REG_BINARY, (PVOID)qw, 4), + "RegSetValueExA failed\n"); + ok(!RegSetValueExA(hkey_main,"BIN64",0,REG_BINARY, (PVOID)qw, 8), + "RegSetValueExA failed\n"); } static void test_enum_value(void) @@ -255,6 +263,140 @@ static void test_query_value_ex(void) ok(type == REG_SZ, "type %ld is not REG_SZ\n", type); } +static void test_get_value(void) +{ + HMODULE hadvapi32; + DWORD (WINAPI *pRegGetValueA)(HKEY,LPCSTR,LPCSTR,DWORD,LPDWORD,PVOID,LPDWORD); + + DWORD ret; + DWORD size; + DWORD type; + DWORD dw, qw[2]; + CHAR buf[80]; + CHAR expanded[] = "bar\\subdir1"; + + /* This function was introduced with Windows 2003 SP1 */ + hadvapi32 = LoadLibraryA("advapi32.dll"); + if(!hadvapi32) + { + ok(0, "error=%ld\n", GetLastError()); + return; + } + pRegGetValueA = (PVOID)GetProcAddress(hadvapi32, "RegGetValueA"); + if(!pRegGetValueA) + return; + + /* 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); + ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret); + ok(size == 4, "size=%ld\n", size); + ok(type == REG_DWORD, "type=%ld\n", type); + ok(dw == 0x12345678, "dw=%ld\n", dw); + + /* Query by subkey-name */ + ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD, NULL, NULL, NULL); + ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret); + + /* 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); + ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%ld\n", ret); + /* Although the function failed all values are retrieved */ + ok(size == 4, "size=%ld\n", size); + ok(type == REG_DWORD, "type=%ld\n", type); + ok(dw == 0x12345678, "dw=%ld\n", dw); + + /* Test RRF_ZEROONFAILURE */ + type = dw = 0xdeadbeef; size = 4; + ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_SZ|RRF_ZEROONFAILURE, &type, &dw, &size); + ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%ld\n", ret); + /* Again all values are retrieved ... */ + ok(size == 4, "size=%ld\n", size); + ok(type == REG_DWORD, "type=%ld\n", type); + /* ... except the buffer, which is zeroed out */ + ok(dw == 0, "dw=%ld\n", dw); + + /* Query REG_DWORD using RRF_RT_DWORD (ok) */ + size = type = dw = 0xdeadbeef; + ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_DWORD, &type, &dw, &size); + ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret); + ok(size == 4, "size=%ld\n", size); + ok(type == REG_DWORD, "type=%ld\n", type); + ok(dw == 0x12345678, "dw=%ld\n", dw); + + /* 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); + ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret); + ok(size == 4, "size=%ld\n", size); + ok(type == REG_BINARY, "type=%ld\n", type); + ok(dw == 0x12345678, "dw=%ld\n", dw); + + /* 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); + ok(ret == ERROR_DATATYPE_MISMATCH, "ret=%ld\n", ret); + ok(size == 8, "size=%ld\n", size); + ok(type == REG_BINARY, "type=%ld\n", type); + ok(qw[0] == 0x12345678 && + qw[1] == 0x87654321, "qw={%ld,%ld}\n", qw[0], qw[1]); + + /* 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); + ok(ret == ERROR_MORE_DATA, "ret=%ld\n", ret); + ok(dw == 0xdeadbeef, "dw=%ld\n", dw); + ok(size == 8, "size=%ld\n", size); + + /* 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); + ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret); + ok(size == 8, "size=%ld\n", size); + ok(type == REG_BINARY, "type=%ld\n", type); + ok(qw[0] == 0x12345678 && + qw[1] == 0x87654321, "qw={%ld,%ld}\n", qw[0], qw[1]); + + /* This silly behaviour is not documented but since expanding REG_EXPAND_SZ + * values is one the two major features (with type restrictions being the + * other one) of this function and it doesn't work as one might expect we + * better test it... */ + + /* RRF_RT_REG_EXPAND_SZ without RRF_NOEXPAND is not allowed */ + ret = pRegGetValueA(hkey_main, NULL, "Test1", RRF_RT_REG_EXPAND_SZ, NULL, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "ret=%ld\n", ret); + /* Instead you have to use RRF_RT_REG_SZ to expand a REG_EXPAND_SZ */ + buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf); + ret = pRegGetValueA(hkey_main, NULL, "Test1", RRF_RT_REG_SZ, &type, buf, &size); + ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret); +#if 0 + /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded length + 1 here. */ + ok(size == strlen(expanded)+1, "strlen(expanded)=%ld size=%ld\n", strlen(expanded), size); +#endif + ok(type == REG_SZ, "type=%ld\n", type); + ok(!strcmp(expanded, buf), "expanded=\"%s\" buf=\"%s\"\n", expanded, buf); + + /* Query REG_SZ using RRF_RT_REG_SZ (should not expand it) */ + buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf); + ret = pRegGetValueA(hkey_main, NULL, "Test2", RRF_RT_REG_SZ, &type, buf, &size); + ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret); + ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%ld\n", strlen(sTestpath1), size); + ok(type == REG_SZ, "type=%ld\n", type); + ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf); + + /* With RRF_RT_REG_SZ however, RRF_NOEXPAND is not allowed */ + ret = pRegGetValueA(hkey_main, NULL, "Test1", RRF_RT_REG_SZ|RRF_NOEXPAND, NULL, NULL, NULL); + ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%ld\n", ret); + /* So we use RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND to get the unexpanded REG_EXPAND_SZ */ + buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf); + ret = pRegGetValueA(hkey_main, NULL, "Test1", RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND, &type, buf, &size); + ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret); + ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%ld\n", strlen(sTestpath1), size); + ok(type == REG_EXPAND_SZ, "type=%ld\n", type); + ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf); +} + static void test_reg_open_key(void) { DWORD ret = 0; @@ -450,6 +592,7 @@ START_TEST(registry) create_test_entries(); test_enum_value(); test_query_value_ex(); + test_get_value(); test_reg_open_key(); test_reg_create_key(); test_reg_close_key(); diff --git a/include/winreg.h b/include/winreg.h index 25d77dc8a9..2feae835a3 100644 --- a/include/winreg.h +++ b/include/winreg.h @@ -64,6 +64,21 @@ typedef ACCESS_MASK REGSAM; #define MAX_SHUTDOWN_TIMEOUT (10*365*24*60*60) +/* + * RegGetValue() restrictions + */ + +#define RRF_RT_REG_NONE (1 << 0) +#define RRF_RT_REG_SZ (1 << 1) +#define RRF_RT_REG_EXPAND_SZ (1 << 2) +#define RRF_RT_REG_BINARY (1 << 3) +#define RRF_RT_REG_DWORD (1 << 4) +#define RRF_RT_REG_MULTI_SZ (1 << 5) +#define RRF_RT_REG_QWORD (1 << 6) +#define RRF_RT_DWORD (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD) +#define RRF_RT_QWORD (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD) +#define RRF_NOEXPAND (1 << 28) +#define RRF_ZEROONFAILURE (1 << 29) BOOL WINAPI AbortSystemShutdownA(LPSTR); BOOL WINAPI AbortSystemShutdownW(LPWSTR);