#include "wine/test.h"
#include "windef.h"
#include "winbase.h"
-#include "winternl.h"
+#include "wine/winternl.h"
#include "winreg.h"
#include "winsvc.h"
#include "winerror.h"
static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(UNICODE_STRING*);
static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
+static LONG (WINAPI *pRegDeleteKeyValueA)(HKEY,LPCSTR,LPCSTR);
+static LONG (WINAPI *pRegSetKeyValueW)(HKEY,LPCWSTR,LPCWSTR,DWORD,const void*,DWORD);
+
+static BOOL limited_user;
/* Debugging functions from wine/libs/wine/debug.c */
ADVAPI32_GET_PROC(RegGetValueA);
ADVAPI32_GET_PROC(RegDeleteTreeA);
ADVAPI32_GET_PROC(RegDeleteKeyExA);
+ ADVAPI32_GET_PROC(RegDeleteKeyValueA);
+ ADVAPI32_GET_PROC(RegSetKeyValueW);
pIsWow64Process = (void *)GetProcAddress( hkernel32, "IsWow64Process" );
pRtlFormatCurrentUserKeyPath = (void *)GetProcAddress( hntdll, "RtlFormatCurrentUserKeyPath" );
assert (!RegCreateKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main ));
}
+static void check_user_privs(void)
+{
+ DWORD ret;
+ HKEY hkey = (HKEY)0xdeadbeef;
+
+ ret = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WRITE, &hkey);
+ ok(ret == ERROR_SUCCESS || ret == ERROR_ACCESS_DENIED, "expected success or access denied, got %i\n", ret);
+ if (ret == ERROR_SUCCESS)
+ {
+ ok(hkey != NULL, "RegOpenKeyExA succeeded but returned NULL hkey\n");
+ RegCloseKey(hkey);
+ }
+ else
+ {
+ ok(hkey == NULL, "RegOpenKeyExA failed but returned hkey %p\n", hkey);
+ limited_user = TRUE;
+ trace("running as limited user\n");
+ }
+}
+
#define lok ok_(__FILE__, line)
#define test_hkey_main_Value_A(name, string, full_byte_len) _test_hkey_main_Value_A(__LINE__, name, string, full_byte_len)
static void _test_hkey_main_Value_A(int line, LPCSTR name, LPCSTR string,
ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %d, GLE=%d\n", ret, GetLastError());
ret = RegSetValueExW(hkey_main, name2W, 0, REG_DWORD, (const BYTE *)1, 1);
ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %d, GLE=%d\n", ret, GetLastError());
+
+ if (pRegGetValueA) /* avoid a crash on Windows 2000 */
+ {
+ ret = RegSetValueExW(hkey_main, NULL, 0, REG_SZ, NULL, 4);
+ ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %d, GLE=%d\n", ret, GetLastError());
+
+ ret = RegSetValueExW(hkey_main, NULL, 0, REG_SZ, NULL, 0);
+ ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+
+ ret = RegSetValueExW(hkey_main, NULL, 0, REG_DWORD, NULL, 4);
+ ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %d, GLE=%d\n", ret, GetLastError());
+
+ ret = RegSetValueExW(hkey_main, NULL, 0, REG_DWORD, NULL, 0);
+ ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+ }
+
+ /* RegSetKeyValue */
+ if (!pRegSetKeyValueW)
+ win_skip("RegSetKeyValue() is not supported.\n");
+ else
+ {
+ static const WCHAR subkeyW[] = {'s','u','b','k','e','y',0};
+ DWORD len, type;
+ HKEY subkey;
+
+ ret = pRegSetKeyValueW(hkey_main, NULL, name1W, REG_SZ, (const BYTE*)string2W, sizeof(string2W));
+ ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+ test_hkey_main_Value_A(name1A, string2A, sizeof(string2A));
+ test_hkey_main_Value_W(name1W, string2W, sizeof(string2W));
+
+ ret = pRegSetKeyValueW(hkey_main, subkeyW, name1W, REG_SZ, string1W, sizeof(string1W));
+ ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+
+ ret = RegOpenKeyExW(hkey_main, subkeyW, 0, KEY_QUERY_VALUE, &subkey);
+ ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+ type = len = 0;
+ ret = RegQueryValueExW(subkey, name1W, 0, &type, NULL, &len);
+ ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+ ok(len == sizeof(string1W), "got %d\n", len);
+ ok(type == REG_SZ, "got type %d\n", type);
+
+ ret = pRegSetKeyValueW(hkey_main, subkeyW, name1W, REG_SZ, NULL, 0);
+ ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+
+ ret = pRegSetKeyValueW(hkey_main, subkeyW, name1W, REG_SZ, NULL, 4);
+ ok(ret == ERROR_NOACCESS, "got %d\n", ret);
+
+ ret = pRegSetKeyValueW(hkey_main, subkeyW, name1W, REG_DWORD, NULL, 4);
+ ok(ret == ERROR_NOACCESS, "got %d\n", ret);
+
+ RegCloseKey(subkey);
+ }
}
static void create_test_entries(void)
res = RegSetValueExA( test_key, "Test", 0, REG_BINARY, NULL, 0 );
ok( ERROR_SUCCESS == res || ERROR_INVALID_PARAMETER == res, "RegSetValueExA returned %d\n", res );
+ /* test reading the value and data without setting them */
+ val_count = 20;
+ data_count = 20;
+ type = 1234;
+ strcpy( value, "xxxxxxxxxx" );
+ strcpy( data, "xxxxxxxxxx" );
+ res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
+ 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 == 0, "data_count set to %d instead of 0\n", data_count );
+ ok( type == REG_BINARY, "type %d is not REG_BINARY\n", type );
+ ok( !strcmp( value, "Test" ), "value is '%s' instead of Test\n", value );
+ ok( !strcmp( data, "xxxxxxxxxx" ), "data is '%s' instead of xxxxxxxxxx\n", data );
+
+ val_count = 20;
+ data_count = 20;
+ type = 1234;
+ memcpy( valueW, xxxW, sizeof(xxxW) );
+ memcpy( dataW, xxxW, sizeof(xxxW) );
+ res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
+ 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 == 0, "data_count set to %d instead of 0\n", data_count );
+ ok( type == REG_BINARY, "type %d is not REG_BINARY\n", type );
+ ok( !memcmp( valueW, testW, sizeof(testW) ), "value is not 'Test'\n" );
+ ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data is not 'xxxxxxxxxx'\n" );
+
res = RegSetValueExA( test_key, "Test", 0, REG_SZ, (const BYTE *)"foobar", 7 );
ok( res == 0, "RegSetValueExA failed error %d\n", res );
ok( !strcmp( value, "Test" ), "value is '%s' instead of Test\n", value );
ok( !strcmp( data, "foobar" ), "data is '%s' instead of foobar\n", data );
+ if (pRegGetValueA) /* avoid a crash on Windows 2000 */
+ {
+ /* no value and no val_count parameter */
+ data_count = 20;
+ type = 1234;
+ strcpy( data, "xxxxxxxxxx" );
+ res = RegEnumValueA( test_key, 0, NULL, NULL, NULL, &type, (BYTE*)data, &data_count );
+ ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
+
+ /* no value parameter */
+ val_count = 20;
+ data_count = 20;
+ type = 1234;
+ strcpy( data, "xxxxxxxxxx" );
+ res = RegEnumValueA( test_key, 0, NULL, &val_count, NULL, &type, (BYTE*)data, &data_count );
+ ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
+
+ /* no val_count parameter */
+ data_count = 20;
+ type = 1234;
+ strcpy( value, "xxxxxxxxxx" );
+ strcpy( data, "xxxxxxxxxx" );
+ res = RegEnumValueA( test_key, 0, value, NULL, NULL, &type, (BYTE*)data, &data_count );
+ ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
+ }
+
/* Unicode tests */
SetLastError(0xdeadbeef);
ok( !memcmp( valueW, testW, sizeof(testW) ), "value is not 'Test'\n" );
ok( !memcmp( dataW, foobarW, sizeof(foobarW) ), "data is not 'foobar'\n" );
+ if (pRegGetValueA) /* avoid a crash on Windows 2000 */
+ {
+ /* no valueW and no val_count parameter */
+ data_count = 20;
+ type = 1234;
+ memcpy( dataW, xxxW, sizeof(xxxW) );
+ res = RegEnumValueW( test_key, 0, NULL, NULL, NULL, &type, (BYTE*)dataW, &data_count );
+ ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
+
+ /* no valueW parameter */
+ val_count = 20;
+ data_count = 20;
+ type = 1234;
+ memcpy( dataW, xxxW, sizeof(xxxW) );
+ res = RegEnumValueW( test_key, 0, NULL, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
+ ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
+
+ /* no val_count parameter */
+ data_count = 20;
+ type = 1234;
+ memcpy( valueW, xxxW, sizeof(xxxW) );
+ memcpy( dataW, xxxW, sizeof(xxxW) );
+ res = RegEnumValueW( test_key, 0, valueW, NULL, NULL, &type, (BYTE*)dataW, &data_count );
+ ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
+ }
+
cleanup:
RegDeleteKeyA(test_key, "");
RegCloseKey(test_key);
ok(hkResult != NULL, "hkResult != NULL\n");
RegCloseKey(hkResult);
+ /* trailing slashes */
+ ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test\\\\", &hkResult);
+ ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
+ RegCloseKey(hkResult);
+
/* open nonexistent key
* check that hkResult is set to NULL
*/
ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 95 returns BADKEY */
"expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
ok(hkResult == hkPreserve, "expected hkResult == hkPreserve\n");
- RegCloseKey(hkResult);
/* send in NULL hkResult */
ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", NULL);
"expected ERROR_SUCCESS, ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret);
RegCloseKey(hkResult);
+ /* NULL or empty subkey of special root */
+ hkResult = NULL;
+ ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, NULL, 0, KEY_QUERY_VALUE, &hkResult);
+ ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
+ ok(hkResult == HKEY_CLASSES_ROOT, "expected hkResult == HKEY_CLASSES_ROOT\n");
+
+ hkResult = NULL;
+ ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "", 0, KEY_QUERY_VALUE, &hkResult);
+ ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
+ ok(hkResult == HKEY_CLASSES_ROOT, "expected hkResult == HKEY_CLASSES_ROOT\n");
+
+ hkResult = NULL;
+ ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "\\", 0, KEY_QUERY_VALUE, &hkResult);
+ ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
+ ok(hkResult != HKEY_CLASSES_ROOT, "expected hkResult to be a new key\n");
+ ok(!RegCloseKey(hkResult), "got invalid hkey\n");
+
+ /* empty subkey of existing handle */
+ hkResult = hkPreserve;
+ ret = RegOpenKeyExA(hkPreserve, "", 0, KEY_QUERY_VALUE, &hkResult);
+ ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
+ ok(hkResult != hkPreserve, "expected hkResult != hkPreserve\n");
+ ok(!RegCloseKey(hkResult), "got invalid hkey\n");
+
+ /* NULL subkey of existing handle */
+ hkResult = hkPreserve;
+ ret = RegOpenKeyExA(hkPreserve, NULL, 0, KEY_QUERY_VALUE, &hkResult);
+ ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
+ ok(hkResult != hkPreserve, "expected hkResult != hkPreserve\n");
+ ok(!RegCloseKey(hkResult), "got invalid hkey\n");
+
+ /* empty subkey of NULL */
+ hkResult = hkPreserve;
+ ret = RegOpenKeyExA(NULL, "", 0, KEY_QUERY_VALUE, &hkResult);
+ ok(ret == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", ret);
+ ok(hkResult == hkPreserve, "expected hkResult == hkPreserve\n");
+
+ RegCloseKey(hkPreserve);
+
/* WOW64 flags */
hkResult = NULL;
ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WOW64_32KEY, &hkResult);
ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &hkRoot32, NULL);
- ok(ret == ERROR_SUCCESS && hkRoot32 != NULL,
- "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
+ if (limited_user)
+ ok(ret == ERROR_ACCESS_DENIED && hkRoot32 == NULL,
+ "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
+ else
+ ok(ret == ERROR_SUCCESS && hkRoot32 != NULL,
+ "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &hkRoot64, NULL);
- ok(ret == ERROR_SUCCESS && hkRoot64 != NULL,
- "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
+ if (limited_user)
+ ok(ret == ERROR_ACCESS_DENIED && hkRoot64 == NULL,
+ "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
+ else
+ ok(ret == ERROR_SUCCESS && hkRoot64 != NULL,
+ "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
bRet = AllocateAndInitializeSid(&sid_authority, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0, &world_sid);
ok(bRet == TRUE,
"Expected SetSecurityDescriptorDacl to return TRUE, got %d, last error %u\n", bRet, GetLastError());
- /* The "sanctioned" methods of setting a registry ACL aren't implemented in Wine. */
- bRet = SetKernelObjectSecurity(hkRoot64, DACL_SECURITY_INFORMATION, sd);
- ok(bRet == TRUE,
- "Expected SetKernelObjectSecurity to return TRUE, got %d, last error %u\n", bRet, GetLastError());
+ if (limited_user)
+ {
+ skip("not enough privileges to modify HKLM\n");
+ }
+ else
+ {
+ LONG error;
- bRet = SetKernelObjectSecurity(hkRoot32, DACL_SECURITY_INFORMATION, sd);
- ok(bRet == TRUE,
- "Expected SetKernelObjectSecurity to return TRUE, got %d, last error %u\n", bRet, GetLastError());
+ error = RegSetKeySecurity(hkRoot64, DACL_SECURITY_INFORMATION, sd);
+ ok(error == ERROR_SUCCESS,
+ "Expected RegSetKeySecurity to return success, got error %u\n", error);
- hkResult = NULL;
- ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_WOW64_64KEY | KEY_READ, &hkResult);
- ok(ret == ERROR_SUCCESS && hkResult != NULL,
- "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
- RegCloseKey(hkResult);
+ error = RegSetKeySecurity(hkRoot32, DACL_SECURITY_INFORMATION, sd);
+ ok(error == ERROR_SUCCESS,
+ "Expected RegSetKeySecurity to return success, got error %u\n", error);
- hkResult = NULL;
- ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_WOW64_32KEY | KEY_READ, &hkResult);
- ok(ret == ERROR_SUCCESS && hkResult != NULL,
- "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
- RegCloseKey(hkResult);
+ hkResult = NULL;
+ ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_WOW64_64KEY | KEY_READ, &hkResult);
+ ok(ret == ERROR_SUCCESS && hkResult != NULL,
+ "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
+ RegCloseKey(hkResult);
+
+ hkResult = NULL;
+ ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_WOW64_32KEY | KEY_READ, &hkResult);
+ ok(ret == ERROR_SUCCESS && hkResult != NULL,
+ "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
+ RegCloseKey(hkResult);
+ }
HeapFree(GetProcessHeap(), 0, sd);
LocalFree(key_acl);
ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
/* clean up */
- RegDeleteKey(hkey2, "");
- RegDeleteKey(hkey1, "");
+ RegDeleteKeyA(hkey2, "");
+ RegDeleteKeyA(hkey1, "");
RegCloseKey(hkey2);
RegCloseKey(hkey1);
ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
/* clean up */
- RegDeleteKey(hkey2, "");
- RegDeleteKey(hkey1, "");
+ RegDeleteKeyA(hkey2, "");
+ RegDeleteKeyA(hkey1, "");
RegCloseKey(hkey2);
RegCloseKey(hkey1);
ok(ret == ERROR_BAD_PATHNAME, "expected ERROR_BAD_PATHNAME, got %d\n", ret);
else {
ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
- RegDeleteKey(hkey1, NULL);
+ RegDeleteKeyA(hkey1, "");
RegCloseKey(hkey1);
}
+ /* trailing backslash characters */
+ ret = RegCreateKeyExA(hkey_main, "Subkey4\\\\", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
+ ok(ret == ERROR_SUCCESS, "RegCreateKeyExA failed with error %d\n", ret);
+ RegDeleteKeyA(hkey1, "");
+ RegCloseKey(hkey1);
+
/* WOW64 flags - open an existing key */
hkey1 = NULL;
ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0, KEY_READ|KEY_WOW64_32KEY, NULL, &hkey1, NULL);
ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &hkRoot32, NULL);
- ok(ret == ERROR_SUCCESS && hkRoot32 != NULL,
- "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%d)\n", ret);
+ if (limited_user)
+ ok(ret == ERROR_ACCESS_DENIED && hkRoot32 == NULL,
+ "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%d)\n", ret);
+ else
+ ok(ret == ERROR_SUCCESS && hkRoot32 != NULL,
+ "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%d)\n", ret);
ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &hkRoot64, NULL);
- ok(ret == ERROR_SUCCESS && hkRoot64 != NULL,
- "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%d)\n", ret);
+ if (limited_user)
+ ok(ret == ERROR_ACCESS_DENIED && hkRoot64 == NULL,
+ "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%d)\n", ret);
+ else
+ ok(ret == ERROR_SUCCESS && hkRoot64 != NULL,
+ "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%d)\n", ret);
bRet = AllocateAndInitializeSid(&sid_authority, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0, &world_sid);
access.Trustee.ptstrName = (char *)world_sid;
dwRet = SetEntriesInAclA(1, &access, NULL, &key_acl);
- ok(ret == ERROR_SUCCESS,
+ ok(dwRet == ERROR_SUCCESS,
"Expected SetEntriesInAclA to return ERROR_SUCCESS, got %u, last error %u\n", dwRet, GetLastError());
sd = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
ok(bRet == TRUE,
"Expected SetSecurityDescriptorDacl to return TRUE, got %d, last error %u\n", bRet, GetLastError());
- /* The "sanctioned" methods of setting a registry ACL aren't implemented in Wine. */
- bRet = SetKernelObjectSecurity(hkRoot64, DACL_SECURITY_INFORMATION, sd);
- ok(bRet == TRUE,
- "Expected SetKernelObjectSecurity to return TRUE, got %d, last error %u\n", bRet, GetLastError());
-
- bRet = SetKernelObjectSecurity(hkRoot32, DACL_SECURITY_INFORMATION, sd);
- ok(bRet == TRUE,
- "Expected SetKernelObjectSecurity to return TRUE, got %d, last error %u\n", bRet, GetLastError());
-
- hkey1 = NULL;
- ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
- KEY_WOW64_64KEY | KEY_READ, NULL, &hkey1, NULL);
- ok(ret == ERROR_SUCCESS && hkey1 != NULL,
- "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
- RegCloseKey(hkey1);
+ if (limited_user)
+ {
+ skip("not enough privileges to modify HKLM\n");
+ }
+ else
+ {
+ ret = RegSetKeySecurity(hkRoot64, DACL_SECURITY_INFORMATION, sd);
+ ok(ret == ERROR_SUCCESS,
+ "Expected RegSetKeySecurity to return success, got error %u\n", ret);
+
+ ret = RegSetKeySecurity(hkRoot32, DACL_SECURITY_INFORMATION, sd);
+ ok(ret == ERROR_SUCCESS,
+ "Expected RegSetKeySecurity to return success, got error %u\n", ret);
+
+ hkey1 = NULL;
+ ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
+ KEY_WOW64_64KEY | KEY_READ, NULL, &hkey1, NULL);
+ ok(ret == ERROR_SUCCESS && hkey1 != NULL,
+ "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
+ RegCloseKey(hkey1);
- hkey1 = NULL;
- ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
- KEY_WOW64_32KEY | KEY_READ, NULL, &hkey1, NULL);
- ok(ret == ERROR_SUCCESS && hkey1 != NULL,
- "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
- RegCloseKey(hkey1);
+ hkey1 = NULL;
+ ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
+ KEY_WOW64_32KEY | KEY_READ, NULL, &hkey1, NULL);
+ ok(ret == ERROR_SUCCESS && hkey1 != NULL,
+ "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
+ RegCloseKey(hkey1);
+ }
HeapFree(GetProcessHeap(), 0, sd);
LocalFree(key_acl);
static void test_reg_delete_key(void)
{
DWORD ret;
+ HKEY key;
- ret = RegDeleteKey(hkey_main, NULL);
+ ret = RegDeleteKeyA(hkey_main, NULL);
/* 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.
ret == ERROR_ACCESS_DENIED ||
ret == ERROR_BADKEY, /* Win95 */
"ret=%d\n", ret);
-}
-
-static void test_reg_save_key(void)
-{
- DWORD ret;
-
- ret = RegSaveKey(hkey_main, "saved_key", NULL);
- ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
-}
-
-static void test_reg_load_key(void)
-{
- DWORD ret;
- HKEY hkHandle;
- ret = RegLoadKey(HKEY_LOCAL_MACHINE, "Test", "saved_key");
- ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
-
- ret = RegOpenKey(HKEY_LOCAL_MACHINE, "Test", &hkHandle);
- ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
-
- RegCloseKey(hkHandle);
-}
-
-static void test_reg_unload_key(void)
-{
- DWORD ret;
-
- ret = RegUnLoadKey(HKEY_LOCAL_MACHINE, "Test");
- ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
-
- DeleteFile("saved_key");
- DeleteFile("saved_key.LOG");
+ ret = RegCreateKeyA(hkey_main, "deleteme", &key);
+ ok(ret == ERROR_SUCCESS, "Could not create key, got %d\n", ret);
+ ret = RegDeleteKeyA(key, "");
+ ok(ret == ERROR_SUCCESS, "RegDeleteKeyA failed, got %d\n", ret);
+ RegCloseKey(key);
+ ret = RegOpenKeyA(hkey_main, "deleteme", &key);
+ ok(ret == ERROR_FILE_NOT_FOUND, "Key was not deleted, got %d\n", ret);
+ RegCloseKey(key);
}
static BOOL set_privileges(LPCSTR privilege, BOOL set)
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
return FALSE;
- if(!LookupPrivilegeValue(NULL, privilege, &luid))
+ if(!LookupPrivilegeValueA(NULL, privilege, &luid))
{
CloseHandle(hToken);
return FALSE;
return TRUE;
}
+static void test_reg_save_key(void)
+{
+ DWORD ret;
+
+ if (!set_privileges(SE_BACKUP_NAME, TRUE) ||
+ !set_privileges(SE_RESTORE_NAME, FALSE))
+ {
+ win_skip("Failed to set SE_BACKUP_NAME privileges, skipping tests\n");
+ return;
+ }
+
+ ret = RegSaveKeyA(hkey_main, "saved_key", NULL);
+ ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
+
+ set_privileges(SE_BACKUP_NAME, FALSE);
+}
+
+static void test_reg_load_key(void)
+{
+ DWORD ret;
+ HKEY hkHandle;
+
+ if (!set_privileges(SE_RESTORE_NAME, TRUE) ||
+ !set_privileges(SE_BACKUP_NAME, FALSE))
+ {
+ win_skip("Failed to set SE_RESTORE_NAME privileges, skipping tests\n");
+ return;
+ }
+
+ ret = RegLoadKeyA(HKEY_LOCAL_MACHINE, "Test", "saved_key");
+ ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
+
+ set_privileges(SE_RESTORE_NAME, FALSE);
+
+ ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, "Test", &hkHandle);
+ ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
+
+ RegCloseKey(hkHandle);
+}
+
+static void test_reg_unload_key(void)
+{
+ DWORD ret;
+
+ if (!set_privileges(SE_RESTORE_NAME, TRUE) ||
+ !set_privileges(SE_BACKUP_NAME, FALSE))
+ {
+ win_skip("Failed to set SE_RESTORE_NAME privileges, skipping tests\n");
+ return;
+ }
+
+ ret = RegUnLoadKeyA(HKEY_LOCAL_MACHINE, "Test");
+ ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
+
+ set_privileges(SE_RESTORE_NAME, FALSE);
+
+ DeleteFileA("saved_key");
+ DeleteFileA("saved_key.LOG");
+}
+
/* tests that show that RegConnectRegistry and
OpenSCManager accept computer names without the
\\ prefix (what MSDN says). */
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);
+ ok(!val[0], "Expected val to be untouched, got %s\n", val);
/* try a NULL value and size */
ret = RegQueryValueA(hkey_main, "subkey", NULL, NULL);
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(!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' */
}
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(!valW[0], "Expected valW to be untouched\n");
ok(size == sizeof(expected), "Got wrong size: %d\n", size);
/* unicode - try size in WCHARS */
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(!valW[0], "Expected valW to be untouched\n");
ok(size == sizeof(expected), "Got wrong size: %d\n", size);
/* unicode - successfully read the value */
RegCloseKey(subkey);
}
+static void test_reg_query_info(void)
+{
+ HKEY subkey;
+ HKEY subsubkey;
+ LONG ret;
+ char classbuffer[32];
+ WCHAR classbufferW[32];
+ char expectbuffer[32];
+ WCHAR expectbufferW[32];
+ char subkey_class[] = "subkey class";
+ WCHAR subkey_classW[] = {'s','u','b','k','e','y',' ','c','l','a','s','s',0};
+ char subsubkey_class[] = "subsubkey class";
+ DWORD classlen;
+ DWORD subkeys, maxsubkeylen, maxclasslen;
+ DWORD values, maxvaluenamelen, maxvaluelen;
+ DWORD sdlen;
+ FILETIME lastwrite;
+
+ ret = RegCreateKeyExA(hkey_main, "subkey", 0, subkey_class, 0, KEY_ALL_ACCESS, NULL, &subkey, NULL);
+ ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+
+ /* all parameters NULL */
+ ret = RegQueryInfoKeyA(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_INVALID_HANDLE, "ret = %d\n", ret);
+
+ ret = RegQueryInfoKeyW(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_INVALID_HANDLE, "ret = %d\n", ret);
+
+ /* not requesting any information */
+ ret = RegQueryInfoKeyA(subkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
+
+ ret = RegQueryInfoKeyW(subkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
+
+ /* class without length is invalid */
+ memset(classbuffer, 0x55, sizeof(classbuffer));
+ ret = RegQueryInfoKeyA(subkey, classbuffer, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "ret = %d\n", ret);
+ ok(classbuffer[0] == 0x55, "classbuffer[0] = 0x%x\n", classbuffer[0]);
+
+ memset(classbufferW, 0x55, sizeof(classbufferW));
+ ret = RegQueryInfoKeyW(subkey, classbufferW, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "ret = %d\n", ret);
+ ok(classbufferW[0] == 0x5555, "classbufferW[0] = 0x%x\n", classbufferW[0]);
+
+ /* empty key */
+ sdlen = 0;
+ ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
+ ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
+ ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
+ ok(subkeys == 0, "subkeys = %u\n", subkeys);
+ ok(maxsubkeylen == 0, "maxsubkeylen = %u\n", maxsubkeylen);
+ ok(maxclasslen == 0, "maxclasslen = %u\n", maxclasslen);
+ ok(values == 0, "values = %u\n", values);
+ ok(maxvaluenamelen == 0, "maxvaluenamelen = %u\n", maxvaluenamelen);
+ ok(maxvaluelen == 0, "maxvaluelen = %u\n", maxvaluelen);
+ todo_wine ok(sdlen != 0, "sdlen = %u\n", sdlen);
+ ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
+ ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
+
+ sdlen = 0;
+ ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
+ ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
+ ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
+ ok(subkeys == 0, "subkeys = %u\n", subkeys);
+ ok(maxsubkeylen == 0, "maxsubkeylen = %u\n", maxsubkeylen);
+ ok(maxclasslen == 0, "maxclasslen = %u\n", maxclasslen);
+ ok(values == 0, "values = %u\n", values);
+ ok(maxvaluenamelen == 0, "maxvaluenamelen = %u\n", maxvaluenamelen);
+ ok(maxvaluelen == 0, "maxvaluelen = %u\n", maxvaluelen);
+ todo_wine ok(sdlen != 0, "sdlen = %u\n", sdlen);
+ ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
+ ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
+
+ ret = RegCreateKeyExA(subkey, "subsubkey", 0, subsubkey_class, 0, KEY_ALL_ACCESS, NULL, &subsubkey, NULL);
+ ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+
+ ret = RegSetValueExA(subkey, NULL, 0, REG_SZ, (const BYTE*)"data", 5);
+ ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+
+ /* with subkey & default value */
+ sdlen = 0;
+ ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
+ ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
+ ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
+ ok(subkeys == 1, "subkeys = %u\n", subkeys);
+ ok(maxsubkeylen == strlen("subsubkey"), "maxsubkeylen = %u\n", maxsubkeylen);
+ ok(maxclasslen == strlen(subsubkey_class), "maxclasslen = %u\n", maxclasslen);
+ ok(values == 1, "values = %u\n", values);
+ ok(maxvaluenamelen == 0, "maxvaluenamelen = %u\n", maxvaluenamelen);
+ ok(maxvaluelen == sizeof("data") * sizeof(WCHAR), "maxvaluelen = %u\n", maxvaluelen);
+ todo_wine ok(sdlen != 0, "sdlen = %u\n", sdlen);
+ ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
+ ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
+
+ sdlen = 0;
+ ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
+ ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
+ ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
+ ok(subkeys == 1, "subkeys = %u\n", subkeys);
+ ok(maxsubkeylen == strlen("subsubkey"), "maxsubkeylen = %u\n", maxsubkeylen);
+ ok(maxclasslen == strlen(subsubkey_class), "maxclasslen = %u\n", maxclasslen);
+ ok(values == 1, "values = %u\n", values);
+ ok(maxvaluenamelen == 0, "maxvaluenamelen = %u\n", maxvaluenamelen);
+ ok(maxvaluelen == sizeof("data") * sizeof(WCHAR), "maxvaluelen = %u\n", maxvaluelen);
+ todo_wine ok(sdlen != 0, "sdlen = %u\n", sdlen);
+ ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
+ ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
+
+ ret = RegSetValueExA(subkey, "value one", 0, REG_SZ, (const BYTE*)"first value data", 17);
+ ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+
+ ret = RegSetValueExA(subkey, "value 2", 0, REG_SZ, (const BYTE*)"second value data", 18);
+ ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+
+ /* with named value */
+ ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
+ ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
+ ok(values == 3, "values = %u\n", values);
+ ok(maxvaluenamelen == strlen("value one"), "maxvaluenamelen = %u\n", maxvaluenamelen);
+ ok(maxvaluelen == sizeof("second value data") * sizeof(WCHAR), "maxvaluelen = %u\n", maxvaluelen);
+
+ ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
+ ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
+ ok(values == 3, "values = %u\n", values);
+ ok(maxvaluenamelen == strlen("value one"), "maxvaluenamelen = %u\n", maxvaluenamelen);
+ ok(maxvaluelen == sizeof("second value data") * sizeof(WCHAR), "maxvaluelen = %u\n", maxvaluelen);
+
+ /* class name with zero size buffer */
+ memset(classbuffer, 0x55, sizeof(classbuffer));
+ classlen = 0;
+ ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
+ ok(classlen == strlen(subkey_class) /* win2k */ ||
+ classlen == 0, "classlen = %u\n", classlen);
+ memset(expectbuffer, 0x55, sizeof(expectbuffer));
+ ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)), "classbuffer was modified\n");
+
+ memset(classbufferW, 0x55, sizeof(classbufferW));
+ classlen = 0;
+ ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
+ ok(classlen == strlen(subkey_class) /* win2k */ ||
+ classlen == 0, "classlen = %u\n", classlen);
+ memset(expectbufferW, 0x55, sizeof(expectbufferW));
+ ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)), "classbufferW was modified\n");
+
+ /* class name with one char buffer */
+ memset(classbuffer, 0x55, sizeof(classbuffer));
+ classlen = 1;
+ ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_MORE_DATA, "ret = %d\n", ret);
+ ok(classlen == 0, "classlen = %u\n", classlen);
+ memset(expectbuffer, 0x55, sizeof(expectbuffer));
+ expectbuffer[0] = 0;
+ ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)), "classbuffer was modified\n");
+
+ memset(classbufferW, 0x55, sizeof(classbufferW));
+ classlen = 1;
+ ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_INSUFFICIENT_BUFFER, "ret = %d\n", ret);
+ ok(classlen == 0 /* win8 */ ||
+ classlen == strlen(subkey_class), "classlen = %u\n", classlen);
+ memset(expectbufferW, 0x55, sizeof(expectbufferW));
+ ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)), "classbufferW was modified\n");
+
+ /* class name with buffer one char too small */
+ memset(classbuffer, 0x55, sizeof(classbuffer));
+ classlen = sizeof(subkey_class) - 1;
+ ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_MORE_DATA, "ret = %d\n", ret);
+ ok(classlen == sizeof(subkey_class) - 2, "classlen = %u\n", classlen);
+ memset(expectbuffer, 0x55, sizeof(expectbuffer));
+ strcpy(expectbuffer, subkey_class);
+ expectbuffer[sizeof(subkey_class) - 2] = 0;
+ expectbuffer[sizeof(subkey_class) - 1] = 0x55;
+ ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)),
+ "classbuffer = %.*s, expected %s\n",
+ (int)sizeof(classbuffer), classbuffer, expectbuffer);
+
+ memset(classbufferW, 0x55, sizeof(classbufferW));
+ classlen = sizeof(subkey_class) - 1;
+ ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_INSUFFICIENT_BUFFER, "ret = %d\n", ret);
+ ok(classlen == sizeof(subkey_class) - 2 /* win8 */ ||
+ classlen == strlen(subkey_class), "classlen = %u\n", classlen);
+ memset(expectbufferW, 0x55, sizeof(expectbufferW));
+ ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)), "classbufferW was modified\n");
+
+ /* class name with large enough buffer */
+ memset(classbuffer, 0x55, sizeof(classbuffer));
+ classlen = sizeof(subkey_class);
+ ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
+ ok(classlen == sizeof(subkey_class) - 1, "classlen = %u\n", classlen);
+ memset(expectbuffer, 0x55, sizeof(expectbuffer));
+ strcpy(expectbuffer, subkey_class);
+ ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)),
+ "classbuffer = \"%.*s\", expected %s\n",
+ (int)sizeof(classbuffer), classbuffer, expectbuffer);
+
+ memset(classbufferW, 0x55, sizeof(classbufferW));
+ classlen = sizeof(subkey_class);
+ ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
+ ok(classlen == sizeof(subkey_class) - 1, "classlen = %u\n", classlen);
+ memset(expectbufferW, 0x55, sizeof(expectbufferW));
+ lstrcpyW(expectbufferW, subkey_classW);
+ ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)),
+ "classbufferW = %s, expected %s\n",
+ wine_dbgstr_wn(classbufferW, sizeof(classbufferW) / sizeof(WCHAR)), wine_dbgstr_w(expectbufferW));
+
+ RegDeleteKeyA(subsubkey, "");
+ RegCloseKey(subsubkey);
+ RegDeleteKeyA(subkey, "");
+ RegCloseKey(subkey);
+}
+
static void test_string_termination(void)
{
HKEY subkey;
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);
+ ok(!buffer[0], "Expected length 0 got length %u(%s)\n", lstrlenA(buffer), buffer);
size = MAX_PATH;
ok(RegQueryValueA(subkey, "value", buffer, &size),
"Value is still present\n");
{
HKEY hKey;
DWORD dw = 0;
- static char keyname[] = "test_rw_order";
+ static const char keyname[] = "test_rw_order";
char value_buf[2];
DWORD values, value_len, value_name_max_len;
LSTATUS ret;
ok(!RegEnumValueA(hKey, 3, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n");
todo_wine ok(strcmp(value_buf, "B") == 0, "Expected name \"B\", got %s\n", value_buf);
- ok(!RegDeleteKey(HKEY_CURRENT_USER, keyname), "Failed to delete key\n");
+ ok(!RegDeleteKeyA(HKEY_CURRENT_USER, keyname), "Failed to delete key\n");
}
static void test_symlinks(void)
KEY_ALL_ACCESS, NULL, &key, NULL );
ok( err == ERROR_ALREADY_EXISTS, "RegCreateKeyEx wrong error %u\n", err );
- err = RegDeleteKey( hkey_main, "target" );
+ err = RegDeleteKeyA( hkey_main, "target" );
ok( err == ERROR_SUCCESS, "RegDeleteKey failed error %u\n", err );
- err = RegDeleteKey( hkey_main, "link" );
+ err = RegDeleteKeyA( hkey_main, "link" );
ok( err == ERROR_FILE_NOT_FOUND, "RegDeleteKey wrong error %u\n", err );
status = pNtDeleteKey( link );
static void test_redirection(void)
{
DWORD err, type, dw, len;
- HKEY key, root32, root64, key32, key64;
+ HKEY key, root32, root64, key32, key64, native, op_key;
BOOL is_vista = FALSE;
+ REGSAM opposite = (sizeof(void*) == 8 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY);
if (ptr_size != 64)
{
check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
RegCloseKey( key );
}
+ else
+ {
+ err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
+ KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
+ ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
+ check_key_value( key, "Wine\\Winetest", 0, 64 );
+ check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
+ dw = get_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY );
+ todo_wine ok( dw == 32, "wrong value %u\n", dw );
+ check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
+ RegCloseKey( key );
+
+ err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
+ KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
+ ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
+ check_key_value( key, "Wine\\Winetest", 0, 32 );
+ dw = get_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY );
+ ok( dw == 32 || broken(dw == 64) /* vista */, "wrong value %u\n", dw );
+ check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
+ RegCloseKey( key );
+ }
check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", 0, ptr_size );
check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
RegCloseKey( key64 );
RegCloseKey( root32 );
RegCloseKey( root64 );
+
+ /* open key in native bit mode */
+ err = RegOpenKeyExA(HKEY_CLASSES_ROOT, "Interface", 0, KEY_ALL_ACCESS, &native);
+ ok(err == ERROR_SUCCESS, "got %i\n", err);
+
+ pRegDeleteKeyExA(native, "AWineTest", 0, 0);
+
+ /* write subkey in opposite bit mode */
+ err = RegOpenKeyExA(HKEY_CLASSES_ROOT, "Interface", 0, KEY_ALL_ACCESS | opposite, &op_key);
+ ok(err == ERROR_SUCCESS, "got %i\n", err);
+
+ err = RegCreateKeyExA(op_key, "AWineTest", 0, NULL, 0, KEY_ALL_ACCESS | opposite,
+ NULL, &key, NULL);
+ ok(err == ERROR_SUCCESS || err == ERROR_ACCESS_DENIED, "got %i\n", err);
+ if(err != ERROR_SUCCESS){
+ win_skip("Can't write to registry\n");
+ RegCloseKey(op_key);
+ RegCloseKey(native);
+ return;
+ }
+ RegCloseKey(key);
+
+ /* verify subkey is not present in native mode */
+ err = RegOpenKeyExA(native, "AWineTest", 0, KEY_ALL_ACCESS, &key);
+ ok(err == ERROR_FILE_NOT_FOUND ||
+ broken(err == ERROR_SUCCESS), /* before Win7, HKCR is reflected instead of redirected */
+ "got %i\n", err);
+
+ err = pRegDeleteKeyExA(op_key, "AWineTest", opposite, 0);
+ ok(err == ERROR_SUCCESS, "got %i\n", err);
+
+ RegCloseKey(op_key);
+ RegCloseKey(native);
}
static void test_classesroot(void)
todo_wine ok(res == ERROR_SUCCESS ||
broken(res == ERROR_FILE_NOT_FOUND /* WinNT */),
"test key not found in hkcr: %d\n", res);
- todo_wine ok(IS_HKCR(hkcr), "hkcr mask not set in %p\n", hkcr);
if (res)
{
skip("HKCR key merging not supported\n");
return;
}
+ todo_wine ok(IS_HKCR(hkcr), "hkcr mask not set in %p\n", hkcr);
+
/* set a value in user's classes */
res = RegSetValueExA(hkey, "val1", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
RegCloseKey( hklmsub1 );
/* delete subkey1 from hkcr (should point at user's classes) */
- res = RegDeleteKey(hkcr, "subkey1");
+ res = RegDeleteKeyA(hkcr, "subkey1");
ok(res == ERROR_SUCCESS, "RegDeleteKey failed: %d\n", res);
/* confirm key was removed in hkey but not hklm */
ok(!IS_HKCR(hklmsub1), "hkcr mask set in %p\n", hklmsub1);
/* delete subkey1 from hkcr again (which should now point at hklm) */
- res = RegDeleteKey(hkcr, "subkey1");
+ res = RegDeleteKeyA(hkcr, "subkey1");
ok(res == ERROR_SUCCESS, "RegDeleteKey failed: %d\n", res);
/* confirm hkey was removed in hklm */
res = RegOpenKeyA( HKEY_CLASSES_ROOT, "CLSID", &hkey );
ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %d\n", res);
- todo_wine ok(IS_HKCR(hkey), "hkcr mask not set in %p\n", hkey);
+ todo_wine ok(IS_HKCR(hkey) || broken(!IS_HKCR(hkey)) /* WinNT */,
+ "hkcr mask not set in %p\n", hkey);
RegCloseKey( hkey );
res = RegOpenKeyA( HKEY_CURRENT_USER, "Software", &hkey );
"expect ERROR_FILE_NOT_FOUND, got %i\n", res);
}
+static void test_delete_key_value(void)
+{
+ HKEY subkey;
+ LONG ret;
+
+ if (!pRegDeleteKeyValueA)
+ {
+ win_skip("RegDeleteKeyValue is not available.\n");
+ return;
+ }
+
+ ret = pRegDeleteKeyValueA(NULL, NULL, NULL);
+ ok(ret == ERROR_INVALID_HANDLE, "got %d\n", ret);
+
+ ret = pRegDeleteKeyValueA(hkey_main, NULL, NULL);
+ ok(ret == ERROR_FILE_NOT_FOUND, "got %d\n", ret);
+
+ ret = RegSetValueExA(hkey_main, "test", 0, REG_SZ, (const BYTE*)"value", 6);
+ ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+
+ ret = RegQueryValueExA(hkey_main, "test", NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+
+ /* NULL subkey name means delete from open key */
+ ret = pRegDeleteKeyValueA(hkey_main, NULL, "test");
+ ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+
+ ret = RegQueryValueExA(hkey_main, "test", NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_FILE_NOT_FOUND, "got %d\n", ret);
+
+ /* now with real subkey */
+ ret = RegCreateKeyExA(hkey_main, "Subkey1", 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &subkey, NULL);
+ ok(!ret, "failed with error %d\n", ret);
+
+ ret = RegSetValueExA(subkey, "test", 0, REG_SZ, (const BYTE*)"value", 6);
+ ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+
+ ret = RegQueryValueExA(subkey, "test", NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+
+ ret = pRegDeleteKeyValueA(hkey_main, "Subkey1", "test");
+ ok(ret == ERROR_SUCCESS, "got %d\n", ret);
+
+ ret = RegQueryValueExA(subkey, "test", NULL, NULL, NULL, NULL);
+ ok(ret == ERROR_FILE_NOT_FOUND, "got %d\n", ret);
+
+ RegDeleteKeyA(subkey, "");
+ RegCloseKey(subkey);
+}
+
START_TEST(registry)
{
/* Load pointers for functions that are not available in all Windows versions */
InitFunctionPtrs();
setup_main_key();
+ check_user_privs();
test_set_value();
create_test_entries();
test_enum_value();
test_reg_close_key();
test_reg_delete_key();
test_reg_query_value();
+ test_reg_query_info();
test_string_termination();
test_symlinks();
test_redirection();
test_classesroot_enum();
test_classesroot_mask();
- /* 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);
- }
+ test_reg_save_key();
+ test_reg_load_key();
+ test_reg_unload_key();
test_reg_delete_tree();
test_rw_order();
test_deleted_key();
test_delete_value();
+ test_delete_key_value();
/* cleanup */
delete_key( hkey_main );