kernelbase: Recursively obtain the Wow6432Node parent.
[wine.git] / dlls / advapi32 / tests / registry.c
blob9e051056eedbdd97602e48aed7d324d8b91635c4
1 /*
2 * Unit tests for registry functions
4 * Copyright (c) 2002 Alexandre Julliard
5 * Copyright (c) 2010 André Hentschel
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include "ntstatus.h"
26 #define WIN32_NO_STATUS
27 #include "wine/test.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winternl.h"
31 #include "winreg.h"
32 #include "winperf.h"
33 #include "winsvc.h"
34 #include "winerror.h"
35 #include "aclapi.h"
37 #define IS_HKCR(hk) ((UINT_PTR)hk > 0 && ((UINT_PTR)hk & 3) == 2)
39 static HKEY hkey_main;
40 static DWORD GLE;
42 static const char * sTestpath1 = "%LONGSYSTEMVAR%\\subdir1";
43 static const char * sTestpath2 = "%FOO%\\subdir1";
44 static const DWORD ptr_size = 8 * sizeof(void*);
46 static DWORD (WINAPI *pRegGetValueA)(HKEY,LPCSTR,LPCSTR,DWORD,LPDWORD,PVOID,LPDWORD);
47 static DWORD (WINAPI *pRegGetValueW)(HKEY,LPCWSTR,LPCWSTR,DWORD,LPDWORD,PVOID,LPDWORD);
48 static LONG (WINAPI *pRegCopyTreeA)(HKEY,const char *,HKEY);
49 static LONG (WINAPI *pRegDeleteTreeA)(HKEY,const char *);
50 static DWORD (WINAPI *pRegDeleteKeyExA)(HKEY,LPCSTR,REGSAM,DWORD);
51 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
52 static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
53 static NTSTATUS (WINAPI * pNtUnloadKey)(POBJECT_ATTRIBUTES);
54 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(UNICODE_STRING*);
55 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
56 static NTSTATUS (WINAPI * pRtlInitUnicodeString)(PUNICODE_STRING,PCWSTR);
57 static LONG (WINAPI *pRegDeleteKeyValueA)(HKEY,LPCSTR,LPCSTR);
58 static LONG (WINAPI *pRegSetKeyValueW)(HKEY,LPCWSTR,LPCWSTR,DWORD,const void*,DWORD);
59 static LONG (WINAPI *pRegLoadMUIStringA)(HKEY,LPCSTR,LPSTR,DWORD,LPDWORD,DWORD,LPCSTR);
60 static LONG (WINAPI *pRegLoadMUIStringW)(HKEY,LPCWSTR,LPWSTR,DWORD,LPDWORD,DWORD,LPCWSTR);
61 static DWORD (WINAPI *pEnumDynamicTimeZoneInformation)(const DWORD,
62 DYNAMIC_TIME_ZONE_INFORMATION*);
64 static BOOL limited_user;
66 static const char *dbgstr_SYSTEMTIME(const SYSTEMTIME *st)
68 return wine_dbg_sprintf("%02d-%02d-%04d %02d:%02d:%02d.%03d",
69 st->wMonth, st->wDay, st->wYear,
70 st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);
73 #define ADVAPI32_GET_PROC(func) \
74 p ## func = (void*)GetProcAddress(hadvapi32, #func)
76 static void InitFunctionPtrs(void)
78 HMODULE hntdll = GetModuleHandleA("ntdll.dll");
79 HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
80 HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
82 /* This function was introduced with Windows 2003 SP1 */
83 ADVAPI32_GET_PROC(RegGetValueA);
84 ADVAPI32_GET_PROC(RegGetValueW);
85 ADVAPI32_GET_PROC(RegCopyTreeA);
86 ADVAPI32_GET_PROC(RegDeleteTreeA);
87 ADVAPI32_GET_PROC(RegDeleteKeyExA);
88 ADVAPI32_GET_PROC(RegDeleteKeyValueA);
89 ADVAPI32_GET_PROC(RegSetKeyValueW);
90 ADVAPI32_GET_PROC(RegLoadMUIStringA);
91 ADVAPI32_GET_PROC(RegLoadMUIStringW);
92 ADVAPI32_GET_PROC(EnumDynamicTimeZoneInformation);
94 pIsWow64Process = (void *)GetProcAddress( hkernel32, "IsWow64Process" );
95 pRtlFormatCurrentUserKeyPath = (void *)GetProcAddress( hntdll, "RtlFormatCurrentUserKeyPath" );
96 pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString");
97 pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString");
98 pNtDeleteKey = (void *)GetProcAddress( hntdll, "NtDeleteKey" );
99 pNtUnloadKey = (void *)GetProcAddress( hntdll, "NtUnloadKey" );
102 static BOOL is_special_key(HKEY key)
104 return !!((ULONG_PTR)key & 0x80000000);
107 /* delete key and all its subkeys */
108 static DWORD delete_key( HKEY hkey )
110 char name[MAX_PATH];
111 DWORD ret;
113 if ((ret = RegOpenKeyExA( hkey, "", 0, KEY_ENUMERATE_SUB_KEYS, &hkey ))) return ret;
114 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
116 HKEY tmp;
117 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
119 ret = delete_key( tmp );
120 RegCloseKey( tmp );
122 if (ret) break;
124 if (ret != ERROR_NO_MORE_ITEMS) return ret;
125 RegDeleteKeyA( hkey, "" );
126 RegCloseKey(hkey);
127 return 0;
130 static void setup_main_key(void)
132 DWORD ret;
134 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main )) delete_key( hkey_main );
136 ret = RegCreateKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main );
137 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
140 static void check_user_privs(void)
142 DWORD ret;
143 HKEY hkey = (HKEY)0xdeadbeef;
145 ret = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WRITE, &hkey);
146 ok(ret == ERROR_SUCCESS || ret == ERROR_ACCESS_DENIED, "expected success or access denied, got %li\n", ret);
147 if (ret == ERROR_SUCCESS)
149 ok(hkey != NULL, "RegOpenKeyExA succeeded but returned NULL hkey\n");
150 RegCloseKey(hkey);
152 else
154 ok(hkey == NULL, "RegOpenKeyExA failed but returned hkey %p\n", hkey);
155 limited_user = TRUE;
156 trace("running as limited user\n");
160 #define lok ok_(__FILE__, line)
161 #define test_hkey_main_Value_A(name, string, full_byte_len) _test_hkey_main_Value_A(__LINE__, name, string, full_byte_len)
162 static void _test_hkey_main_Value_A(int line, LPCSTR name, LPCSTR string,
163 DWORD full_byte_len)
165 DWORD ret, type, cbData;
166 DWORD str_byte_len;
167 BYTE* value;
169 type=0xdeadbeef;
170 cbData=0xdeadbeef;
171 /* When successful RegQueryValueExA() leaves GLE as is,
172 * so we must reset it to detect unimplemented functions.
174 SetLastError(0xdeadbeef);
175 ret = RegQueryValueExA(hkey_main, name, NULL, &type, NULL, &cbData);
176 GLE = GetLastError();
177 lok(ret == ERROR_SUCCESS, "RegQueryValueExA/1 failed: %ld, GLE=%ld\n", ret, GLE);
178 /* It is wrong for the Ansi version to not be implemented */
179 ok(GLE == 0xdeadbeef, "RegQueryValueExA set GLE = %lu\n", GLE);
180 if(GLE == ERROR_CALL_NOT_IMPLEMENTED) return;
182 str_byte_len = (string ? lstrlenA(string) : 0) + 1;
183 lok(type == REG_SZ, "RegQueryValueExA/1 returned type %ld\n", type);
184 lok(cbData == full_byte_len, "cbData=%ld instead of %ld or %ld\n", cbData, full_byte_len, str_byte_len);
186 value = HeapAlloc(GetProcessHeap(), 0, cbData+1);
187 memset(value, 0xbd, cbData+1);
188 type=0xdeadbeef;
189 ret = RegQueryValueExA(hkey_main, name, NULL, &type, value, &cbData);
190 GLE = GetLastError();
191 lok(ret == ERROR_SUCCESS, "RegQueryValueExA/2 failed: %ld, GLE=%ld\n", ret, GLE);
192 if (!string)
194 /* When cbData == 0, RegQueryValueExA() should not modify the buffer */
195 lok(*value == 0xbd, "RegQueryValueExA overflowed: cbData=%lu *value=%02x\n", cbData, *value);
197 else
199 lok(memcmp(value, string, cbData) == 0, "RegQueryValueExA/2 failed: %s/%ld != %s/%ld\n",
200 debugstr_an((char*)value, cbData), cbData,
201 debugstr_an(string, full_byte_len), full_byte_len);
202 lok(*(value+cbData) == 0xbd, "RegQueryValueExA/2 overflowed at offset %lu: %02x != bd\n", cbData, *(value+cbData));
204 HeapFree(GetProcessHeap(), 0, value);
207 #define test_hkey_main_Value_W(name, string, full_byte_len) _test_hkey_main_Value_W(__LINE__, name, string, full_byte_len)
208 static void _test_hkey_main_Value_W(int line, LPCWSTR name, LPCWSTR string,
209 DWORD full_byte_len)
211 DWORD ret, type, cbData;
212 BYTE* value;
214 type=0xdeadbeef;
215 cbData=0xdeadbeef;
216 /* When successful RegQueryValueExW() leaves GLE as is,
217 * so we must reset it to detect unimplemented functions.
219 SetLastError(0xdeadbeef);
220 ret = RegQueryValueExW(hkey_main, name, NULL, &type, NULL, &cbData);
221 GLE = GetLastError();
222 lok(ret == ERROR_SUCCESS, "RegQueryValueExW/1 failed: %ld, GLE=%ld\n", ret, GLE);
223 if(GLE == ERROR_CALL_NOT_IMPLEMENTED)
225 win_skip("RegQueryValueExW() is not implemented\n");
226 return;
229 lok(type == REG_SZ, "RegQueryValueExW/1 returned type %ld\n", type);
230 lok(cbData == full_byte_len,
231 "cbData=%ld instead of %ld\n", cbData, full_byte_len);
233 /* Give enough space to overflow by one WCHAR */
234 value = HeapAlloc(GetProcessHeap(), 0, cbData+2);
235 memset(value, 0xbd, cbData+2);
236 type=0xdeadbeef;
237 ret = RegQueryValueExW(hkey_main, name, NULL, &type, value, &cbData);
238 GLE = GetLastError();
239 lok(ret == ERROR_SUCCESS, "RegQueryValueExW/2 failed: %ld, GLE=%ld\n", ret, GLE);
240 if (string)
242 lok(memcmp(value, string, cbData) == 0, "RegQueryValueExW failed: %s/%ld != %s/%ld\n",
243 wine_dbgstr_wn((WCHAR*)value, cbData / sizeof(WCHAR)), cbData,
244 wine_dbgstr_wn(string, full_byte_len / sizeof(WCHAR)), full_byte_len);
246 /* This implies that when cbData == 0, RegQueryValueExW() should not modify the buffer */
247 lok(*(value+cbData) == 0xbd, "RegQueryValueExW/2 overflowed at %lu: %02x != bd\n", cbData, *(value+cbData));
248 lok(*(value+cbData+1) == 0xbd, "RegQueryValueExW/2 overflowed at %lu+1: %02x != bd\n", cbData, *(value+cbData+1));
249 HeapFree(GetProcessHeap(), 0, value);
252 static void test_set_value(void)
254 DWORD ret;
256 static const WCHAR name1W[] = L"CleanSingleString";
257 static const WCHAR name2W[] = L"SomeIntraZeroedString";
258 static const WCHAR emptyW[] = L"";
259 static const WCHAR string1W[] = L"ThisNeverBreaks";
260 static const WCHAR string2W[] = L"This\0Breaks\0\0A\0\0\0Lot\0\0\0\0";
261 static const WCHAR substring2W[] = L"This";
263 static const char name1A[] = "CleanSingleString";
264 static const char name2A[] = "SomeIntraZeroedString";
265 static const char emptyA[] = "";
266 static const char string1A[] = "ThisNeverBreaks";
267 static const char string2A[] = "This\0Breaks\0\0A\0\0\0Lot\0\0\0\0";
268 static const char substring2A[] = "This";
270 if (0)
272 /* Crashes on NT4, Windows 2000 and XP SP1 */
273 ret = RegSetValueA(hkey_main, NULL, REG_SZ, NULL, 0);
274 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have failed with ERROR_INVALID_PARAMETER instead of %ld\n", ret);
277 ret = RegSetValueA(hkey_main, NULL, REG_SZ, string1A, sizeof(string1A));
278 ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %ld, GLE=%ld\n", ret, GetLastError());
279 test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
280 test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
282 /* RegSetValueA ignores the size passed in */
283 ret = RegSetValueA(hkey_main, NULL, REG_SZ, string1A, 4);
284 ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %ld, GLE=%ld\n", ret, GetLastError());
285 test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
286 test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
288 /* stops at first null */
289 ret = RegSetValueA(hkey_main, NULL, REG_SZ, string2A, sizeof(string2A));
290 ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %ld, GLE=%ld\n", ret, GetLastError());
291 test_hkey_main_Value_A(NULL, substring2A, sizeof(substring2A));
292 test_hkey_main_Value_W(NULL, substring2W, sizeof(substring2W));
294 /* only REG_SZ is supported on NT*/
295 ret = RegSetValueA(hkey_main, NULL, REG_BINARY, string2A, sizeof(string2A));
296 ok(ret == ERROR_INVALID_PARAMETER, "got %ld (expected ERROR_INVALID_PARAMETER)\n", ret);
298 ret = RegSetValueA(hkey_main, NULL, REG_EXPAND_SZ, string2A, sizeof(string2A));
299 ok(ret == ERROR_INVALID_PARAMETER, "got %ld (expected ERROR_INVALID_PARAMETER)\n", ret);
301 ret = RegSetValueA(hkey_main, NULL, REG_MULTI_SZ, string2A, sizeof(string2A));
302 ok(ret == ERROR_INVALID_PARAMETER, "got %ld (expected ERROR_INVALID_PARAMETER)\n", ret);
304 /* Test RegSetValueExA with a 'zero-byte' string (as Office 2003 does).
305 * Surprisingly enough we're supposed to get zero bytes out of it.
307 ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)emptyA, 0);
308 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%ld\n", ret, GetLastError());
309 test_hkey_main_Value_A(name1A, NULL, 0);
310 test_hkey_main_Value_W(name1W, NULL, 0);
312 /* test RegSetValueExA with an empty string */
313 ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)emptyA, sizeof(emptyA));
314 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%ld\n", ret, GetLastError());
315 test_hkey_main_Value_A(name1A, emptyA, sizeof(emptyA));
316 test_hkey_main_Value_W(name1W, emptyW, sizeof(emptyW));
318 /* test RegSetValueExA with off-by-one size */
319 ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)string1A, sizeof(string1A)-sizeof(string1A[0]));
320 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%ld\n", ret, GetLastError());
321 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
322 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
324 /* test RegSetValueExA with normal string */
325 ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)string1A, sizeof(string1A));
326 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%ld\n", ret, GetLastError());
327 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
328 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
330 /* test RegSetValueExA with intrazeroed string */
331 ret = RegSetValueExA(hkey_main, name2A, 0, REG_SZ, (const BYTE *)string2A, sizeof(string2A));
332 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%ld\n", ret, GetLastError());
333 test_hkey_main_Value_A(name2A, string2A, sizeof(string2A));
334 test_hkey_main_Value_W(name2W, string2W, sizeof(string2W));
336 if (0)
338 /* Crashes on NT4, Windows 2000 and XP SP1 */
339 ret = RegSetValueW(hkey_main, NULL, REG_SZ, NULL, 0);
340 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have failed with ERROR_INVALID_PARAMETER instead of %ld\n", ret);
342 RegSetValueExA(hkey_main, name2A, 0, REG_SZ, (const BYTE *)1, 1);
343 RegSetValueExA(hkey_main, name2A, 0, REG_DWORD, (const BYTE *)1, 1);
346 ret = RegSetValueW(hkey_main, NULL, REG_SZ, string1W, sizeof(string1W));
347 ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %ld, GLE=%ld\n", ret, GetLastError());
348 test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
349 test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
351 ret = RegSetValueW(hkey_main, name1W, REG_SZ, string1W, sizeof(string1W));
352 ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %ld, GLE=%ld\n", ret, GetLastError());
353 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
354 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
356 /* RegSetValueW ignores the size passed in */
357 ret = RegSetValueW(hkey_main, NULL, REG_SZ, string1W, 4 * sizeof(string1W[0]));
358 ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %ld, GLE=%ld\n", ret, GetLastError());
359 test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
360 test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
362 /* stops at first null */
363 ret = RegSetValueW(hkey_main, NULL, REG_SZ, string2W, sizeof(string2W));
364 ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %ld, GLE=%ld\n", ret, GetLastError());
365 test_hkey_main_Value_A(NULL, substring2A, sizeof(substring2A));
366 test_hkey_main_Value_W(NULL, substring2W, sizeof(substring2W));
368 /* only REG_SZ is supported */
369 ret = RegSetValueW(hkey_main, NULL, REG_BINARY, string2W, sizeof(string2W));
370 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %ld\n", ret);
371 ret = RegSetValueW(hkey_main, NULL, REG_EXPAND_SZ, string2W, sizeof(string2W));
372 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %ld\n", ret);
373 ret = RegSetValueW(hkey_main, NULL, REG_MULTI_SZ, string2W, sizeof(string2W));
374 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %ld\n", ret);
376 /* test RegSetValueExW with off-by-one size */
377 ret = RegSetValueExW(hkey_main, name1W, 0, REG_SZ, (const BYTE *)string1W, sizeof(string1W)-sizeof(string1W[0]));
378 ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %ld, GLE=%ld\n", ret, GetLastError());
379 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
380 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
382 /* test RegSetValueExW with normal string */
383 ret = RegSetValueExW(hkey_main, name1W, 0, REG_SZ, (const BYTE *)string1W, sizeof(string1W));
384 ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %ld, GLE=%ld\n", ret, GetLastError());
385 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
386 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
388 /* test RegSetValueExW with intrazeroed string */
389 ret = RegSetValueExW(hkey_main, name2W, 0, REG_SZ, (const BYTE *)string2W, sizeof(string2W));
390 ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %ld, GLE=%ld\n", ret, GetLastError());
391 test_hkey_main_Value_A(name2A, string2A, sizeof(string2A));
392 test_hkey_main_Value_W(name2W, string2W, sizeof(string2W));
394 /* test RegSetValueExW with data = 1 */
395 ret = RegSetValueExW(hkey_main, name2W, 0, REG_SZ, (const BYTE *)1, 1);
396 ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %ld, GLE=%ld\n", ret, GetLastError());
397 ret = RegSetValueExW(hkey_main, name2W, 0, REG_DWORD, (const BYTE *)1, 1);
398 ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %ld, GLE=%ld\n", ret, GetLastError());
400 if (pRegGetValueA) /* avoid a crash on Windows 2000 */
402 ret = RegSetValueExW(hkey_main, NULL, 0, REG_SZ, NULL, 4);
403 ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %ld, GLE=%ld\n", ret, GetLastError());
405 ret = RegSetValueExW(hkey_main, NULL, 0, REG_SZ, NULL, 0);
406 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
408 ret = RegSetValueExW(hkey_main, NULL, 0, REG_DWORD, NULL, 4);
409 ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %ld, GLE=%ld\n", ret, GetLastError());
411 ret = RegSetValueExW(hkey_main, NULL, 0, REG_DWORD, NULL, 0);
412 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
415 /* RegSetKeyValue */
416 if (!pRegSetKeyValueW)
417 win_skip("RegSetKeyValue() is not supported.\n");
418 else
420 DWORD len, type;
421 HKEY subkey;
423 ret = pRegSetKeyValueW(hkey_main, NULL, name1W, REG_SZ, (const BYTE*)string2W, sizeof(string2W));
424 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
425 test_hkey_main_Value_A(name1A, string2A, sizeof(string2A));
426 test_hkey_main_Value_W(name1W, string2W, sizeof(string2W));
428 ret = pRegSetKeyValueW(hkey_main, L"subkey", name1W, REG_SZ, string1W, sizeof(string1W));
429 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
431 ret = RegOpenKeyExW(hkey_main, L"subkey", 0, KEY_QUERY_VALUE, &subkey);
432 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
433 type = len = 0;
434 ret = RegQueryValueExW(subkey, name1W, 0, &type, NULL, &len);
435 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
436 ok(len == sizeof(string1W), "got %ld\n", len);
437 ok(type == REG_SZ, "got type %ld\n", type);
439 ret = pRegSetKeyValueW(hkey_main, L"subkey", name1W, REG_SZ, NULL, 0);
440 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
442 ret = pRegSetKeyValueW(hkey_main, L"subkey", name1W, REG_SZ, NULL, 4);
443 ok(ret == ERROR_NOACCESS, "got %ld\n", ret);
445 ret = pRegSetKeyValueW(hkey_main, L"subkey", name1W, REG_DWORD, NULL, 4);
446 ok(ret == ERROR_NOACCESS, "got %ld\n", ret);
448 RegCloseKey(subkey);
452 static void create_test_entries(void)
454 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
456 SetEnvironmentVariableA("LONGSYSTEMVAR", "bar");
457 SetEnvironmentVariableA("FOO", "ImARatherLongButIndeedNeededString");
459 ok(!RegSetValueExA(hkey_main,"TP1_EXP_SZ",0,REG_EXPAND_SZ, (const BYTE *)sTestpath1, strlen(sTestpath1)+1),
460 "RegSetValueExA failed\n");
461 ok(!RegSetValueExA(hkey_main,"TP1_SZ",0,REG_SZ, (const BYTE *)sTestpath1, strlen(sTestpath1)+1),
462 "RegSetValueExA failed\n");
463 ok(!RegSetValueExA(hkey_main,"TP1_ZB_SZ",0,REG_SZ, (const BYTE *)"", 0),
464 "RegSetValueExA failed\n");
465 ok(!RegSetValueExA(hkey_main,"TP2_EXP_SZ",0,REG_EXPAND_SZ, (const BYTE *)sTestpath2, strlen(sTestpath2)+1),
466 "RegSetValueExA failed\n");
467 ok(!RegSetValueExA(hkey_main,"DWORD",0,REG_DWORD, (const BYTE *)qw, 4),
468 "RegSetValueExA failed\n");
469 ok(!RegSetValueExA(hkey_main,"BIN32",0,REG_BINARY, (const BYTE *)qw, 4),
470 "RegSetValueExA failed\n");
471 ok(!RegSetValueExA(hkey_main,"BIN64",0,REG_BINARY, (const BYTE *)qw, 8),
472 "RegSetValueExA failed\n");
475 static void test_enum_value(void)
477 DWORD res;
478 HKEY test_key;
479 char value[20], data[30];
480 WCHAR valueW[20], dataW[20];
481 DWORD val_count, data_count, type;
483 /* create the working key for new 'Test' value */
484 res = RegCreateKeyA( hkey_main, "TestKey", &test_key );
485 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", res);
487 /* check NULL data with zero length */
488 res = RegSetValueExA( test_key, "Test", 0, REG_SZ, NULL, 0 );
489 if (GetVersion() & 0x80000000)
490 ok( res == ERROR_INVALID_PARAMETER, "RegSetValueExA returned %ld\n", res );
491 else
492 ok( !res, "RegSetValueExA returned %ld\n", res );
493 res = RegSetValueExA( test_key, "Test", 0, REG_EXPAND_SZ, NULL, 0 );
494 ok( ERROR_SUCCESS == res, "RegSetValueExA returned %ld\n", res );
495 res = RegSetValueExA( test_key, "Test", 0, REG_BINARY, NULL, 0 );
496 ok( ERROR_SUCCESS == res, "RegSetValueExA returned %ld\n", res );
498 /* test reading the value and data without setting them */
499 val_count = 20;
500 data_count = 20;
501 type = 1234;
502 strcpy( value, "xxxxxxxxxx" );
503 strcpy( data, "xxxxxxxxxx" );
504 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
505 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", res );
506 ok( val_count == 4, "val_count set to %ld instead of 4\n", val_count );
507 ok( data_count == 0, "data_count set to %ld instead of 0\n", data_count );
508 ok( type == REG_BINARY, "type %ld is not REG_BINARY\n", type );
509 ok( !strcmp( value, "Test" ), "value is '%s' instead of Test\n", value );
510 ok( !strcmp( data, "xxxxxxxxxx" ), "data is '%s' instead of xxxxxxxxxx\n", data );
512 val_count = 20;
513 data_count = 20;
514 type = 1234;
515 wcscpy( valueW, L"xxxxxxxx" );
516 wcscpy( dataW, L"xxxxxxxx" );
517 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
518 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", res );
519 ok( val_count == 4, "val_count set to %ld instead of 4\n", val_count );
520 ok( data_count == 0, "data_count set to %ld instead of 0\n", data_count );
521 ok( type == REG_BINARY, "type %ld is not REG_BINARY\n", type );
522 ok( !wcscmp( valueW, L"Test" ), "value is not 'Test'\n" );
523 ok( !wcscmp( dataW, L"xxxxxxxx" ), "data is not 'xxxxxxxx'\n" );
525 res = RegSetValueExA( test_key, "Test", 0, REG_SZ, (const BYTE *)"foobar", 7 );
526 ok( res == 0, "RegSetValueExA failed error %ld\n", res );
528 /* overflow both name and data */
529 val_count = 2;
530 data_count = 2;
531 type = 1234;
532 strcpy( value, "xxxxxxxxxx" );
533 strcpy( data, "xxxxxxxxxx" );
534 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
535 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
536 ok( val_count == 2, "val_count set to %ld\n", val_count );
537 /* Chinese, Japanese, and Korean editions of Windows 10 sometimes set data_count to a higher value */
538 ok( data_count == 7 || broken( data_count > 7 ), "data_count set to %ld instead of 7\n", data_count );
539 ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
540 ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
541 ok( !strcmp( data, "xxxxxxxxxx" ), "data set to '%s'\n", data );
543 /* overflow name */
544 val_count = 3;
545 data_count = 16;
546 type = 1234;
547 strcpy( value, "xxxxxxxxxx" );
548 memset( data, 'x', sizeof(data) );
549 data[sizeof(data)-1] = '\0';
550 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
551 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
552 ok( val_count == 3, "val_count set to %ld\n", val_count );
553 /* In double-byte and UTF-8 locales Windows 10 may set data_count > 7,
554 * potentially even more than the declared buffer size, in which case the
555 * buffer is not NUL-terminated.
557 ok( data_count == 7 || broken( data_count > 7 ), "data_count set to %ld instead of 7\n", data_count );
558 ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
559 /* v5.1.2600.0 (XP Home and Professional) does not touch value or data in
560 * this case. Neither does Windows 10 21H1 in UTF-8 locales.
562 ok( !strcmp( value, "Te" ) || !strcmp( value, "xxxxxxxxxx" ),
563 "value set to '%s' instead of 'Te' or 'xxxxxxxxxx'\n", value );
564 ok( !strcmp( data, "foobar" ) || !strcmp( data, "xxxxxxx" ) ||
565 broken( data_count > 7 && data_count < 16 &&
566 strspn( data, "x" ) == data_count && data[data_count] == 0 ) ||
567 broken( data_count >= 16 && strspn( data, "x" ) == sizeof(data) - 1 ),
568 "data set to '%s' instead of 'foobar' or x's, data_count=%lu\n", data, data_count );
570 /* overflow empty name */
571 val_count = 0;
572 data_count = 16;
573 type = 1234;
574 strcpy( value, "xxxxxxxxxx" );
575 memset( data, 'x', sizeof(data) );
576 data[sizeof(data)-1] = '\0';
577 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
578 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
579 ok( val_count == 0, "val_count set to %ld\n", val_count );
580 /* See comment in 'overflow name' section */
581 ok( data_count == 7 || broken( data_count > 7 ), "data_count set to %ld instead of 7\n", data_count );
582 ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
583 ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
584 /* See comment in 'overflow name' section */
585 ok( !strcmp( data, "foobar" ) || !strcmp( data, "xxxxxxx" ) ||
586 broken( data_count > 7 && data_count < 16 &&
587 strspn( data, "x" ) == data_count && data[data_count] == 0 ) ||
588 broken( data_count >= 16 && strspn( data, "x" ) == sizeof(data) - 1 ),
589 "data set to '%s' instead of 'foobar' or x's, data_count=%lu\n", data, data_count );
591 /* overflow data */
592 val_count = 20;
593 data_count = 2;
594 type = 1234;
595 strcpy( value, "xxxxxxxxxx" );
596 strcpy( data, "xxxxxxxxxx" );
597 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
598 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
599 ok( val_count == 20, "val_count set to %ld\n", val_count );
600 ok( data_count == 7, "data_count set to %ld instead of 7\n", data_count );
601 ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
602 ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
603 ok( !strcmp( data, "xxxxxxxxxx" ), "data set to '%s'\n", data );
605 /* no overflow */
606 val_count = 20;
607 data_count = 20;
608 type = 1234;
609 strcpy( value, "xxxxxxxxxx" );
610 strcpy( data, "xxxxxxxxxx" );
611 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
612 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", res );
613 ok( val_count == 4, "val_count set to %ld instead of 4\n", val_count );
614 ok( data_count == 7, "data_count set to %ld instead of 7\n", data_count );
615 ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
616 ok( !strcmp( value, "Test" ), "value is '%s' instead of Test\n", value );
617 ok( !strcmp( data, "foobar" ), "data is '%s' instead of foobar\n", data );
619 if (pRegGetValueA) /* avoid a crash on Windows 2000 */
621 /* no value and no val_count parameter */
622 data_count = 20;
623 type = 1234;
624 strcpy( data, "xxxxxxxxxx" );
625 res = RegEnumValueA( test_key, 0, NULL, NULL, NULL, &type, (BYTE*)data, &data_count );
626 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", res );
628 /* no value parameter */
629 val_count = 20;
630 data_count = 20;
631 type = 1234;
632 strcpy( data, "xxxxxxxxxx" );
633 res = RegEnumValueA( test_key, 0, NULL, &val_count, NULL, &type, (BYTE*)data, &data_count );
634 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", res );
636 /* no val_count parameter */
637 data_count = 20;
638 type = 1234;
639 strcpy( value, "xxxxxxxxxx" );
640 strcpy( data, "xxxxxxxxxx" );
641 res = RegEnumValueA( test_key, 0, value, NULL, NULL, &type, (BYTE*)data, &data_count );
642 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", res );
645 /* Unicode tests */
647 SetLastError(0xdeadbeef);
648 res = RegSetValueExW( test_key, L"Test", 0, REG_SZ, (const BYTE *)L"foobar", 7*sizeof(WCHAR) );
649 if (res==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
651 win_skip("RegSetValueExW is not implemented\n");
652 goto cleanup;
654 ok( res == 0, "RegSetValueExW failed error %ld\n", res );
656 /* overflow both name and data */
657 val_count = 2;
658 data_count = 2;
659 type = 1234;
660 wcscpy( valueW, L"xxxxxxxx" );
661 wcscpy( dataW, L"xxxxxxxx" );
662 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
663 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
664 ok( val_count == 2, "val_count set to %ld\n", val_count );
665 ok( data_count == 7*sizeof(WCHAR), "data_count set to %ld instead of 7*sizeof(WCHAR)\n", data_count );
666 ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
667 ok( !wcscmp( valueW, L"xxxxxxxx" ), "value modified\n" );
668 ok( !wcscmp( dataW, L"xxxxxxxx" ), "data modified\n" );
670 /* overflow name */
671 val_count = 3;
672 data_count = 20;
673 type = 1234;
674 wcscpy( valueW, L"xxxxxxxx" );
675 wcscpy( dataW, L"xxxxxxxx" );
676 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
677 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
678 ok( val_count == 3, "val_count set to %ld\n", val_count );
679 ok( data_count == 7*sizeof(WCHAR), "data_count set to %ld instead of 7*sizeof(WCHAR)\n", data_count );
680 ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
681 ok( !wcscmp( valueW, L"xxxxxxxx" ), "value modified\n" );
682 ok( !wcscmp( dataW, L"xxxxxxxx" ), "data modified\n" );
684 /* overflow data */
685 val_count = 20;
686 data_count = 2;
687 type = 1234;
688 wcscpy( valueW, L"xxxxxxxx" );
689 wcscpy( dataW, L"xxxxxxxx" );
690 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
691 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
692 ok( val_count == 4, "val_count set to %ld instead of 4\n", val_count );
693 ok( data_count == 7*sizeof(WCHAR), "data_count set to %ld instead of 7*sizeof(WCHAR)\n", data_count );
694 ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
695 ok( !wcscmp( valueW, L"Test" ), "value is not 'Test'\n" );
696 ok( !wcscmp( dataW, L"xxxxxxxx" ), "data modified\n" );
698 /* no overflow */
699 val_count = 20;
700 data_count = 20;
701 type = 1234;
702 wcscpy( valueW, L"xxxxxxxx" );
703 wcscpy( dataW, L"xxxxxxxx" );
704 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
705 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", res );
706 ok( val_count == 4, "val_count set to %ld instead of 4\n", val_count );
707 ok( data_count == 7*sizeof(WCHAR), "data_count set to %ld instead of 7*sizeof(WCHAR)\n", data_count );
708 ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
709 ok( !wcscmp( valueW, L"Test" ), "value is not 'Test'\n" );
710 ok( !wcscmp( dataW, L"foobar" ), "data is not 'foobar'\n" );
712 if (pRegGetValueA) /* avoid a crash on Windows 2000 */
714 /* no valueW and no val_count parameter */
715 data_count = 20;
716 type = 1234;
717 wcscpy( dataW, L"xxxxxxxx" );
718 res = RegEnumValueW( test_key, 0, NULL, NULL, NULL, &type, (BYTE*)dataW, &data_count );
719 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", res );
721 /* no valueW parameter */
722 val_count = 20;
723 data_count = 20;
724 type = 1234;
725 wcscpy( dataW, L"xxxxxxxx" );
726 res = RegEnumValueW( test_key, 0, NULL, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
727 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", res );
729 /* no val_count parameter */
730 data_count = 20;
731 type = 1234;
732 wcscpy( valueW, L"xxxxxxxx" );
733 wcscpy( dataW, L"xxxxxxxx" );
734 res = RegEnumValueW( test_key, 0, valueW, NULL, NULL, &type, (BYTE*)dataW, &data_count );
735 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", res );
738 cleanup:
739 RegDeleteKeyA(test_key, "");
740 RegCloseKey(test_key);
743 static void test_query_value_ex(void)
745 DWORD ret, size, type;
746 BYTE buffer[10];
748 size = sizeof(buffer);
749 ret = RegQueryValueExA(hkey_main, "TP1_SZ", NULL, &type, NULL, &size);
750 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
751 ok(size == strlen(sTestpath1) + 1, "(%ld,%ld)\n", (DWORD)strlen(sTestpath1) + 1, size);
752 ok(type == REG_SZ, "type %ld is not REG_SZ\n", type);
754 type = 0xdeadbeef;
755 size = 0xdeadbeef;
756 ret = RegQueryValueExA(HKEY_CLASSES_ROOT, "Nonexistent Value", NULL, &type, NULL, &size);
757 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %ld\n", ret);
758 ok(size == 0, "size should have been set to 0 instead of %ld\n", size);
760 size = sizeof(buffer);
761 ret = RegQueryValueExA(HKEY_CLASSES_ROOT, "Nonexistent Value", NULL, &type, buffer, &size);
762 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %ld\n", ret);
763 ok(size == sizeof(buffer), "size shouldn't have been changed to %ld\n", size);
765 size = 4;
766 ret = RegQueryValueExA(hkey_main, "BIN32", NULL, &size, buffer, &size);
767 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
770 static void test_get_value(void)
772 DWORD ret;
773 DWORD size;
774 DWORD type;
775 DWORD dw, qw[2];
776 CHAR buf[80];
777 CHAR expanded[] = "bar\\subdir1";
778 CHAR expanded2[] = "ImARatherLongButIndeedNeededString\\subdir1";
780 if(!pRegGetValueA)
782 win_skip("RegGetValue not available on this platform\n");
783 return;
786 /* Invalid parameter */
787 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD, &type, &dw, NULL);
788 ok(ret == ERROR_INVALID_PARAMETER, "ret=%ld\n", ret);
790 /* Query REG_DWORD using RRF_RT_REG_DWORD (ok) */
791 size = type = dw = 0xdeadbeef;
792 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD, &type, &dw, &size);
793 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
794 ok(size == 4, "size=%ld\n", size);
795 ok(type == REG_DWORD, "type=%ld\n", type);
796 ok(dw == 0x12345678, "dw=%ld\n", dw);
798 /* Check RRF_SUBKEY_WOW64*KEY validation on a case without a subkey */
799 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY | RRF_SUBKEY_WOW6432KEY, NULL, NULL, NULL);
800 ok(ret == ERROR_INVALID_PARAMETER || broken(ret == ERROR_SUCCESS), /* Before Win10 */
801 "ret=%ld\n", ret);
802 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY, NULL, NULL, NULL);
803 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
804 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6432KEY, NULL, NULL, NULL);
805 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
807 /* Query by subkey-name */
808 ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD, NULL, NULL, NULL);
809 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
811 /* Check RRF_SUBKEY_WOW64*KEY validation on a case with a subkey */
812 ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY | RRF_SUBKEY_WOW6432KEY, NULL, NULL, NULL);
813 ok(ret == ERROR_INVALID_PARAMETER || broken(ret == ERROR_SUCCESS), /* Before Win10 */
814 "ret=%ld\n", ret);
815 ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY, NULL, NULL, NULL);
816 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
817 ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6432KEY, NULL, NULL, NULL);
818 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
820 /* Query REG_DWORD using RRF_RT_REG_BINARY (restricted) */
821 size = type = dw = 0xdeadbeef;
822 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_BINARY, &type, &dw, &size);
823 ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%ld\n", ret);
824 /* Although the function failed all values are retrieved */
825 ok(size == 4, "size=%ld\n", size);
826 ok(type == REG_DWORD, "type=%ld\n", type);
827 ok(dw == 0x12345678, "dw=%ld\n", dw);
829 /* Test RRF_ZEROONFAILURE */
830 type = dw = 0xdeadbeef; size = 4;
831 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_SZ|RRF_ZEROONFAILURE, &type, &dw, &size);
832 ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%ld\n", ret);
833 /* Again all values are retrieved ... */
834 ok(size == 4, "size=%ld\n", size);
835 ok(type == REG_DWORD, "type=%ld\n", type);
836 /* ... except the buffer, which is zeroed out */
837 ok(dw == 0, "dw=%ld\n", dw);
839 /* Test RRF_ZEROONFAILURE with a NULL buffer... */
840 type = size = 0xbadbeef;
841 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_SZ|RRF_ZEROONFAILURE, &type, NULL, &size);
842 ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%ld\n", ret);
843 ok(size == 4, "size=%ld\n", size);
844 ok(type == REG_DWORD, "type=%ld\n", type);
846 /* Query REG_DWORD using RRF_RT_DWORD (ok) */
847 size = type = dw = 0xdeadbeef;
848 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_DWORD, &type, &dw, &size);
849 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
850 ok(size == 4, "size=%ld\n", size);
851 ok(type == REG_DWORD, "type=%ld\n", type);
852 ok(dw == 0x12345678, "dw=%ld\n", dw);
854 /* Query 32-bit REG_BINARY using RRF_RT_DWORD (ok) */
855 size = type = dw = 0xdeadbeef;
856 ret = pRegGetValueA(hkey_main, NULL, "BIN32", RRF_RT_DWORD, &type, &dw, &size);
857 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
858 ok(size == 4, "size=%ld\n", size);
859 ok(type == REG_BINARY, "type=%ld\n", type);
860 ok(dw == 0x12345678, "dw=%ld\n", dw);
862 /* Query 64-bit REG_BINARY using RRF_RT_DWORD (type mismatch) */
863 qw[0] = qw[1] = size = type = 0xdeadbeef;
864 ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_DWORD, &type, qw, &size);
865 ok(ret == ERROR_DATATYPE_MISMATCH, "ret=%ld\n", ret);
866 ok(size == 8, "size=%ld\n", size);
867 ok(type == REG_BINARY, "type=%ld\n", type);
868 ok(qw[0] == 0x12345678 &&
869 qw[1] == 0x87654321, "qw={%ld,%ld}\n", qw[0], qw[1]);
871 /* Query 64-bit REG_BINARY using 32-bit buffer (buffer too small) */
872 type = dw = 0xdeadbeef; size = 4;
873 ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_REG_BINARY, &type, &dw, &size);
874 ok(ret == ERROR_MORE_DATA, "ret=%ld\n", ret);
875 ok(dw == 0xdeadbeef, "dw=%ld\n", dw);
876 ok(size == 8, "size=%ld\n", size);
878 /* Query 64-bit REG_BINARY using RRF_RT_QWORD (ok) */
879 qw[0] = qw[1] = size = type = 0xdeadbeef;
880 ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_QWORD, &type, qw, &size);
881 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
882 ok(size == 8, "size=%ld\n", size);
883 ok(type == REG_BINARY, "type=%ld\n", type);
884 ok(qw[0] == 0x12345678 &&
885 qw[1] == 0x87654321, "qw={%ld,%ld}\n", qw[0], qw[1]);
887 /* Query REG_SZ using RRF_RT_REG_SZ (ok) */
888 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
889 ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ, &type, buf, &size);
890 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
891 ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%ld\n", lstrlenA(sTestpath1), size);
892 ok(type == REG_SZ, "type=%ld\n", type);
893 ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
895 /* Query REG_SZ using RRF_RT_REG_SZ and no buffer (ok) */
896 type = 0xdeadbeef; size = 0;
897 ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ, &type, NULL, &size);
898 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
899 /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
900 ok(size == strlen(sTestpath1)+1 || broken(size == strlen(sTestpath1)+2),
901 "strlen(sTestpath1)=%d size=%ld\n", lstrlenA(sTestpath1), size);
902 ok(type == REG_SZ, "type=%ld\n", type);
904 /* Query REG_SZ using RRF_RT_REG_SZ on a zero-byte value (ok) */
905 strcpy(buf, sTestpath1);
906 type = 0xdeadbeef;
907 size = sizeof(buf);
908 ret = pRegGetValueA(hkey_main, NULL, "TP1_ZB_SZ", RRF_RT_REG_SZ, &type, buf, &size);
909 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
910 /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
911 ok(size == 0 ||
912 size == 1, /* win2k3 */
913 "size=%ld\n", size);
914 ok(type == REG_SZ, "type=%ld\n", type);
915 ok(!strcmp(sTestpath1, buf) ||
916 !strcmp(buf, ""),
917 "Expected \"%s\" or \"\", got \"%s\"\n", sTestpath1, buf);
919 /* Query REG_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (ok) */
920 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
921 ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ|RRF_NOEXPAND, &type, buf, &size);
922 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
923 ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%ld\n", lstrlenA(sTestpath1), size);
924 ok(type == REG_SZ, "type=%ld\n", type);
925 ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
927 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ and no buffer (ok, expands) */
928 size = 0;
929 ret = pRegGetValueA(hkey_main, NULL, "TP2_EXP_SZ", RRF_RT_REG_SZ, NULL, NULL, &size);
930 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
931 ok((size == strlen(expanded2)+1) || /* win2k3 SP1 */
932 (size == strlen(expanded2)+2) || /* win2k3 SP2 */
933 (size == strlen(sTestpath2)+1),
934 "strlen(expanded2)=%d, strlen(sTestpath2)=%d, size=%ld\n", lstrlenA(expanded2), lstrlenA(sTestpath2), size);
936 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ (ok, expands) */
937 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
938 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_SZ, &type, buf, &size);
939 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
940 /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath1 length + 1 here. */
941 ok(size == strlen(expanded)+1 || broken(size == strlen(sTestpath1)+1),
942 "strlen(expanded)=%d, strlen(sTestpath1)=%d, size=%ld\n", lstrlenA(expanded), lstrlenA(sTestpath1), size);
943 ok(type == REG_SZ, "type=%ld\n", type);
944 ok(!strcmp(expanded, buf), "expanded=\"%s\" buf=\"%s\"\n", expanded, buf);
946 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ (ok, expands a lot) */
947 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
948 ret = pRegGetValueA(hkey_main, NULL, "TP2_EXP_SZ", RRF_RT_REG_SZ, &type, buf, &size);
949 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
950 /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath2 length + 1 here. */
951 ok(size == strlen(expanded2)+1 || broken(size == strlen(sTestpath2)+1),
952 "strlen(expanded2)=%d, strlen(sTestpath1)=%d, size=%ld\n", lstrlenA(expanded2), lstrlenA(sTestpath2), size);
953 ok(type == REG_SZ, "type=%ld\n", type);
954 ok(!strcmp(expanded2, buf), "expanded2=\"%s\" buf=\"%s\"\n", expanded2, buf);
956 /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND (ok, doesn't expand) */
957 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
958 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND, &type, buf, &size);
959 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
960 ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%ld\n", lstrlenA(sTestpath1), size);
961 ok(type == REG_EXPAND_SZ, "type=%ld\n", type);
962 ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
964 /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND and no buffer (ok, doesn't expand) */
965 size = 0xbadbeef;
966 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND, NULL, NULL, &size);
967 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
968 /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
969 ok(size == strlen(sTestpath1)+1 || broken(size == strlen(sTestpath1)+2),
970 "strlen(sTestpath1)=%d size=%ld\n", lstrlenA(sTestpath1), size);
972 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (type mismatch) */
973 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_SZ|RRF_NOEXPAND, NULL, NULL, NULL);
974 ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%ld\n", ret);
976 /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ (not allowed without RRF_NOEXPAND) */
977 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ, NULL, NULL, NULL);
978 /* before win8: ERROR_INVALID_PARAMETER, win8: ERROR_UNSUPPORTED_TYPE */
979 ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_UNSUPPORTED_TYPE, "ret=%ld\n", ret);
981 /* Query REG_EXPAND_SZ using RRF_RT_ANY */
982 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
983 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_ANY, &type, buf, &size);
984 ok(ret == ERROR_SUCCESS, "ret=%ld\n", ret);
985 /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath1 length + 1 here. */
986 ok(size == strlen(expanded)+1 || broken(size == strlen(sTestpath1)+1),
987 "strlen(expanded)=%d, strlen(sTestpath1)=%d, size=%ld\n", lstrlenA(expanded), lstrlenA(sTestpath1), size);
988 ok(type == REG_SZ, "type=%ld\n", type);
989 ok(!strcmp(expanded, buf), "expanded=\"%s\" buf=\"%s\"\n", expanded, buf);
992 static void test_reg_open_key(void)
994 DWORD ret = 0;
995 HKEY hkResult = NULL;
996 HKEY hkPreserve = NULL;
997 HKEY hkRoot64 = NULL;
998 HKEY hkRoot32 = NULL;
999 BOOL bRet;
1000 SID_IDENTIFIER_AUTHORITY sid_authority = {SECURITY_WORLD_SID_AUTHORITY};
1001 PSID world_sid;
1002 EXPLICIT_ACCESSA access;
1003 PACL key_acl;
1004 SECURITY_DESCRIPTOR *sd;
1006 /* successful open */
1007 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
1008 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1009 ok(hkResult != NULL, "expected hkResult != NULL\n");
1010 hkPreserve = hkResult;
1012 /* open same key twice */
1013 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
1014 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1015 ok(hkResult != hkPreserve, "expected hkResult != hkPreserve\n");
1016 ok(hkResult != NULL, "hkResult != NULL\n");
1017 RegCloseKey(hkResult);
1019 /* trailing slashes */
1020 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test\\\\", &hkResult);
1021 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1022 RegCloseKey(hkResult);
1024 /* open nonexistent key
1025 * check that hkResult is set to NULL
1027 hkResult = hkPreserve;
1028 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Nonexistent", &hkResult);
1029 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %ld\n", ret);
1030 ok(hkResult == NULL, "expected hkResult == NULL\n");
1032 /* open the same nonexistent key again to make sure the key wasn't created */
1033 hkResult = hkPreserve;
1034 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Nonexistent", &hkResult);
1035 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %ld\n", ret);
1036 ok(hkResult == NULL, "expected hkResult == NULL\n");
1038 /* send in NULL lpSubKey
1039 * check that hkResult receives the value of hKey
1041 hkResult = hkPreserve;
1042 ret = RegOpenKeyA(HKEY_CURRENT_USER, NULL, &hkResult);
1043 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1044 ok(hkResult == HKEY_CURRENT_USER, "expected hkResult == HKEY_CURRENT_USER\n");
1046 /* send empty-string in lpSubKey */
1047 hkResult = hkPreserve;
1048 ret = RegOpenKeyA(HKEY_CURRENT_USER, "", &hkResult);
1049 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1050 ok(hkResult == HKEY_CURRENT_USER, "expected hkResult == HKEY_CURRENT_USER\n");
1052 /* send in NULL lpSubKey and NULL hKey
1053 * hkResult is set to NULL
1055 hkResult = hkPreserve;
1056 ret = RegOpenKeyA(NULL, NULL, &hkResult);
1057 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1058 ok(hkResult == NULL, "expected hkResult == NULL\n");
1060 /* only send NULL hKey
1061 * the value of hkResult remains unchanged
1063 hkResult = hkPreserve;
1064 ret = RegOpenKeyA(NULL, "Software\\Wine\\Test", &hkResult);
1065 ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 95 returns BADKEY */
1066 "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %ld\n", ret);
1067 ok(hkResult == hkPreserve, "expected hkResult == hkPreserve\n");
1069 /* send in NULL hkResult */
1070 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", NULL);
1071 ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", ret);
1073 ret = RegOpenKeyA(HKEY_CURRENT_USER, NULL, NULL);
1074 ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", ret);
1076 ret = RegOpenKeyA(NULL, NULL, NULL);
1077 ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", ret);
1079 /* beginning backslash character */
1080 ret = RegOpenKeyA(HKEY_CURRENT_USER, "\\Software\\Wine\\Test", &hkResult);
1081 ok(ret == ERROR_BAD_PATHNAME || /* NT/2k/XP */
1082 broken(ret == ERROR_SUCCESS), /* wow64 */
1083 "expected ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %ld\n", ret);
1084 if (!ret) RegCloseKey(hkResult);
1086 hkResult = NULL;
1087 ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "\\clsid", 0, KEY_QUERY_VALUE, &hkResult);
1088 ok(ret == ERROR_SUCCESS || /* 2k/XP */
1089 ret == ERROR_BAD_PATHNAME, /* NT */
1090 "expected ERROR_SUCCESS, ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %ld\n", ret);
1091 RegCloseKey(hkResult);
1093 /* NULL or empty subkey of special root */
1094 hkResult = NULL;
1095 ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, NULL, 0, KEY_QUERY_VALUE, &hkResult);
1096 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1097 ok(hkResult == HKEY_CLASSES_ROOT, "expected hkResult == HKEY_CLASSES_ROOT\n");
1099 hkResult = NULL;
1100 ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "", 0, KEY_QUERY_VALUE, &hkResult);
1101 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1102 ok(hkResult == HKEY_CLASSES_ROOT, "expected hkResult == HKEY_CLASSES_ROOT\n");
1104 hkResult = NULL;
1105 ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "\\", 0, KEY_QUERY_VALUE, &hkResult);
1106 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1107 ok(hkResult != HKEY_CLASSES_ROOT, "expected hkResult to be a new key\n");
1108 ok(!RegCloseKey(hkResult), "got invalid hkey\n");
1110 /* empty subkey of existing handle */
1111 hkResult = hkPreserve;
1112 ret = RegOpenKeyExA(hkPreserve, "", 0, KEY_QUERY_VALUE, &hkResult);
1113 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1114 ok(hkResult != hkPreserve, "expected hkResult != hkPreserve\n");
1115 ok(!RegCloseKey(hkResult), "got invalid hkey\n");
1117 /* NULL subkey of existing handle */
1118 hkResult = hkPreserve;
1119 ret = RegOpenKeyExA(hkPreserve, NULL, 0, KEY_QUERY_VALUE, &hkResult);
1120 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1121 ok(hkResult != hkPreserve, "expected hkResult != hkPreserve\n");
1122 ok(!RegCloseKey(hkResult), "got invalid hkey\n");
1124 /* empty subkey of NULL */
1125 hkResult = hkPreserve;
1126 ret = RegOpenKeyExW(NULL, L"", 0, KEY_QUERY_VALUE, &hkResult);
1127 ok(ret == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", ret);
1128 ok(hkResult == NULL || broken(hkResult == hkPreserve /* Windows XP */), "expected hkResult == NULL\n");
1130 hkResult = hkPreserve;
1131 ret = RegOpenKeyExA(NULL, "", 0, KEY_QUERY_VALUE, &hkResult);
1132 ok(ret == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", ret);
1133 ok(hkResult == hkPreserve, "expected hkResult == hkPreserve\n");
1135 RegCloseKey(hkPreserve);
1137 /* WOW64 flags */
1138 hkResult = NULL;
1139 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WOW64_32KEY, &hkResult);
1140 ok((ret == ERROR_SUCCESS && hkResult != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */),
1141 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%lu)\n", ret);
1142 RegCloseKey(hkResult);
1144 hkResult = NULL;
1145 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WOW64_64KEY, &hkResult);
1146 ok((ret == ERROR_SUCCESS && hkResult != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */),
1147 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%lu)\n", ret);
1148 RegCloseKey(hkResult);
1150 /* check special HKEYs on 64bit
1151 * only the lower 4 bytes of the supplied key are used
1153 if (ptr_size == 64)
1155 /* HKEY_CURRENT_USER */
1156 ret = RegOpenKeyA(UlongToHandle(HandleToUlong(HKEY_CURRENT_USER)), "Software", &hkResult);
1157 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1158 ok(hkResult != NULL, "expected hkResult != NULL\n");
1159 RegCloseKey(hkResult);
1161 ret = RegOpenKeyA((HKEY)(HandleToUlong(HKEY_CURRENT_USER) | (ULONG64)1 << 32), "Software", &hkResult);
1162 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1163 ok(hkResult != NULL, "expected hkResult != NULL\n");
1164 RegCloseKey(hkResult);
1166 ret = RegOpenKeyA((HKEY)(HandleToUlong(HKEY_CURRENT_USER) | (ULONG64)0xdeadbeef << 32), "Software", &hkResult);
1167 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1168 ok(hkResult != NULL, "expected hkResult != NULL\n");
1169 RegCloseKey(hkResult);
1171 ret = RegOpenKeyA((HKEY)(HandleToUlong(HKEY_CURRENT_USER) | (ULONG64)0xffffffff << 32), "Software", &hkResult);
1172 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1173 ok(hkResult != NULL, "expected hkResult != NULL\n");
1174 RegCloseKey(hkResult);
1176 /* HKEY_LOCAL_MACHINE */
1177 ret = RegOpenKeyA((HKEY)(HandleToUlong(HKEY_LOCAL_MACHINE) | (ULONG64)0xdeadbeef << 32), "Software", &hkResult);
1178 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1179 ok(hkResult != NULL, "expected hkResult != NULL\n");
1180 RegCloseKey(hkResult);
1183 /* Try using WOW64 flags when opening a key with a DACL set to verify that
1184 * the registry access check is performed correctly. Redirection isn't
1185 * being tested, so the tests don't care about whether the process is
1186 * running under WOW64. */
1187 if (!pIsWow64Process)
1189 win_skip("WOW64 flags are not recognized\n");
1190 return;
1193 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1194 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &hkRoot32, NULL);
1195 if (limited_user)
1196 ok(ret == ERROR_ACCESS_DENIED && hkRoot32 == NULL,
1197 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%lu)\n", ret);
1198 else
1199 ok(ret == ERROR_SUCCESS && hkRoot32 != NULL,
1200 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%lu)\n", ret);
1202 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1203 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &hkRoot64, NULL);
1204 if (limited_user)
1205 ok(ret == ERROR_ACCESS_DENIED && hkRoot64 == NULL,
1206 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%lu)\n", ret);
1207 else
1208 ok(ret == ERROR_SUCCESS && hkRoot64 != NULL,
1209 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%lu)\n", ret);
1211 bRet = AllocateAndInitializeSid(&sid_authority, 1, SECURITY_WORLD_RID,
1212 0, 0, 0, 0, 0, 0, 0, &world_sid);
1213 ok(bRet == TRUE,
1214 "Expected AllocateAndInitializeSid to return TRUE, got %d, last error %lu\n", bRet, GetLastError());
1216 access.grfAccessPermissions = GENERIC_ALL | STANDARD_RIGHTS_ALL;
1217 access.grfAccessMode = SET_ACCESS;
1218 access.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
1219 access.Trustee.pMultipleTrustee = NULL;
1220 access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1221 access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
1222 access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
1223 access.Trustee.ptstrName = (char *)world_sid;
1225 ret = SetEntriesInAclA(1, &access, NULL, &key_acl);
1226 ok(ret == ERROR_SUCCESS,
1227 "Expected SetEntriesInAclA to return ERROR_SUCCESS, got %lu, last error %lu\n", ret, GetLastError());
1229 sd = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
1230 bRet = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
1231 ok(bRet == TRUE,
1232 "Expected InitializeSecurityDescriptor to return TRUE, got %d, last error %lu\n", bRet, GetLastError());
1234 bRet = SetSecurityDescriptorDacl(sd, TRUE, key_acl, FALSE);
1235 ok(bRet == TRUE,
1236 "Expected SetSecurityDescriptorDacl to return TRUE, got %d, last error %lu\n", bRet, GetLastError());
1238 if (limited_user)
1240 skip("not enough privileges to modify HKLM\n");
1242 else
1244 LONG error;
1246 error = RegSetKeySecurity(hkRoot64, DACL_SECURITY_INFORMATION, sd);
1247 ok(error == ERROR_SUCCESS,
1248 "Expected RegSetKeySecurity to return success, got error %lu\n", error);
1250 error = RegSetKeySecurity(hkRoot32, DACL_SECURITY_INFORMATION, sd);
1251 ok(error == ERROR_SUCCESS,
1252 "Expected RegSetKeySecurity to return success, got error %lu\n", error);
1254 hkResult = NULL;
1255 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_WOW64_64KEY | KEY_READ, &hkResult);
1256 ok(ret == ERROR_SUCCESS && hkResult != NULL,
1257 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%lu)\n", ret);
1258 RegCloseKey(hkResult);
1260 hkResult = NULL;
1261 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_WOW64_32KEY | KEY_READ, &hkResult);
1262 ok(ret == ERROR_SUCCESS && hkResult != NULL,
1263 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%lu)\n", ret);
1264 RegCloseKey(hkResult);
1267 HeapFree(GetProcessHeap(), 0, sd);
1268 LocalFree(key_acl);
1269 FreeSid(world_sid);
1270 RegDeleteKeyA(hkRoot64, "");
1271 RegCloseKey(hkRoot64);
1272 RegDeleteKeyA(hkRoot32, "");
1273 RegCloseKey(hkRoot32);
1276 static void test_reg_create_key(void)
1278 LONG ret;
1279 HKEY hkey1, hkey2;
1280 HKEY hkRoot64 = NULL;
1281 HKEY hkRoot32 = NULL;
1282 DWORD dwRet;
1283 BOOL bRet;
1284 SID_IDENTIFIER_AUTHORITY sid_authority = {SECURITY_WORLD_SID_AUTHORITY};
1285 PSID world_sid;
1286 EXPLICIT_ACCESSA access;
1287 PACL key_acl;
1288 SECURITY_DESCRIPTOR *sd;
1290 ret = RegCreateKeyExA(hkey_main, "Subkey1", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
1291 ok(!ret, "RegCreateKeyExA failed with error %ld\n", ret);
1292 /* should succeed: all versions of Windows ignore the access rights
1293 * to the parent handle */
1294 ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey2, NULL);
1295 ok(!ret, "RegCreateKeyExA failed with error %ld\n", ret);
1297 /* clean up */
1298 RegDeleteKeyA(hkey2, "");
1299 RegDeleteKeyA(hkey1, "");
1300 RegCloseKey(hkey2);
1301 RegCloseKey(hkey1);
1303 /* test creation of volatile keys */
1304 ret = RegCreateKeyExA(hkey_main, "Volatile", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey1, NULL);
1305 ok(!ret, "RegCreateKeyExA failed with error %ld\n", ret);
1306 ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey2, NULL);
1307 ok(ret == ERROR_CHILD_MUST_BE_VOLATILE, "RegCreateKeyExA failed with error %ld\n", ret);
1308 if (!ret) RegCloseKey( hkey2 );
1309 ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey2, NULL);
1310 ok(!ret, "RegCreateKeyExA failed with error %ld\n", ret);
1311 RegCloseKey(hkey2);
1312 /* should succeed if the key already exists */
1313 ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey2, NULL);
1314 ok(!ret, "RegCreateKeyExA failed with error %ld\n", ret);
1316 /* clean up */
1317 RegDeleteKeyA(hkey2, "");
1318 RegDeleteKeyA(hkey1, "");
1319 RegCloseKey(hkey2);
1320 RegCloseKey(hkey1);
1322 /* beginning backslash character */
1323 ret = RegCreateKeyExA(hkey_main, "\\Subkey3", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
1324 ok(ret == ERROR_BAD_PATHNAME, "expected ERROR_BAD_PATHNAME, got %ld\n", ret);
1326 /* trailing backslash characters */
1327 ret = RegCreateKeyExA(hkey_main, "Subkey4\\\\", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
1328 ok(ret == ERROR_SUCCESS, "RegCreateKeyExA failed with error %ld\n", ret);
1329 RegDeleteKeyA(hkey1, "");
1330 RegCloseKey(hkey1);
1332 /* WOW64 flags - open an existing key */
1333 hkey1 = NULL;
1334 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0, KEY_READ|KEY_WOW64_32KEY, NULL, &hkey1, NULL);
1335 ok(ret == ERROR_SUCCESS && hkey1 != NULL,
1336 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%lu)\n", ret);
1337 RegCloseKey(hkey1);
1339 hkey1 = NULL;
1340 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0, KEY_READ|KEY_WOW64_64KEY, NULL, &hkey1, NULL);
1341 ok(ret == ERROR_SUCCESS && hkey1 != NULL,
1342 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%lu)\n", ret);
1343 RegCloseKey(hkey1);
1345 /* Try using WOW64 flags when opening a key with a DACL set to verify that
1346 * the registry access check is performed correctly. Redirection isn't
1347 * being tested, so the tests don't care about whether the process is
1348 * running under WOW64. */
1349 if (!pIsWow64Process)
1351 win_skip("WOW64 flags are not recognized\n");
1352 return;
1355 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1356 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &hkRoot32, NULL);
1357 if (limited_user)
1358 ok(ret == ERROR_ACCESS_DENIED && hkRoot32 == NULL,
1359 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%ld)\n", ret);
1360 else
1361 ok(ret == ERROR_SUCCESS && hkRoot32 != NULL,
1362 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%ld)\n", ret);
1364 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1365 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &hkRoot64, NULL);
1366 if (limited_user)
1367 ok(ret == ERROR_ACCESS_DENIED && hkRoot64 == NULL,
1368 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%ld)\n", ret);
1369 else
1370 ok(ret == ERROR_SUCCESS && hkRoot64 != NULL,
1371 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%ld)\n", ret);
1373 bRet = AllocateAndInitializeSid(&sid_authority, 1, SECURITY_WORLD_RID,
1374 0, 0, 0, 0, 0, 0, 0, &world_sid);
1375 ok(bRet == TRUE,
1376 "Expected AllocateAndInitializeSid to return TRUE, got %d, last error %lu\n", bRet, GetLastError());
1378 access.grfAccessPermissions = GENERIC_ALL | STANDARD_RIGHTS_ALL;
1379 access.grfAccessMode = SET_ACCESS;
1380 access.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
1381 access.Trustee.pMultipleTrustee = NULL;
1382 access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1383 access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
1384 access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
1385 access.Trustee.ptstrName = (char *)world_sid;
1387 dwRet = SetEntriesInAclA(1, &access, NULL, &key_acl);
1388 ok(dwRet == ERROR_SUCCESS,
1389 "Expected SetEntriesInAclA to return ERROR_SUCCESS, got %lu, last error %lu\n", dwRet, GetLastError());
1391 sd = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
1392 bRet = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
1393 ok(bRet == TRUE,
1394 "Expected InitializeSecurityDescriptor to return TRUE, got %d, last error %lu\n", bRet, GetLastError());
1396 bRet = SetSecurityDescriptorDacl(sd, TRUE, key_acl, FALSE);
1397 ok(bRet == TRUE,
1398 "Expected SetSecurityDescriptorDacl to return TRUE, got %d, last error %lu\n", bRet, GetLastError());
1400 if (limited_user)
1402 skip("not enough privileges to modify HKLM\n");
1404 else
1406 ret = RegSetKeySecurity(hkRoot64, DACL_SECURITY_INFORMATION, sd);
1407 ok(ret == ERROR_SUCCESS,
1408 "Expected RegSetKeySecurity to return success, got error %lu\n", ret);
1410 ret = RegSetKeySecurity(hkRoot32, DACL_SECURITY_INFORMATION, sd);
1411 ok(ret == ERROR_SUCCESS,
1412 "Expected RegSetKeySecurity to return success, got error %lu\n", ret);
1414 hkey1 = NULL;
1415 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1416 KEY_WOW64_64KEY | KEY_READ, NULL, &hkey1, NULL);
1417 ok(ret == ERROR_SUCCESS && hkey1 != NULL,
1418 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%lu)\n", ret);
1419 RegCloseKey(hkey1);
1421 hkey1 = NULL;
1422 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1423 KEY_WOW64_32KEY | KEY_READ, NULL, &hkey1, NULL);
1424 ok(ret == ERROR_SUCCESS && hkey1 != NULL,
1425 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%lu)\n", ret);
1426 RegCloseKey(hkey1);
1429 HeapFree(GetProcessHeap(), 0, sd);
1430 LocalFree(key_acl);
1431 FreeSid(world_sid);
1432 RegDeleteKeyA(hkRoot64, "");
1433 RegCloseKey(hkRoot64);
1434 RegDeleteKeyA(hkRoot32, "");
1435 RegCloseKey(hkRoot32);
1438 static void test_reg_close_key(void)
1440 DWORD ret = 0;
1441 HKEY hkHandle;
1443 /* successfully close key
1444 * hkHandle remains changed after call to RegCloseKey
1446 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkHandle);
1447 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1448 ret = RegCloseKey(hkHandle);
1449 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1451 /* try to close the key twice */
1452 ret = RegCloseKey(hkHandle); /* Windows 95 doesn't mind. */
1453 ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_SUCCESS,
1454 "expected ERROR_INVALID_HANDLE or ERROR_SUCCESS, got %ld\n", ret);
1456 /* try to close a NULL handle */
1457 ret = RegCloseKey(NULL);
1458 ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 95 returns BADKEY */
1459 "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %ld\n", ret);
1461 /* Check to see if we didn't potentially close our main handle, which could happen on win98 as
1462 * win98 doesn't give a new handle when the same key is opened.
1463 * Not re-opening will make some next tests fail.
1465 if (hkey_main == hkHandle)
1467 trace("The main handle is most likely closed, so re-opening\n");
1468 RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main );
1472 static void test_reg_delete_key(void)
1474 DWORD ret;
1475 HKEY key;
1477 ret = RegDeleteKeyA(hkey_main, NULL);
1479 /* There is a bug in NT4 and W2K that doesn't check if the subkey is NULL. If
1480 * there are also no subkeys available it will delete the key pointed to by hkey_main.
1481 * Not re-creating will make some next tests fail.
1483 if (ret == ERROR_SUCCESS)
1485 trace("We are probably running on NT4 or W2K as the main key is deleted,"
1486 " re-creating the main key\n");
1487 setup_main_key();
1489 else
1490 ok(ret == ERROR_INVALID_PARAMETER ||
1491 ret == ERROR_ACCESS_DENIED ||
1492 ret == ERROR_BADKEY, /* Win95 */
1493 "ret=%ld\n", ret);
1495 ret = RegCreateKeyA(hkey_main, "deleteme", &key);
1496 ok(ret == ERROR_SUCCESS, "Could not create key, got %ld\n", ret);
1497 ret = RegDeleteKeyA(key, "");
1498 ok(ret == ERROR_SUCCESS, "RegDeleteKeyA failed, got %ld\n", ret);
1499 RegCloseKey(key);
1500 ret = RegOpenKeyA(hkey_main, "deleteme", &key);
1501 ok(ret == ERROR_FILE_NOT_FOUND, "Key was not deleted, got %ld\n", ret);
1502 RegCloseKey(key);
1504 /* Test deleting 32-bit keys */
1505 ret = RegCreateKeyExA(hkey_main, "deleteme", 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, NULL, &key, NULL);
1506 ok(ret == ERROR_SUCCESS, "Could not create key, got %ld\n", ret);
1507 RegCloseKey(key);
1509 ret = RegOpenKeyExA(hkey_main, "deleteme", 0, KEY_READ | KEY_WOW64_32KEY, &key);
1510 ok(ret == ERROR_SUCCESS, "Could not open key, got %ld\n", ret);
1512 ret = RegDeleteKeyExA(key, "", KEY_WOW64_32KEY, 0);
1513 ok(ret == ERROR_SUCCESS, "RegDeleteKeyExA failed, got %ld\n", ret);
1514 RegCloseKey(key);
1516 ret = RegOpenKeyExA(hkey_main, "deleteme", 0, KEY_READ | KEY_WOW64_32KEY, &key);
1517 ok(ret == ERROR_FILE_NOT_FOUND, "Key was not deleted, got %ld\n", ret);
1518 RegCloseKey(key);
1521 static BOOL set_privileges(LPCSTR privilege, BOOL set)
1523 TOKEN_PRIVILEGES tp;
1524 HANDLE hToken;
1525 LUID luid;
1527 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
1528 return FALSE;
1530 if(!LookupPrivilegeValueA(NULL, privilege, &luid))
1532 CloseHandle(hToken);
1533 return FALSE;
1536 tp.PrivilegeCount = 1;
1537 tp.Privileges[0].Luid = luid;
1539 if (set)
1540 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1541 else
1542 tp.Privileges[0].Attributes = 0;
1544 AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
1545 if (GetLastError() != ERROR_SUCCESS)
1547 CloseHandle(hToken);
1548 return FALSE;
1551 CloseHandle(hToken);
1552 return TRUE;
1555 static void test_reg_save_key(void)
1557 DWORD ret;
1559 if (!set_privileges(SE_BACKUP_NAME, TRUE) ||
1560 !set_privileges(SE_RESTORE_NAME, FALSE))
1562 win_skip("Failed to set SE_BACKUP_NAME privileges, skipping tests\n");
1563 return;
1566 ret = RegSaveKeyA(hkey_main, "saved_key", NULL);
1567 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1569 set_privileges(SE_BACKUP_NAME, FALSE);
1572 static void test_reg_load_key(void)
1574 DWORD ret;
1575 HKEY hkHandle;
1577 if (!set_privileges(SE_RESTORE_NAME, TRUE) ||
1578 !set_privileges(SE_BACKUP_NAME, FALSE))
1580 win_skip("Failed to set SE_RESTORE_NAME privileges, skipping tests\n");
1581 return;
1584 ret = RegLoadKeyA(HKEY_LOCAL_MACHINE, "Test", "saved_key");
1585 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1587 set_privileges(SE_RESTORE_NAME, FALSE);
1589 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, "Test", &hkHandle);
1590 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1592 RegCloseKey(hkHandle);
1595 static void test_reg_unload_key(void)
1597 UNICODE_STRING key_name;
1598 OBJECT_ATTRIBUTES attr;
1599 NTSTATUS status;
1600 DWORD ret;
1601 HKEY key;
1603 if (!set_privileges(SE_RESTORE_NAME, TRUE) ||
1604 !set_privileges(SE_BACKUP_NAME, FALSE))
1606 win_skip("Failed to set SE_RESTORE_NAME privileges, skipping tests\n");
1607 return;
1610 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Test", 0, KEY_READ, &key);
1611 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1613 /* try to unload though the key handle is live */
1614 pRtlInitUnicodeString(&key_name, L"\\REGISTRY\\Machine\\Test");
1615 InitializeObjectAttributes(&attr, &key_name, OBJ_CASE_INSENSITIVE, NULL, NULL);
1616 status = pNtUnloadKey(&attr);
1617 ok(status == STATUS_CANNOT_DELETE, "expected STATUS_CANNOT_DELETE, got %08lx\n", status);
1619 RegCloseKey(key);
1621 ret = RegUnLoadKeyA(HKEY_LOCAL_MACHINE, "Test");
1622 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1624 set_privileges(SE_RESTORE_NAME, FALSE);
1626 DeleteFileA("saved_key");
1627 DeleteFileA("saved_key.LOG");
1630 /* Helper function to wait for a file blocked by the registry to be available */
1631 static void wait_file_available(char *path)
1633 int attempts = 0;
1634 HANDLE file = NULL;
1636 while (((file = CreateFileA(path, GENERIC_READ, 0, NULL,
1637 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
1638 && attempts++ < 10)
1640 Sleep(200);
1642 ok(file != INVALID_HANDLE_VALUE, "couldn't open file %s after 10 attempts error %ld.\n", path, GetLastError());
1643 CloseHandle(file);
1646 static void test_reg_load_app_key(void)
1648 DWORD ret, size;
1649 char temppath[MAX_PATH], hivefilepath[MAX_PATH];
1650 const BYTE test_data[] = "Hello World";
1651 BYTE output[sizeof(test_data)];
1652 HKEY appkey = NULL;
1654 GetTempPathA(sizeof(temppath), temppath);
1655 GetTempFileNameA(temppath, "key", 0, hivefilepath);
1656 DeleteFileA(hivefilepath);
1658 if (!set_privileges(SE_BACKUP_NAME, TRUE) ||
1659 !set_privileges(SE_RESTORE_NAME, FALSE))
1661 win_skip("Failed to set SE_BACKUP_NAME privileges, skipping tests\n");
1662 return;
1665 ret = RegSaveKeyA(hkey_main, hivefilepath, NULL);
1666 if (ret != ERROR_SUCCESS)
1668 win_skip("Failed to save test key 0x%lx\n", ret);
1669 return;
1672 set_privileges(SE_BACKUP_NAME, FALSE);
1673 set_privileges(SE_RESTORE_NAME, FALSE);
1675 /* Test simple key load */
1676 /* Check if the changes are saved */
1677 ret = RegLoadAppKeyA(hivefilepath, &appkey, KEY_READ | KEY_WRITE, 0, 0);
1678 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1679 ok(appkey != NULL, "got a null key\n");
1681 ret = RegSetValueExA(appkey, "testkey", 0, REG_BINARY, test_data, sizeof(test_data));
1682 todo_wine ok(ret == ERROR_SUCCESS, "couldn't set key value %lx\n", ret);
1683 RegCloseKey(appkey);
1685 wait_file_available(hivefilepath);
1687 appkey = NULL;
1688 ret = RegLoadAppKeyA(hivefilepath, &appkey, KEY_READ, 0, 0);
1689 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1690 ok(appkey != NULL, "got a null key\n");
1692 size = sizeof(test_data);
1693 memset(output, 0xff, sizeof(output));
1694 ret = RegGetValueA(appkey, NULL, "testkey", RRF_RT_REG_BINARY, NULL, output, &size);
1695 todo_wine ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
1696 ok(size == sizeof(test_data), "size doesn't match %ld != %ld\n", size, (DWORD)sizeof(test_data));
1697 todo_wine ok(!memcmp(test_data, output, sizeof(test_data)), "output is not what expected\n");
1699 RegCloseKey(appkey);
1701 wait_file_available(hivefilepath);
1702 ret = DeleteFileA(hivefilepath);
1703 ok(ret, "couldn't delete hive file %ld\n", GetLastError());
1706 /* tests that show that RegConnectRegistry and
1707 OpenSCManager accept computer names without the
1708 \\ prefix (what MSDN says). */
1709 static void test_regconnectregistry( void)
1711 CHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
1712 CHAR netwName[MAX_COMPUTERNAME_LENGTH + 3]; /* 2 chars for double backslash */
1713 DWORD len = sizeof(compName) ;
1714 BOOL ret;
1715 LONG retl;
1716 HKEY hkey;
1717 SC_HANDLE schnd;
1719 SetLastError(0xdeadbeef);
1720 ret = GetComputerNameA(compName, &len);
1721 ok( ret, "GetComputerName failed err = %ld\n", GetLastError());
1722 if( !ret) return;
1724 lstrcpyA(netwName, "\\\\");
1725 lstrcpynA(netwName+2, compName, MAX_COMPUTERNAME_LENGTH + 1);
1727 retl = RegConnectRegistryA( compName, HKEY_LOCAL_MACHINE, &hkey);
1728 ok( !retl ||
1729 retl == ERROR_DLL_INIT_FAILED ||
1730 retl == ERROR_BAD_NETPATH, /* some win2k */
1731 "RegConnectRegistryA failed err = %ld\n", retl);
1732 if( !retl) RegCloseKey( hkey);
1734 retl = RegConnectRegistryA( netwName, HKEY_LOCAL_MACHINE, &hkey);
1735 ok( !retl ||
1736 retl == ERROR_DLL_INIT_FAILED ||
1737 retl == ERROR_BAD_NETPATH, /* some win2k */
1738 "RegConnectRegistryA failed err = %ld\n", retl);
1739 if( !retl) RegCloseKey( hkey);
1741 SetLastError(0xdeadbeef);
1742 schnd = OpenSCManagerA( compName, NULL, GENERIC_READ);
1743 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1745 win_skip("OpenSCManagerA is not implemented\n");
1746 return;
1749 ok( schnd != NULL, "OpenSCManagerA failed err = %ld\n", GetLastError());
1750 CloseServiceHandle( schnd);
1752 SetLastError(0xdeadbeef);
1753 schnd = OpenSCManagerA( netwName, NULL, GENERIC_READ);
1754 ok( schnd != NULL, "OpenSCManagerA failed err = %ld\n", GetLastError());
1755 CloseServiceHandle( schnd);
1759 static void test_reg_query_value(void)
1761 HKEY subkey;
1762 CHAR val[MAX_PATH];
1763 WCHAR valW[5];
1764 LONG size, ret;
1766 ret = RegCreateKeyA(hkey_main, "subkey", &subkey);
1767 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1769 ret = RegSetValueA(subkey, NULL, REG_SZ, "data", 4);
1770 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1772 /* try an invalid hkey */
1773 SetLastError(0xdeadbeef);
1774 size = MAX_PATH;
1775 ret = RegQueryValueA((HKEY)0xcafebabe, "subkey", val, &size);
1776 ok(ret == ERROR_INVALID_HANDLE ||
1777 ret == ERROR_BADKEY || /* Windows 98 returns BADKEY */
1778 ret == ERROR_ACCESS_DENIED, /* non-admin winxp */
1779 "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %ld\n", ret);
1780 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1782 /* try a NULL hkey */
1783 SetLastError(0xdeadbeef);
1784 size = MAX_PATH;
1785 ret = RegQueryValueA(NULL, "subkey", val, &size);
1786 ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 98 returns BADKEY */
1787 "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %ld\n", ret);
1788 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1790 /* try a NULL value */
1791 size = MAX_PATH;
1792 ret = RegQueryValueA(hkey_main, "subkey", NULL, &size);
1793 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1794 ok(size == 5, "Expected 5, got %ld\n", size);
1796 /* try a NULL size */
1797 SetLastError(0xdeadbeef);
1798 val[0] = '\0';
1799 ret = RegQueryValueA(hkey_main, "subkey", val, NULL);
1800 ok(ret == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %ld\n", ret);
1801 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1802 ok(!val[0], "Expected val to be untouched, got %s\n", val);
1804 /* try a NULL value and size */
1805 ret = RegQueryValueA(hkey_main, "subkey", NULL, NULL);
1806 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1808 /* try a size too small */
1809 SetLastError(0xdeadbeef);
1810 val[0] = '\0';
1811 size = 1;
1812 ret = RegQueryValueA(hkey_main, "subkey", val, &size);
1813 ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %ld\n", ret);
1814 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1815 ok(!val[0], "Expected val to be untouched, got %s\n", val);
1816 ok(size == 5, "Expected 5, got %ld\n", size);
1818 /* successfully read the value using 'subkey' */
1819 size = MAX_PATH;
1820 ret = RegQueryValueA(hkey_main, "subkey", val, &size);
1821 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1822 ok(!lstrcmpA(val, "data"), "Expected 'data', got '%s'\n", val);
1823 ok(size == 5, "Expected 5, got %ld\n", size);
1825 /* successfully read the value using the subkey key */
1826 size = MAX_PATH;
1827 ret = RegQueryValueA(subkey, NULL, val, &size);
1828 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1829 ok(!lstrcmpA(val, "data"), "Expected 'data', got '%s'\n", val);
1830 ok(size == 5, "Expected 5, got %ld\n", size);
1832 /* unicode - try size too small */
1833 SetLastError(0xdeadbeef);
1834 valW[0] = '\0';
1835 size = 0;
1836 ret = RegQueryValueW(subkey, NULL, valW, &size);
1837 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1839 win_skip("RegQueryValueW is not implemented\n");
1840 goto cleanup;
1842 ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %ld\n", ret);
1843 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1844 ok(!valW[0], "Expected valW to be untouched\n");
1845 ok(size == 10, "Got wrong size: %ld\n", size);
1847 /* unicode - try size in WCHARS */
1848 SetLastError(0xdeadbeef);
1849 size = ARRAY_SIZE(valW);
1850 ret = RegQueryValueW(subkey, NULL, valW, &size);
1851 ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %ld\n", ret);
1852 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1853 ok(!valW[0], "Expected valW to be untouched\n");
1854 ok(size == 10, "Got wrong size: %ld\n", size);
1856 /* unicode - successfully read the value */
1857 size = sizeof(valW);
1858 ret = RegQueryValueW(subkey, NULL, valW, &size);
1859 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1860 ok(!lstrcmpW(valW, L"data"), "Got wrong value\n");
1861 ok(size == 10, "Got wrong size: %ld\n", size);
1863 /* unicode - set the value without a NULL terminator */
1864 ret = RegSetValueW(subkey, NULL, REG_SZ, L"data", 8);
1865 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1867 /* unicode - read the unterminated value, value is terminated for us */
1868 memset(valW, 'a', sizeof(valW));
1869 size = sizeof(valW);
1870 ret = RegQueryValueW(subkey, NULL, valW, &size);
1871 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1872 ok(!lstrcmpW(valW, L"data"), "Got wrong value\n");
1873 ok(size == 10, "Got wrong size: %ld\n", size);
1875 cleanup:
1876 RegDeleteKeyA(subkey, "");
1877 RegCloseKey(subkey);
1880 static void test_reg_query_info(void)
1882 HKEY subkey;
1883 HKEY subsubkey;
1884 LONG ret;
1885 char classbuffer[32];
1886 WCHAR classbufferW[32];
1887 char expectbuffer[32];
1888 WCHAR expectbufferW[32];
1889 char subkey_class[] = "subkey class";
1890 WCHAR subkey_classW[] = L"subkey class";
1891 char subsubkey_class[] = "subsubkey class";
1892 DWORD classlen;
1893 DWORD subkeys, maxsubkeylen, maxclasslen;
1894 DWORD values, maxvaluenamelen, maxvaluelen;
1895 DWORD sdlen;
1896 FILETIME lastwrite;
1898 ret = RegCreateKeyExA(hkey_main, "subkey", 0, subkey_class, 0, KEY_ALL_ACCESS, NULL, &subkey, NULL);
1899 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1901 /* all parameters NULL */
1902 ret = RegQueryInfoKeyA(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1903 ok(ret == ERROR_INVALID_HANDLE, "ret = %ld\n", ret);
1905 ret = RegQueryInfoKeyW(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1906 ok(ret == ERROR_INVALID_HANDLE, "ret = %ld\n", ret);
1908 /* not requesting any information */
1909 ret = RegQueryInfoKeyA(subkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1910 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
1912 ret = RegQueryInfoKeyW(subkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1913 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
1915 /* class without length is invalid */
1916 memset(classbuffer, 0x55, sizeof(classbuffer));
1917 ret = RegQueryInfoKeyA(subkey, classbuffer, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1918 ok(ret == ERROR_INVALID_PARAMETER, "ret = %ld\n", ret);
1919 ok(classbuffer[0] == 0x55, "classbuffer[0] = 0x%x\n", classbuffer[0]);
1921 memset(classbufferW, 0x55, sizeof(classbufferW));
1922 ret = RegQueryInfoKeyW(subkey, classbufferW, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1923 ok(ret == ERROR_INVALID_PARAMETER, "ret = %ld\n", ret);
1924 ok(classbufferW[0] == 0x5555, "classbufferW[0] = 0x%x\n", classbufferW[0]);
1926 /* empty key */
1927 sdlen = classlen =0;
1928 ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1929 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
1930 ok(classlen == strlen(subkey_class), "classlen = %lu\n", classlen);
1931 ok(subkeys == 0, "subkeys = %lu\n", subkeys);
1932 ok(maxsubkeylen == 0, "maxsubkeylen = %lu\n", maxsubkeylen);
1933 ok(maxclasslen == 0, "maxclasslen = %lu\n", maxclasslen);
1934 ok(values == 0, "values = %lu\n", values);
1935 ok(maxvaluenamelen == 0, "maxvaluenamelen = %lu\n", maxvaluenamelen);
1936 ok(maxvaluelen == 0, "maxvaluelen = %lu\n", maxvaluelen);
1937 todo_wine ok(sdlen != 0, "sdlen = %lu\n", sdlen);
1938 ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %lu\n", lastwrite.dwLowDateTime);
1939 ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %lu\n", lastwrite.dwHighDateTime);
1941 sdlen = classlen = 0;
1942 ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1943 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
1944 ok(classlen == strlen(subkey_class), "classlen = %lu\n", classlen);
1945 ok(subkeys == 0, "subkeys = %lu\n", subkeys);
1946 ok(maxsubkeylen == 0, "maxsubkeylen = %lu\n", maxsubkeylen);
1947 ok(maxclasslen == 0, "maxclasslen = %lu\n", maxclasslen);
1948 ok(values == 0, "values = %lu\n", values);
1949 ok(maxvaluenamelen == 0, "maxvaluenamelen = %lu\n", maxvaluenamelen);
1950 ok(maxvaluelen == 0, "maxvaluelen = %lu\n", maxvaluelen);
1951 todo_wine ok(sdlen != 0, "sdlen = %lu\n", sdlen);
1952 ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %lu\n", lastwrite.dwLowDateTime);
1953 ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %lu\n", lastwrite.dwHighDateTime);
1955 ret = RegCreateKeyExA(subkey, "subsubkey", 0, subsubkey_class, 0, KEY_ALL_ACCESS, NULL, &subsubkey, NULL);
1956 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1958 ret = RegSetValueExA(subkey, NULL, 0, REG_SZ, (const BYTE*)"data", 5);
1959 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1961 /* with subkey & default value */
1962 sdlen = classlen = 0;
1963 ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1964 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
1965 ok(classlen == strlen(subkey_class), "classlen = %lu\n", classlen);
1966 ok(subkeys == 1, "subkeys = %lu\n", subkeys);
1967 ok(maxsubkeylen == strlen("subsubkey"), "maxsubkeylen = %lu\n", maxsubkeylen);
1968 ok(maxclasslen == strlen(subsubkey_class), "maxclasslen = %lu\n", maxclasslen);
1969 ok(values == 1, "values = %lu\n", values);
1970 ok(maxvaluenamelen == 0, "maxvaluenamelen = %lu\n", maxvaluenamelen);
1971 ok(maxvaluelen == sizeof("data") * sizeof(WCHAR), "maxvaluelen = %lu\n", maxvaluelen);
1972 todo_wine ok(sdlen != 0, "sdlen = %lu\n", sdlen);
1973 ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %lu\n", lastwrite.dwLowDateTime);
1974 ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %lu\n", lastwrite.dwHighDateTime);
1976 sdlen = classlen = 0;
1977 ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1978 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
1979 ok(classlen == strlen(subkey_class), "classlen = %lu\n", classlen);
1980 ok(subkeys == 1, "subkeys = %lu\n", subkeys);
1981 ok(maxsubkeylen == strlen("subsubkey"), "maxsubkeylen = %lu\n", maxsubkeylen);
1982 ok(maxclasslen == strlen(subsubkey_class), "maxclasslen = %lu\n", maxclasslen);
1983 ok(values == 1, "values = %lu\n", values);
1984 ok(maxvaluenamelen == 0, "maxvaluenamelen = %lu\n", maxvaluenamelen);
1985 ok(maxvaluelen == sizeof("data") * sizeof(WCHAR), "maxvaluelen = %lu\n", maxvaluelen);
1986 todo_wine ok(sdlen != 0, "sdlen = %lu\n", sdlen);
1987 ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %lu\n", lastwrite.dwLowDateTime);
1988 ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %lu\n", lastwrite.dwHighDateTime);
1990 ret = RegSetValueExA(subkey, "value one", 0, REG_SZ, (const BYTE*)"first value data", 17);
1991 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1993 ret = RegSetValueExA(subkey, "value 2", 0, REG_SZ, (const BYTE*)"second value data", 18);
1994 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
1996 /* with named value */
1997 classlen = 0;
1998 ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1999 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
2000 ok(values == 3, "values = %lu\n", values);
2001 ok(maxvaluenamelen == strlen("value one"), "maxvaluenamelen = %lu\n", maxvaluenamelen);
2002 ok(maxvaluelen == sizeof("second value data") * sizeof(WCHAR), "maxvaluelen = %lu\n", maxvaluelen);
2004 classlen = 0;
2005 ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
2006 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
2007 ok(values == 3, "values = %lu\n", values);
2008 ok(maxvaluenamelen == strlen("value one"), "maxvaluenamelen = %lu\n", maxvaluenamelen);
2009 ok(maxvaluelen == sizeof("second value data") * sizeof(WCHAR), "maxvaluelen = %lu\n", maxvaluelen);
2011 /* class name with zero size buffer */
2012 memset(classbuffer, 0x55, sizeof(classbuffer));
2013 classlen = 0;
2014 ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2015 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
2016 ok(classlen == strlen(subkey_class) /* win2k */ ||
2017 classlen == 0, "classlen = %lu\n", classlen);
2018 memset(expectbuffer, 0x55, sizeof(expectbuffer));
2019 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)), "classbuffer was modified\n");
2021 memset(classbufferW, 0x55, sizeof(classbufferW));
2022 classlen = 0;
2023 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2024 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
2025 ok(classlen == strlen(subkey_class) /* win2k */ ||
2026 classlen == 0, "classlen = %lu\n", classlen);
2027 memset(expectbufferW, 0x55, sizeof(expectbufferW));
2028 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)), "classbufferW was modified\n");
2030 /* class name with one char buffer */
2031 memset(classbuffer, 0x55, sizeof(classbuffer));
2032 classlen = 1;
2033 ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2034 ok(ret == ERROR_MORE_DATA, "ret = %ld\n", ret);
2035 ok(classlen == 0, "classlen = %lu\n", classlen);
2036 memset(expectbuffer, 0x55, sizeof(expectbuffer));
2037 expectbuffer[0] = 0;
2038 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)), "classbuffer was modified\n");
2040 memset(classbufferW, 0x55, sizeof(classbufferW));
2041 classlen = 1;
2042 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2043 /* failure-code changed to ERROR_MORE_DATA in recent win10 */
2044 ok((ret == ERROR_INSUFFICIENT_BUFFER) || (ret == ERROR_MORE_DATA), "ret = %ld\n", ret);
2045 ok(classlen == 0 /* win8 */ ||
2046 classlen == strlen(subkey_class), "classlen = %lu\n", classlen);
2047 memset(expectbufferW, 0x55, sizeof(expectbufferW));
2048 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)), "classbufferW was modified\n");
2050 /* class name with buffer one char too small */
2051 memset(classbuffer, 0x55, sizeof(classbuffer));
2052 classlen = sizeof(subkey_class) - 1;
2053 ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2054 ok(ret == ERROR_MORE_DATA, "ret = %ld\n", ret);
2055 ok(classlen == sizeof(subkey_class) - 2, "classlen = %lu\n", classlen);
2056 memset(expectbuffer, 0x55, sizeof(expectbuffer));
2057 strcpy(expectbuffer, subkey_class);
2058 expectbuffer[sizeof(subkey_class) - 2] = 0;
2059 expectbuffer[sizeof(subkey_class) - 1] = 0x55;
2060 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)),
2061 "classbuffer = %.*s, expected %s\n",
2062 (int)sizeof(classbuffer), classbuffer, expectbuffer);
2064 memset(classbufferW, 0x55, sizeof(classbufferW));
2065 classlen = sizeof(subkey_class) - 1;
2066 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2067 ok(ret == ERROR_INSUFFICIENT_BUFFER, "ret = %ld\n", ret);
2068 ok(classlen == sizeof(subkey_class) - 2 /* win8 */ ||
2069 classlen == strlen(subkey_class), "classlen = %lu\n", classlen);
2070 memset(expectbufferW, 0x55, sizeof(expectbufferW));
2071 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)), "classbufferW was modified\n");
2073 /* class name with large enough buffer */
2074 memset(classbuffer, 0x55, sizeof(classbuffer));
2075 classlen = sizeof(subkey_class);
2076 ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2077 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
2078 ok(classlen == sizeof(subkey_class) - 1, "classlen = %lu\n", classlen);
2079 memset(expectbuffer, 0x55, sizeof(expectbuffer));
2080 strcpy(expectbuffer, subkey_class);
2081 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)),
2082 "classbuffer = \"%.*s\", expected %s\n",
2083 (int)sizeof(classbuffer), classbuffer, expectbuffer);
2085 memset(classbuffer, 0x55, sizeof(classbuffer));
2086 classlen = 0xdeadbeef;
2087 ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2088 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
2089 ok(classlen == sizeof(subkey_class) - 1, "classlen = %lu\n", classlen);
2090 memset(expectbuffer, 0x55, sizeof(expectbuffer));
2091 strcpy(expectbuffer, subkey_class);
2092 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)),
2093 "classbuffer = \"%.*s\", expected %s\n",
2094 (int)sizeof(classbuffer), classbuffer, expectbuffer);
2096 memset(classbufferW, 0x55, sizeof(classbufferW));
2097 classlen = sizeof(subkey_class);
2098 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2099 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
2100 ok(classlen == sizeof(subkey_class) - 1, "classlen = %lu\n", classlen);
2101 memset(expectbufferW, 0x55, sizeof(expectbufferW));
2102 lstrcpyW(expectbufferW, subkey_classW);
2103 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)),
2104 "classbufferW = %s, expected %s\n",
2105 wine_dbgstr_wn(classbufferW, ARRAY_SIZE(classbufferW)), wine_dbgstr_w(expectbufferW));
2107 memset(classbufferW, 0x55, sizeof(classbufferW));
2108 classlen = 0xdeadbeef;
2109 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2110 ok(ret == ERROR_SUCCESS, "ret = %ld\n", ret);
2111 ok(classlen == sizeof(subkey_class) - 1, "classlen = %lu\n", classlen);
2112 memset(expectbufferW, 0x55, sizeof(expectbufferW));
2113 lstrcpyW(expectbufferW, subkey_classW);
2114 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)),
2115 "classbufferW = %s, expected %s\n",
2116 wine_dbgstr_wn(classbufferW, ARRAY_SIZE(classbufferW)), wine_dbgstr_w(expectbufferW));
2118 RegDeleteKeyA(subsubkey, "");
2119 RegCloseKey(subsubkey);
2120 RegDeleteKeyA(subkey, "");
2121 RegCloseKey(subkey);
2124 static void test_string_termination(void)
2126 HKEY subkey;
2127 LSTATUS ret;
2128 static const char string[] = "FullString";
2129 char name[11];
2130 BYTE buffer[11];
2131 DWORD insize, outsize, nsize;
2133 ret = RegCreateKeyA(hkey_main, "string_termination", &subkey);
2134 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2136 /* Off-by-one RegSetValueExA -> adds a trailing '\0'! */
2137 insize=sizeof(string)-1;
2138 ret = RegSetValueExA(subkey, "stringtest", 0, REG_SZ, (BYTE*)string, insize);
2139 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %ld\n", ret);
2140 outsize=insize;
2141 ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
2142 ok(ret == ERROR_MORE_DATA, "RegQueryValueExA returned: %ld\n", ret);
2144 /* Off-by-two RegSetValueExA -> no trailing '\0' */
2145 insize=sizeof(string)-2;
2146 ret = RegSetValueExA(subkey, "stringtest", 0, REG_SZ, (BYTE*)string, insize);
2147 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %ld\n", ret);
2148 outsize=0;
2149 ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, NULL, &outsize);
2150 ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", ret);
2151 ok(outsize == insize, "wrong size %lu != %lu\n", outsize, insize);
2153 /* RegQueryValueExA may return a string with no trailing '\0' */
2154 outsize=insize;
2155 memset(buffer, 0xbd, sizeof(buffer));
2156 ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
2157 ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", ret);
2158 ok(outsize == insize, "wrong size: %lu != %lu\n", outsize, insize);
2159 ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%lu != %s\n",
2160 debugstr_an((char*)buffer, outsize), outsize, string);
2161 ok(buffer[insize] == 0xbd, "buffer overflow at %lu %02x\n", insize, buffer[insize]);
2163 /* RegQueryValueExA adds a trailing '\0' if there is room */
2164 outsize=insize+1;
2165 memset(buffer, 0xbd, sizeof(buffer));
2166 ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
2167 ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", ret);
2168 ok(outsize == insize, "wrong size: %lu != %lu\n", outsize, insize);
2169 ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%lu != %s\n",
2170 debugstr_an((char*)buffer, outsize), outsize, string);
2171 ok(buffer[insize] == 0, "buffer overflow at %lu %02x\n", insize, buffer[insize]);
2173 /* RegEnumValueA may return a string with no trailing '\0' */
2174 outsize=insize;
2175 memset(buffer, 0xbd, sizeof(buffer));
2176 nsize=sizeof(name);
2177 ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize);
2178 ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %ld\n", ret);
2179 ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name);
2180 ok(outsize == insize, "wrong size: %lu != %lu\n", outsize, insize);
2181 ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%lu != %s\n",
2182 debugstr_an((char*)buffer, outsize), outsize, string);
2183 ok(buffer[insize] == 0xbd, "buffer overflow at %lu %02x\n", insize, buffer[insize]);
2185 /* RegEnumValueA adds a trailing '\0' if there is room */
2186 outsize=insize+1;
2187 memset(buffer, 0xbd, sizeof(buffer));
2188 nsize=sizeof(name);
2189 ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize);
2190 ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %ld\n", ret);
2191 ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name);
2192 ok(outsize == insize, "wrong size: %lu != %lu\n", outsize, insize);
2193 ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%lu != %s\n",
2194 debugstr_an((char*)buffer, outsize), outsize, string);
2195 ok(buffer[insize] == 0, "buffer overflow at %lu %02x\n", insize, buffer[insize]);
2197 RegDeleteKeyA(subkey, "");
2198 RegCloseKey(subkey);
2201 static void test_reg_copy_tree(void)
2203 HKEY src, dst, subkey;
2204 CHAR buffer[MAX_PATH];
2205 DWORD dwsize, type;
2206 LONG size, ret;
2208 if (!pRegCopyTreeA)
2210 win_skip("Skipping RegCopyTreeA tests, function not present\n");
2211 return;
2214 ret = RegCreateKeyA(hkey_main, "src", &src);
2215 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2216 ret = RegCreateKeyA(hkey_main, "dst", &dst);
2217 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2219 /* Copy nonexistent subkey */
2220 ret = pRegCopyTreeA(src, "nonexistent_subkey", dst);
2221 ok(ret == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", ret);
2223 /* Create test keys and values */
2224 ret = RegSetValueA(src, NULL, REG_SZ, "data", 4);
2225 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2226 ret = RegSetValueExA(src, "value", 0, REG_SZ, (const BYTE *)"data2", 5);
2227 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2229 ret = RegCreateKeyA(src, "subkey2", &subkey);
2230 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2231 ret = RegSetValueA(subkey, NULL, REG_SZ, "data3", 5);
2232 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2233 ret = RegSetValueExA(subkey, "value", 0, REG_SZ, (const BYTE *)"data4", 5);
2234 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2235 ret = RegCloseKey(subkey);
2236 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2238 ret = RegCreateKeyA(src, "subkey3", &subkey);
2239 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2240 ret = RegCloseKey(subkey);
2241 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2243 /* Copy subkey */
2244 ret = pRegCopyTreeA(src, "subkey2", dst);
2245 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2247 size = MAX_PATH;
2248 ret = RegQueryValueA(dst, NULL, buffer, &size);
2249 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2250 ok(!strcmp(buffer, "data3"), "Expected 'data3', got '%s'\n", buffer);
2252 dwsize = MAX_PATH;
2253 ret = RegQueryValueExA(dst, "value", NULL, &type, (BYTE *)buffer, &dwsize);
2254 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2255 ok(type == REG_SZ, "Expected REG_SZ, got %lu\n", type);
2256 ok(!strcmp(buffer, "data4"), "Expected 'data4', got '%s'\n", buffer);
2258 /* Copy full tree */
2259 ret = pRegCopyTreeA(src, NULL, dst);
2260 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2262 size = MAX_PATH;
2263 ret = RegQueryValueA(dst, NULL, buffer, &size);
2264 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2265 ok(!strcmp(buffer, "data"), "Expected 'data', got '%s'\n", buffer);
2267 dwsize = MAX_PATH;
2268 ret = RegQueryValueExA(dst, "value", NULL, &type, (BYTE *)buffer, &dwsize);
2269 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2270 ok(type == REG_SZ, "Expected REG_SZ, got %lu\n", type);
2271 ok(!strcmp(buffer, "data2"), "Expected 'data2', got '%s'\n", buffer);
2273 ret = RegOpenKeyA(dst, "subkey2", &subkey);
2274 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2275 size = MAX_PATH;
2276 ret = RegQueryValueA(subkey, NULL, buffer, &size);
2277 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2278 ok(!strcmp(buffer, "data3"), "Expected 'data3', got '%s'\n", buffer);
2279 dwsize = MAX_PATH;
2280 ret = RegQueryValueExA(subkey, "value", NULL, &type, (BYTE *)buffer, &dwsize);
2281 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2282 ok(type == REG_SZ, "Expected REG_SZ, got %lu\n", type);
2283 ok(!strcmp(buffer, "data4"), "Expected 'data4', got '%s'\n", buffer);
2284 ret = RegCloseKey(subkey);
2285 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2287 ret = RegOpenKeyA(dst, "subkey3", &subkey);
2288 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2289 ret = RegCloseKey(subkey);
2290 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2292 delete_key(src);
2293 delete_key(dst);
2296 static void test_reg_delete_tree(void)
2298 CHAR buffer[MAX_PATH];
2299 HKEY subkey, subkey2;
2300 DWORD dwsize, type;
2301 LONG size, ret;
2303 if(!pRegDeleteTreeA) {
2304 win_skip("Skipping RegDeleteTreeA tests, function not present\n");
2305 return;
2308 ret = RegCreateKeyA(hkey_main, "subkey", &subkey);
2309 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2310 ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
2311 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2312 ret = RegSetValueA(subkey, NULL, REG_SZ, "data", 4);
2313 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2314 ret = RegSetValueA(subkey2, NULL, REG_SZ, "data2", 5);
2315 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2316 ret = RegCloseKey(subkey2);
2317 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2319 ret = pRegDeleteTreeA(subkey, "subkey2");
2320 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2321 ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
2322 "subkey2 was not deleted\n");
2323 size = MAX_PATH;
2324 ok(!RegQueryValueA(subkey, NULL, buffer, &size),
2325 "Default value of subkey no longer present\n");
2327 ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
2328 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2329 ret = RegCloseKey(subkey2);
2330 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2331 ret = pRegDeleteTreeA(hkey_main, "subkey\\subkey2");
2332 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2333 ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
2334 "subkey2 was not deleted\n");
2335 ok(!RegQueryValueA(subkey, NULL, buffer, &size),
2336 "Default value of subkey no longer present\n");
2338 ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
2339 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2340 ret = RegCloseKey(subkey2);
2341 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2342 ret = RegCreateKeyA(subkey, "subkey3", &subkey2);
2343 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2344 ret = RegCloseKey(subkey2);
2345 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2346 ret = RegSetValueA(subkey, NULL, REG_SZ, "data", 4);
2347 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2348 ret = RegSetValueExA(subkey, "value", 0, REG_SZ, (const BYTE *)"data2", 5);
2349 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2350 ret = pRegDeleteTreeA(subkey, NULL);
2351 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2352 ok(!RegOpenKeyA(hkey_main, "subkey", &subkey),
2353 "subkey was deleted\n");
2354 ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
2355 "subkey2 was not deleted\n");
2356 ok(RegOpenKeyA(subkey, "subkey3", &subkey2),
2357 "subkey3 was not deleted\n");
2358 size = MAX_PATH;
2359 ret = RegQueryValueA(subkey, NULL, buffer, &size);
2360 ok(ret == ERROR_SUCCESS,
2361 "Default value of subkey is not present\n");
2362 ok(!buffer[0], "Expected length 0 got length %u(%s)\n", lstrlenA(buffer), buffer);
2363 dwsize = MAX_PATH;
2364 ok(RegQueryValueExA(subkey, "value", NULL, &type, (BYTE *)buffer, &dwsize),
2365 "Value is still present\n");
2366 ret = RegCloseKey(subkey);
2367 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2369 ret = RegOpenKeyA(hkey_main, "subkey", &subkey);
2370 ok(ret == ERROR_SUCCESS, "subkey was deleted\n");
2371 ret = pRegDeleteTreeA(subkey, "");
2372 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2373 ret = RegCloseKey(subkey);
2374 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2376 ret = RegOpenKeyA(hkey_main, "subkey", &subkey);
2377 ok(ret == ERROR_SUCCESS, "subkey was deleted\n");
2378 ret = RegCloseKey(subkey);
2379 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", ret);
2381 ret = pRegDeleteTreeA(hkey_main, "not-here");
2382 ok(ret == ERROR_FILE_NOT_FOUND,
2383 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", ret);
2386 static void test_rw_order(void)
2388 HKEY hKey;
2389 DWORD dw = 0;
2390 static const char keyname[] = "test_rw_order";
2391 char value_buf[2];
2392 DWORD values, value_len, value_name_max_len;
2393 LSTATUS ret;
2395 RegDeleteKeyA(HKEY_CURRENT_USER, keyname);
2396 ret = RegCreateKeyA(HKEY_CURRENT_USER, keyname, &hKey);
2397 if(ret != ERROR_SUCCESS) {
2398 skip("Couldn't create key. Skipping.\n");
2399 return;
2402 ok(!RegSetValueExA(hKey, "A", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)),
2403 "RegSetValueExA for value \"A\" failed\n");
2404 ok(!RegSetValueExA(hKey, "C", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)),
2405 "RegSetValueExA for value \"C\" failed\n");
2406 ok(!RegSetValueExA(hKey, "D", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)),
2407 "RegSetValueExA for value \"D\" failed\n");
2408 ok(!RegSetValueExA(hKey, "B", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)),
2409 "RegSetValueExA for value \"B\" failed\n");
2411 ok(!RegQueryInfoKeyA(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &values,
2412 &value_name_max_len, NULL, NULL, NULL), "RegQueryInfoKeyA failed\n");
2413 ok(values == 4, "Expected 4 values, got %lu\n", values);
2415 /* Value enumeration preserves RegSetValueEx call order */
2416 value_len = 2;
2417 ok(!RegEnumValueA(hKey, 0, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n");
2418 ok(strcmp(value_buf, "A") == 0, "Expected name \"A\", got %s\n", value_buf);
2419 value_len = 2;
2420 ok(!RegEnumValueA(hKey, 1, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n");
2421 todo_wine ok(strcmp(value_buf, "C") == 0, "Expected name \"C\", got %s\n", value_buf);
2422 value_len = 2;
2423 ok(!RegEnumValueA(hKey, 2, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n");
2424 todo_wine ok(strcmp(value_buf, "D") == 0, "Expected name \"D\", got %s\n", value_buf);
2425 value_len = 2;
2426 ok(!RegEnumValueA(hKey, 3, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n");
2427 todo_wine ok(strcmp(value_buf, "B") == 0, "Expected name \"B\", got %s\n", value_buf);
2429 ok(!RegDeleteKeyA(HKEY_CURRENT_USER, keyname), "Failed to delete key\n");
2432 static void test_symlinks(void)
2434 static const WCHAR targetW[] = L"\\Software\\Wine\\Test\\target";
2435 BYTE buffer[1024];
2436 UNICODE_STRING target_str;
2437 WCHAR *target;
2438 HKEY key, link;
2439 NTSTATUS status;
2440 DWORD target_len, type, len, dw, err;
2442 if (!pRtlFormatCurrentUserKeyPath || !pNtDeleteKey)
2444 win_skip( "Can't perform symlink tests\n" );
2445 return;
2448 pRtlFormatCurrentUserKeyPath( &target_str );
2450 target_len = target_str.Length + sizeof(targetW);
2451 target = HeapAlloc( GetProcessHeap(), 0, target_len );
2452 memcpy( target, target_str.Buffer, target_str.Length );
2453 memcpy( target + target_str.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
2455 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, REG_OPTION_CREATE_LINK,
2456 KEY_ALL_ACCESS, NULL, &link, NULL );
2457 ok( err == ERROR_SUCCESS, "RegCreateKeyEx failed: %lu\n", err );
2459 /* REG_SZ is not allowed */
2460 err = RegSetValueExA( link, "SymbolicLinkValue", 0, REG_SZ, (BYTE *)"foobar", sizeof("foobar") );
2461 ok( err == ERROR_ACCESS_DENIED, "RegSetValueEx wrong error %lu\n", err );
2462 err = RegSetValueExA( link, "SymbolicLinkValue", 0, REG_LINK,
2463 (BYTE *)target, target_len - sizeof(WCHAR) );
2464 ok( err == ERROR_SUCCESS, "RegSetValueEx failed error %lu\n", err );
2465 /* other values are not allowed */
2466 err = RegSetValueExA( link, "link", 0, REG_LINK, (BYTE *)target, target_len - sizeof(WCHAR) );
2467 ok( err == ERROR_ACCESS_DENIED, "RegSetValueEx wrong error %lu\n", err );
2469 /* try opening the target through the link */
2471 err = RegOpenKeyA( hkey_main, "link", &key );
2472 ok( err == ERROR_FILE_NOT_FOUND, "RegOpenKey wrong error %lu\n", err );
2474 err = RegCreateKeyExA( hkey_main, "target", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key, NULL );
2475 ok( err == ERROR_SUCCESS, "RegCreateKeyEx failed error %lu\n", err );
2477 dw = 0xbeef;
2478 err = RegSetValueExA( key, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2479 ok( err == ERROR_SUCCESS, "RegSetValueEx failed error %lu\n", err );
2480 RegCloseKey( key );
2482 err = RegOpenKeyA( hkey_main, "link", &key );
2483 ok( err == ERROR_SUCCESS, "RegOpenKey failed error %lu\n", err );
2485 len = sizeof(buffer);
2486 err = RegQueryValueExA( key, "value", NULL, &type, buffer, &len );
2487 ok( err == ERROR_SUCCESS, "RegOpenKey failed error %lu\n", err );
2488 ok( len == sizeof(DWORD), "wrong len %lu\n", len );
2490 len = sizeof(buffer);
2491 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2492 ok( err == ERROR_FILE_NOT_FOUND, "RegQueryValueEx wrong error %lu\n", err );
2494 /* REG_LINK can be created in non-link keys */
2495 err = RegSetValueExA( key, "SymbolicLinkValue", 0, REG_LINK,
2496 (BYTE *)target, target_len - sizeof(WCHAR) );
2497 ok( err == ERROR_SUCCESS, "RegSetValueEx failed error %lu\n", err );
2498 len = sizeof(buffer);
2499 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2500 ok( err == ERROR_SUCCESS, "RegQueryValueEx failed error %lu\n", err );
2501 ok( len == target_len - sizeof(WCHAR), "wrong len %lu\n", len );
2502 err = RegDeleteValueA( key, "SymbolicLinkValue" );
2503 ok( err == ERROR_SUCCESS, "RegDeleteValue failed error %lu\n", err );
2505 RegCloseKey( key );
2507 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key, NULL );
2508 ok( err == ERROR_SUCCESS, "RegCreateKeyEx failed error %lu\n", err );
2510 len = sizeof(buffer);
2511 err = RegQueryValueExA( key, "value", NULL, &type, buffer, &len );
2512 ok( err == ERROR_SUCCESS, "RegQueryValueEx failed error %lu\n", err );
2513 ok( len == sizeof(DWORD), "wrong len %lu\n", len );
2515 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2516 ok( err == ERROR_FILE_NOT_FOUND, "RegQueryValueEx wrong error %lu\n", err );
2517 RegCloseKey( key );
2519 /* now open the symlink itself */
2521 err = RegOpenKeyExA( hkey_main, "link", REG_OPTION_OPEN_LINK, KEY_ALL_ACCESS, &key );
2522 ok( err == ERROR_SUCCESS, "RegOpenKeyEx failed error %lu\n", err );
2523 len = sizeof(buffer);
2524 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2525 ok( err == ERROR_SUCCESS, "RegQueryValueEx failed error %lu\n", err );
2526 ok( len == target_len - sizeof(WCHAR), "wrong len %lu\n", len );
2527 RegCloseKey( key );
2529 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, REG_OPTION_OPEN_LINK,
2530 KEY_ALL_ACCESS, NULL, &key, NULL );
2531 ok( err == ERROR_SUCCESS, "RegCreateKeyEx failed error %lu\n", err );
2532 len = sizeof(buffer);
2533 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2534 ok( err == ERROR_SUCCESS, "RegQueryValueEx failed error %lu\n", err );
2535 ok( len == target_len - sizeof(WCHAR), "wrong len %lu\n", len );
2536 RegCloseKey( key );
2538 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, REG_OPTION_CREATE_LINK,
2539 KEY_ALL_ACCESS, NULL, &key, NULL );
2540 ok( err == ERROR_ALREADY_EXISTS, "RegCreateKeyEx wrong error %lu\n", err );
2542 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, REG_OPTION_CREATE_LINK | REG_OPTION_OPEN_LINK,
2543 KEY_ALL_ACCESS, NULL, &key, NULL );
2544 ok( err == ERROR_ALREADY_EXISTS, "RegCreateKeyEx wrong error %lu\n", err );
2546 err = RegDeleteKeyA( hkey_main, "target" );
2547 ok( err == ERROR_SUCCESS, "RegDeleteKey failed error %lu\n", err );
2549 err = RegDeleteKeyA( hkey_main, "link" );
2550 ok( err == ERROR_FILE_NOT_FOUND, "RegDeleteKey wrong error %lu\n", err );
2552 status = pNtDeleteKey( link );
2553 ok( !status, "NtDeleteKey failed: 0x%08lx\n", status );
2554 RegCloseKey( link );
2556 HeapFree( GetProcessHeap(), 0, target );
2557 pRtlFreeUnicodeString( &target_str );
2560 static DWORD get_key_value( HKEY root, const char *name, DWORD flags )
2562 HKEY key;
2563 DWORD err, type, dw = 1, len = sizeof(dw);
2565 err = RegOpenKeyExA( root, name, 0, flags | KEY_ALL_ACCESS, &key );
2566 if (err == ERROR_FILE_NOT_FOUND) return 0;
2567 ok( err == ERROR_SUCCESS, "%08lx: RegOpenKeyEx failed: %lu\n", flags, err );
2569 err = RegQueryValueExA( key, "value", NULL, &type, (BYTE *)&dw, &len );
2570 if (err == ERROR_FILE_NOT_FOUND)
2571 dw = 0;
2572 else
2573 ok( err == ERROR_SUCCESS, "%08lx: RegQueryValueEx failed: %lu\n", flags, err );
2574 RegCloseKey( key );
2575 return dw;
2578 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
2580 DWORD dw = get_key_value( root, name, flags );
2581 ok_(__FILE__,line)( dw == expect, "%08lx: wrong value %lu/%lu\n", flags, dw, expect );
2583 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
2585 static void _check_enum_value( int line, const char *name, DWORD flags, DWORD subkeys_in, BOOL found_in)
2587 char buffer[1024];
2588 DWORD err, i, subkeys;
2589 BOOL found;
2590 HKEY key;
2592 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, name, 0, flags, &key );
2593 ok_( __FILE__, line )( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
2595 err = RegQueryInfoKeyA( key, NULL, NULL, NULL, &subkeys,
2596 NULL, NULL, NULL, NULL, NULL, NULL, NULL );
2597 ok_( __FILE__, line )( err == ERROR_SUCCESS, "RegQueryInfoKeyA failed: %lu\n", err );
2598 ok_( __FILE__, line )( subkeys == subkeys_in, "wrong number of subkeys: %lu\n", subkeys );
2600 found = FALSE;
2601 for (i = 0; i < subkeys; i++)
2603 err = RegEnumKeyA( key, i, buffer, sizeof(buffer) );
2604 ok_( __FILE__, line )( err == ERROR_SUCCESS, "RegEnumKeyA failed: %lu\n", err );
2606 if (!strcmp(buffer, "Wine"))
2607 found = TRUE;
2609 ok_( __FILE__, line )( found == found_in, "found equals %d\n", found );
2610 RegCloseKey( key );
2612 #define check_enum_value(name, flags, subkeys, found) _check_enum_value( __LINE__, name, flags, subkeys, found )
2614 static void test_redirection(void)
2616 DWORD err, type, dw, len;
2617 HKEY key, key32, key64, root, root32, root64;
2618 DWORD subkeys, subkeys32, subkeys64;
2620 if (ptr_size != 64)
2622 BOOL is_wow64;
2623 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 ) || !is_wow64)
2625 skip( "Not on Wow64, no redirection\n" );
2626 return;
2630 if (limited_user)
2632 skip("not enough privileges to modify HKLM\n");
2633 return;
2636 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2637 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &root64, NULL );
2638 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2640 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2641 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &root32, NULL );
2642 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2644 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", 0, NULL, 0,
2645 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key64, NULL );
2646 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2648 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", 0, NULL, 0,
2649 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key32, NULL );
2650 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2652 dw = 64;
2653 err = RegSetValueExA( key64, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2654 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
2656 dw = 32;
2657 err = RegSetValueExA( key32, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2658 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
2660 dw = 0;
2661 len = sizeof(dw);
2662 err = RegQueryValueExA( key32, "value", NULL, &type, (BYTE *)&dw, &len );
2663 ok( err == ERROR_SUCCESS, "RegQueryValueExA failed: %lu\n", err );
2664 ok( dw == 32, "wrong value %lu\n", dw );
2666 dw = 0;
2667 len = sizeof(dw);
2668 err = RegQueryValueExA( key64, "value", NULL, &type, (BYTE *)&dw, &len );
2669 ok( err == ERROR_SUCCESS, "RegQueryValueExA failed: %lu\n", err );
2670 ok( dw == 64, "wrong value %lu\n", dw );
2672 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
2673 KEY_ALL_ACCESS, NULL, &key, NULL );
2674 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2675 check_key_value( key, "Wine\\Winetest", 0, ptr_size );
2676 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, ptr_size );
2677 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2678 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, ptr_size == 32 ? 0 : 32 );
2679 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, ptr_size == 32 ? 0 : 32 );
2680 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, ptr_size == 32 ? 0 : 32 );
2681 RegCloseKey( key );
2683 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
2684 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2685 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2686 dw = get_key_value( key, "Wine\\Winetest", 0 );
2687 ok( dw == 64 || broken(dw == 32) /* win7 */, "wrong value %lu\n", dw );
2688 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
2689 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2690 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
2691 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 );
2692 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2693 RegCloseKey( key );
2695 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
2696 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2697 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2698 check_key_value( key, "Wine\\Winetest", 0, 32 );
2699 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 32 );
2700 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2701 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 0 );
2702 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 0 );
2703 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 0 );
2704 RegCloseKey( key );
2706 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", 0, ptr_size );
2707 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
2708 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
2709 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2710 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 );
2711 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2713 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node", 0, NULL, 0,
2714 KEY_ALL_ACCESS, NULL, &key, NULL );
2715 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2716 check_key_value( key, "Wine\\Winetest", 0, 32 );
2717 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 32 );
2718 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2719 RegCloseKey( key );
2721 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node", 0, NULL, 0,
2722 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2723 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2724 check_key_value( key, "Wine\\Winetest", 0, 32 );
2725 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 32 );
2726 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2727 RegCloseKey( key );
2729 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node", 0, NULL, 0,
2730 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2731 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2732 check_key_value( key, "Wine\\Winetest", 0, 32 );
2733 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 32 );
2734 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2735 RegCloseKey( key );
2737 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine", 0, NULL, 0,
2738 KEY_ALL_ACCESS, NULL, &key, NULL );
2739 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2740 check_key_value( key, "Winetest", 0, 32 );
2741 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 32 );
2742 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
2743 RegCloseKey( key );
2745 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine", 0, NULL, 0,
2746 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2747 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2748 check_key_value( key, "Winetest", 0, 32 );
2749 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 32 );
2750 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
2751 RegCloseKey( key );
2753 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine", 0, NULL, 0,
2754 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2755 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2756 check_key_value( key, "Winetest", 0, 32 );
2757 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 32 );
2758 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
2759 RegCloseKey( key );
2761 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2762 KEY_ALL_ACCESS, NULL, &key, NULL );
2763 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2764 check_key_value( key, "Winetest", 0, ptr_size );
2765 check_key_value( key, "Winetest", KEY_WOW64_64KEY, ptr_size );
2766 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
2767 RegCloseKey( key );
2769 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2770 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2771 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2772 check_key_value( key, "Winetest", 0, 64 );
2773 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
2774 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
2775 RegCloseKey( key );
2777 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2778 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2779 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %lu\n", err );
2780 check_key_value( key, "Winetest", 0, 32 );
2781 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 32 );
2782 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
2783 RegCloseKey( key );
2785 if (pRegDeleteKeyExA)
2787 err = pRegDeleteKeyExA( key32, "", KEY_WOW64_32KEY, 0 );
2788 ok( err == ERROR_SUCCESS, "RegDeleteKey failed: %lu\n", err );
2789 err = pRegDeleteKeyExA( key64, "", KEY_WOW64_64KEY, 0 );
2790 ok( err == ERROR_SUCCESS, "RegDeleteKey failed: %lu\n", err );
2791 pRegDeleteKeyExA( key64, "", KEY_WOW64_64KEY, 0 );
2792 pRegDeleteKeyExA( root64, "", KEY_WOW64_64KEY, 0 );
2794 else
2796 err = RegDeleteKeyA( key32, "" );
2797 ok( err == ERROR_SUCCESS, "RegDeleteKey failed: %lu\n", err );
2798 err = RegDeleteKeyA( key64, "" );
2799 ok( err == ERROR_SUCCESS, "RegDeleteKey failed: %lu\n", err );
2800 RegDeleteKeyA( key64, "" );
2801 RegDeleteKeyA( root64, "" );
2803 RegCloseKey( key32 );
2804 RegCloseKey( key64 );
2805 RegCloseKey( root32 );
2806 RegCloseKey( root64 );
2808 /* Software\Classes is shared/reflected so behavior is different */
2810 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wine",
2811 0, NULL, 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key64, NULL);
2812 if (err == ERROR_ACCESS_DENIED)
2814 skip("Not authorized to modify the Classes key\n");
2815 return;
2817 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
2819 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node\\Wine",
2820 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key );
2821 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
2822 RegCloseKey( key );
2824 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node\\Wine",
2825 0, KEY_ALL_ACCESS, &key );
2826 ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS),
2827 "RegOpenKeyExA failed: %lu\n", err );
2828 if (!err) RegCloseKey( key );
2830 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node\\Wine",
2831 0, NULL, 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key32, NULL);
2832 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
2834 dw = 32;
2835 err = RegSetValueExA( key32, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2836 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
2838 dw = 64;
2839 err = RegSetValueExA( key64, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2840 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
2842 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wine", 0, 64 );
2843 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wine", KEY_WOW64_64KEY, 64 );
2844 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wine", KEY_WOW64_32KEY, 64 );
2845 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node\\Wine", 0, ptr_size == 64 ? 0 : 64 );
2846 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node\\Wine", KEY_WOW64_64KEY, 0 );
2847 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node\\Wine", KEY_WOW64_32KEY, 64 );
2849 RegDeleteKeyA( key32, "" );
2850 RegCloseKey( key32 );
2852 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wine", 0, 0 );
2853 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wine", KEY_WOW64_64KEY, 0 );
2854 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wine", KEY_WOW64_32KEY, 0 );
2855 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node\\Wine", 0, 0 );
2856 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node\\Wine", KEY_WOW64_64KEY, 0 );
2857 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node\\Wine", KEY_WOW64_32KEY, 0 );
2859 RegDeleteKeyA( key64, "" );
2860 RegCloseKey( key64 );
2862 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes", 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &root64 );
2863 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
2865 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes", 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &root32 );
2866 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
2868 err = RegCreateKeyExA( root64, "Wine", 0, NULL, 0,
2869 KEY_ALL_ACCESS, NULL, &key64, NULL);
2870 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
2872 err = RegCreateKeyExA( key64, "Wine", 0, NULL, 0,
2873 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL);
2874 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
2875 RegDeleteKeyA( key, "" );
2876 RegCloseKey( key );
2878 err = RegOpenKeyExA( root32, "Wine", 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key );
2879 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
2880 RegCloseKey( key );
2882 err = RegOpenKeyExA( root32, "Wine", 0, KEY_ALL_ACCESS, &key );
2883 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
2884 RegCloseKey( key );
2886 err = RegCreateKeyExA( root32, "Wine", 0, NULL, 0,
2887 KEY_ALL_ACCESS, NULL, &key32, NULL);
2888 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
2890 dw = 32;
2891 err = RegSetValueExA( key32, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2892 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
2894 dw = 64;
2895 err = RegSetValueExA( key64, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2896 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
2898 check_key_value( root64, "Wine", 0, 64 );
2899 check_key_value( root64, "Wine", KEY_WOW64_64KEY, 64 );
2900 check_key_value( root64, "Wine", KEY_WOW64_32KEY, 64 );
2901 check_key_value( root32, "Wine", 0, 64 );
2902 check_key_value( root32, "Wine", KEY_WOW64_64KEY, 64 );
2903 check_key_value( root32, "Wine", KEY_WOW64_32KEY, 64 );
2905 RegDeleteKeyA( key32, "" );
2906 RegCloseKey( key32 );
2908 check_key_value( root64, "Wine", 0, 0 );
2909 check_key_value( root64, "Wine", KEY_WOW64_64KEY, 0 );
2910 check_key_value( root64, "Wine", KEY_WOW64_32KEY, 0 );
2911 check_key_value( root32, "Wine", 0, 0 );
2912 check_key_value( root32, "Wine", KEY_WOW64_64KEY, 0 );
2913 check_key_value( root32, "Wine", KEY_WOW64_32KEY, 0 );
2915 RegDeleteKeyA( key64, "" );
2916 RegCloseKey( key64 );
2918 err = RegCreateKeyExA( root32, "Wine", 0, NULL, 0,
2919 KEY_ALL_ACCESS, NULL, &key32, NULL);
2920 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
2922 dw = 32;
2923 err = RegSetValueExA( key32, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2924 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
2926 check_key_value( root64, "Wine", 0, 32 );
2927 check_key_value( root64, "Wine", KEY_WOW64_64KEY, 32 );
2928 check_key_value( root64, "Wine", KEY_WOW64_32KEY, 32 );
2929 check_key_value( root32, "Wine", 0, 32 );
2930 check_key_value( root32, "Wine", KEY_WOW64_64KEY, 32 );
2931 check_key_value( root32, "Wine", KEY_WOW64_32KEY, 32 );
2933 RegDeleteKeyA( key32, "" );
2934 RegCloseKey( key32 );
2936 RegCloseKey( root64 );
2937 RegCloseKey( root32 );
2939 err = RegOpenKeyExA( HKEY_CLASSES_ROOT, "Interface",
2940 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &root64 );
2941 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
2943 err = RegOpenKeyExA( HKEY_CLASSES_ROOT, "Interface",
2944 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &root32 );
2945 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
2947 err = RegOpenKeyExA( HKEY_CLASSES_ROOT, "Interface",
2948 0, KEY_ALL_ACCESS, &root );
2949 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
2951 err = RegCreateKeyExA( root32, "Wine", 0, NULL, 0,
2952 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key32, NULL);
2953 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
2955 err = RegOpenKeyExA( root, "Wine", 0, KEY_ALL_ACCESS, &key );
2956 ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS),
2957 "RegOpenKeyExA failed: %lu\n", err );
2958 if (!err) RegCloseKey( key );
2960 RegDeleteKeyA( key32, "" );
2961 RegCloseKey( key32 );
2963 err = RegCreateKeyExA( root64, "Wine", 0, NULL, 0,
2964 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key64, NULL);
2965 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
2967 err = RegOpenKeyExA( root, "Wine", 0, KEY_ALL_ACCESS, &key );
2968 ok( err == (ptr_size == 32 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS),
2969 "RegOpenKeyExA failed: %lu\n", err );
2970 if (!err) RegCloseKey( key );
2972 RegDeleteKeyA( key64, "" );
2973 RegCloseKey( key64 );
2975 RegDeleteKeyA( root64, "" );
2976 RegDeleteKeyA( root32, "" );
2977 RegDeleteKeyA( root, "" );
2979 RegCloseKey( root64 );
2980 RegCloseKey( root32 );
2981 RegCloseKey( root );
2983 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes",
2984 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &root64 );
2985 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
2987 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes",
2988 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &root32 );
2989 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
2991 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes",
2992 0, KEY_ALL_ACCESS, &root );
2993 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
2995 err = RegOpenKeyExA( root64, "Interface",
2996 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &key64 );
2997 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
2999 err = RegOpenKeyExA( root32, "Interface",
3000 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key32 );
3001 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
3003 err = RegOpenKeyExA( root, "Interface",
3004 0, KEY_ALL_ACCESS, &key );
3005 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
3007 RegCloseKey( root64 );
3008 RegCloseKey( root32 );
3009 RegCloseKey( root );
3011 root64 = key64;
3012 root32 = key32;
3013 root = key;
3015 err = RegCreateKeyExA( root32, "Wine", 0, NULL, 0,
3016 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key32, NULL);
3017 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
3019 err = RegOpenKeyExA( root, "Wine", 0, KEY_ALL_ACCESS, &key );
3020 ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS),
3021 "RegOpenKeyExA failed: %lu\n", err );
3022 if (!err) RegCloseKey( key );
3024 RegDeleteKeyA( key32, "" );
3025 RegCloseKey( key32 );
3027 err = RegCreateKeyExA( root64, "Wine", 0, NULL, 0,
3028 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key64, NULL);
3029 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
3031 err = RegOpenKeyExA( root, "Wine", 0, KEY_ALL_ACCESS, &key );
3032 ok( err == (ptr_size == 32 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS),
3033 "RegOpenKeyExA failed: %lu\n", err );
3034 if (!err) RegCloseKey( key );
3036 RegDeleteKeyA( key64, "" );
3037 RegCloseKey( key64 );
3039 RegDeleteKeyA( root, "" );
3040 RegCloseKey( root );
3042 err = RegCreateKeyExA( root64, "Wine", 0, NULL, 0,
3043 KEY_ALL_ACCESS, NULL, &key64, NULL);
3044 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
3046 err = RegOpenKeyExA( root32, "Wine", 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key );
3047 ok( err == ERROR_FILE_NOT_FOUND, "RegOpenKeyExA failed: %lu\n", err );
3049 err = RegOpenKeyExA( root32, "Wine", 0, KEY_ALL_ACCESS, &key );
3050 ok( err == ERROR_FILE_NOT_FOUND, "RegOpenKeyExA failed: %lu\n", err );
3052 err = RegCreateKeyExA( root32, "Wine", 0, NULL, 0,
3053 KEY_ALL_ACCESS, NULL, &key32, NULL);
3054 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
3056 dw = 32;
3057 err = RegSetValueExA( key32, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
3058 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
3060 dw = 64;
3061 err = RegSetValueExA( key64, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
3062 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
3064 check_key_value( root64, "Wine", 0, 64 );
3065 check_key_value( root64, "Wine", KEY_WOW64_64KEY, 64 );
3066 check_key_value( root64, "Wine", KEY_WOW64_32KEY, 32 );
3067 check_key_value( root32, "Wine", 0, 32 );
3068 check_key_value( root32, "Wine", KEY_WOW64_64KEY, 32 );
3069 check_key_value( root32, "Wine", KEY_WOW64_32KEY, 32 );
3071 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Interface",
3072 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &key );
3073 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
3074 check_key_value( key, "Wine", 0, 64 );
3075 check_key_value( key, "Wine", KEY_WOW64_64KEY, 64 );
3076 check_key_value( key, "Wine", KEY_WOW64_32KEY, 32 );
3077 RegCloseKey( key );
3079 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Interface",
3080 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key );
3081 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
3082 check_key_value( key, "Wine", 0, 32 );
3083 check_key_value( key, "Wine", KEY_WOW64_64KEY, 32 );
3084 check_key_value( key, "Wine", KEY_WOW64_32KEY, 32 );
3085 RegCloseKey( key );
3087 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Interface\\Wine", 0, ptr_size );
3088 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Interface\\Wine", KEY_WOW64_64KEY, 64 );
3089 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Interface\\Wine", KEY_WOW64_32KEY, 32 );
3091 RegDeleteKeyA( key32, "" );
3092 RegCloseKey( key32 );
3094 check_key_value( root64, "Wine", 0, 64 );
3095 check_key_value( root64, "Wine", KEY_WOW64_64KEY, 64 );
3096 check_key_value( root64, "Wine", KEY_WOW64_32KEY, 0 );
3097 check_key_value( root32, "Wine", 0, 0 );
3098 check_key_value( root32, "Wine", KEY_WOW64_64KEY, 0 );
3099 check_key_value( root32, "Wine", KEY_WOW64_32KEY, 0 );
3101 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Interface\\Wine", 0, ptr_size == 64 ? 64 : 0 );
3102 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Interface\\Wine", KEY_WOW64_64KEY, 64 );
3103 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Classes\\Interface\\Wine", KEY_WOW64_32KEY, 0 );
3105 RegDeleteKeyA( key64, "" );
3106 RegCloseKey( key64 );
3108 err = RegCreateKeyExA( root32, "Wine", 0, NULL, 0,
3109 KEY_ALL_ACCESS, NULL, &key32, NULL);
3110 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
3112 dw = 32;
3113 err = RegSetValueExA( key32, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
3114 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %lu\n", err );
3116 check_key_value( root64, "Wine", 0, 0 );
3117 check_key_value( root64, "Wine", KEY_WOW64_64KEY, 0 );
3118 check_key_value( root64, "Wine", KEY_WOW64_32KEY, 32 );
3119 check_key_value( root32, "Wine", 0, 32 );
3120 check_key_value( root32, "Wine", KEY_WOW64_64KEY, 32 );
3121 check_key_value( root32, "Wine", KEY_WOW64_32KEY, 32 );
3123 RegDeleteKeyA( key32, "" );
3124 RegCloseKey( key32 );
3126 RegCloseKey( root64 );
3127 RegCloseKey( root32 );
3129 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node\\Wine",
3130 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key32, NULL);
3131 ok( err == ERROR_SUCCESS, "RegCreateKeyA failed: %lu\n", err );
3133 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node\\Wine",
3134 0, KEY_ALL_ACCESS, &key );
3135 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
3136 RegCloseKey( key );
3138 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node\\Wine",
3139 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key );
3140 todo_wine_if(ptr_size == 64) ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS),
3141 "RegOpenKeyExA failed: %lu\n", err );
3142 if (!err) RegCloseKey( key );
3144 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node\\Wine",
3145 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &key );
3146 ok( err == (ptr_size == 32 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS),
3147 "RegOpenKeyExA failed: %lu\n", err );
3148 if (!err) RegCloseKey( key );
3150 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wine",
3151 0, KEY_ALL_ACCESS, &key );
3152 ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS),
3153 "RegOpenKeyExA failed: %lu\n", err );
3154 if (!err) RegCloseKey( key );
3156 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wine",
3157 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &key );
3158 todo_wine_if(ptr_size == 64) ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS),
3159 "RegOpenKeyExA failed: %lu\n", err );
3160 if (!err) RegCloseKey( key );
3162 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wine",
3163 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &key );
3164 ok( err == (ptr_size == 64 ? ERROR_FILE_NOT_FOUND : ERROR_SUCCESS),
3165 "RegOpenKeyExA failed: %lu\n", err );
3166 if (!err) RegCloseKey( key );
3168 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\Wow6432Node",
3169 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &root32 );
3170 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
3172 err = RegQueryInfoKeyA(root32, NULL, NULL, NULL, &subkeys,
3173 NULL, NULL, NULL, NULL, NULL, NULL, NULL );
3174 ok( err == ERROR_SUCCESS, "RegQueryInfoKeyA failed: %lu\n", err );
3175 ok( subkeys > 0, "wrong number of subkeys: %lu\n", subkeys );
3176 subkeys32 = subkeys;
3177 RegCloseKey( root32 );
3179 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes",
3180 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &root64 );
3181 ok( err == ERROR_SUCCESS, "RegOpenKeyExA failed: %lu\n", err );
3183 err = RegQueryInfoKeyA(root64, NULL, NULL, NULL, &subkeys,
3184 NULL, NULL, NULL, NULL, NULL, NULL, NULL );
3185 ok( err == ERROR_SUCCESS, "RegQueryInfoKeyA failed: %lu\n", err );
3186 ok( subkeys > subkeys32, "wrong number of subkeys: %lu\n", subkeys );
3187 subkeys64 = subkeys;
3188 RegCloseKey( root64 );
3190 check_enum_value( "Software\\Classes",
3191 KEY_WOW64_32KEY | KEY_ALL_ACCESS, subkeys64, ptr_size == 32 );
3192 check_enum_value( "Software\\Classes",
3193 KEY_WOW64_64KEY | KEY_ALL_ACCESS, subkeys64, ptr_size == 32 );
3194 check_enum_value( "Software\\Classes",
3195 KEY_ALL_ACCESS, subkeys64, ptr_size == 32 );
3196 check_enum_value( "Software\\Classes\\Wow6432Node",
3197 KEY_WOW64_32KEY | KEY_ALL_ACCESS, subkeys32, ptr_size == 64 );
3198 check_enum_value( "Software\\Classes\\Wow6432Node",
3199 KEY_WOW64_64KEY | KEY_ALL_ACCESS, subkeys32, ptr_size == 64 );
3200 check_enum_value( "Software\\Classes\\Wow6432Node",
3201 KEY_ALL_ACCESS, subkeys32, ptr_size == 64 );
3202 check_enum_value( "Software\\Wow6432Node\\Classes",
3203 KEY_WOW64_32KEY | KEY_ALL_ACCESS, subkeys64, ptr_size == 32 );
3204 check_enum_value( "Software\\Wow6432Node\\Classes",
3205 KEY_WOW64_64KEY | KEY_ALL_ACCESS, subkeys32, ptr_size == 64 );
3206 check_enum_value( "Software\\Wow6432Node\\Classes",
3207 KEY_ALL_ACCESS, ptr_size == 32 ? subkeys64 : subkeys32, TRUE );
3209 RegDeleteKeyA( key32, "" );
3210 RegCloseKey( key32 );
3213 static void test_classesroot(void)
3215 HKEY hkey, hklm, hkcr, hkeysub1, hklmsub1, hkcrsub1, hklmsub2, hkcrsub2;
3216 DWORD size = 8;
3217 DWORD type = REG_SZ;
3218 static CHAR buffer[8];
3219 LONG res;
3221 /* create a key in the user's classes */
3222 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", &hkey ))
3224 delete_key( hkey );
3225 RegCloseKey( hkey );
3227 res = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", 0, NULL, 0,
3228 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkey, NULL );
3229 if (res == ERROR_ACCESS_DENIED)
3231 skip("not enough privileges to add a user class\n");
3232 return;
3234 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3236 /* try to open that key in hkcr */
3237 res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "WineTestCls", 0,
3238 KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
3239 todo_wine ok(res == ERROR_SUCCESS ||
3240 broken(res == ERROR_FILE_NOT_FOUND /* WinNT */),
3241 "test key not found in hkcr: %ld\n", res);
3242 if (res)
3244 skip("HKCR key merging not supported\n");
3245 delete_key( hkey );
3246 RegCloseKey( hkey );
3247 return;
3250 todo_wine ok(IS_HKCR(hkcr), "hkcr mask not set in %p\n", hkcr);
3252 /* set a value in user's classes */
3253 res = RegSetValueExA(hkey, "val1", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
3254 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3256 /* try to find the value in hkcr */
3257 res = RegQueryValueExA(hkcr, "val1", NULL, &type, (LPBYTE)buffer, &size);
3258 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", res);
3259 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
3261 /* modify the value in hkcr */
3262 res = RegSetValueExA(hkcr, "val1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
3263 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3265 /* check if the value is also modified in user's classes */
3266 res = RegQueryValueExA(hkey, "val1", NULL, &type, (LPBYTE)buffer, &size);
3267 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3268 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
3270 /* set a value in hkcr */
3271 res = RegSetValueExA(hkcr, "val0", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
3272 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3274 /* try to find the value in user's classes */
3275 res = RegQueryValueExA(hkey, "val0", NULL, &type, (LPBYTE)buffer, &size);
3276 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", res);
3277 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
3279 /* modify the value in user's classes */
3280 res = RegSetValueExA(hkey, "val0", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
3281 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3283 /* check if the value is also modified in hkcr */
3284 res = RegQueryValueExA(hkcr, "val0", NULL, &type, (LPBYTE)buffer, &size);
3285 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3286 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
3288 /* cleanup */
3289 delete_key( hkey );
3290 delete_key( hkcr );
3291 RegCloseKey( hkey );
3292 RegCloseKey( hkcr );
3294 /* create a key in the hklm classes */
3295 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", &hklm ))
3297 delete_key( hklm );
3298 RegCloseKey( hklm );
3300 res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", 0, NULL, REG_OPTION_NON_VOLATILE,
3301 KEY_ALL_ACCESS, NULL, &hklm, NULL );
3302 if (res == ERROR_ACCESS_DENIED)
3304 skip("not enough privileges to add a system class\n");
3305 return;
3307 ok(!IS_HKCR(hklm), "hkcr mask set in %p\n", hklm);
3309 /* try to open that key in hkcr */
3310 res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "WineTestCls", 0,
3311 KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
3312 ok(res == ERROR_SUCCESS,
3313 "test key not found in hkcr: %ld\n", res);
3314 ok(IS_HKCR(hkcr), "hkcr mask not set in %p\n", hkcr);
3315 if (res)
3317 delete_key( hklm );
3318 RegCloseKey( hklm );
3319 return;
3322 /* set a value in hklm classes */
3323 res = RegSetValueExA(hklm, "val2", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
3324 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3326 /* try to find the value in hkcr */
3327 res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
3328 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", res);
3329 ok(!strcmp( buffer, "hklm" ), "value set to '%s'\n", buffer );
3331 /* modify the value in hkcr */
3332 res = RegSetValueExA(hkcr, "val2", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
3333 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3335 /* check that the value is modified in hklm classes */
3336 res = RegQueryValueExA(hklm, "val2", NULL, &type, (LPBYTE)buffer, &size);
3337 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3338 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
3340 if (RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", 0, NULL, 0,
3341 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkey, NULL )) return;
3342 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3344 /* try to open that key in hkcr */
3345 res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "WineTestCls", 0,
3346 KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
3347 ok(res == ERROR_SUCCESS,
3348 "test key not found in hkcr: %ld\n", res);
3349 ok(IS_HKCR(hkcr), "hkcr mask not set in %p\n", hkcr);
3351 /* set a value in user's classes */
3352 res = RegSetValueExA(hkey, "val2", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
3353 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3355 /* try to find the value in hkcr */
3356 res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
3357 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", res);
3358 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
3360 /* modify the value in hklm */
3361 res = RegSetValueExA(hklm, "val2", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
3362 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3364 /* check that the value is not overwritten in hkcr or user's classes */
3365 res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
3366 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", res);
3367 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
3368 res = RegQueryValueExA(hkey, "val2", NULL, &type, (LPBYTE)buffer, &size);
3369 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3370 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
3372 /* modify the value in hkcr */
3373 res = RegSetValueExA(hkcr, "val2", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
3374 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3376 /* check that the value is overwritten in hklm and user's classes */
3377 res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
3378 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", res);
3379 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
3380 res = RegQueryValueExA(hkey, "val2", NULL, &type, (LPBYTE)buffer, &size);
3381 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3382 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
3384 /* create a subkey in hklm */
3385 if (RegCreateKeyExA( hklm, "subkey1", 0, NULL, 0,
3386 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hklmsub1, NULL )) return;
3387 ok(!IS_HKCR(hklmsub1), "hkcr mask set in %p\n", hklmsub1);
3388 /* try to open that subkey in hkcr */
3389 res = RegOpenKeyExA( hkcr, "subkey1", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcrsub1 );
3390 ok(res == ERROR_SUCCESS, "test key not found in hkcr: %ld\n", res);
3391 ok(IS_HKCR(hkcrsub1), "hkcr mask not set in %p\n", hkcrsub1);
3393 /* set a value in hklm classes */
3394 res = RegSetValueExA(hklmsub1, "subval1", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
3395 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3397 /* try to find the value in hkcr */
3398 res = RegQueryValueExA(hkcrsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3399 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", res);
3400 ok(!strcmp( buffer, "hklm" ), "value set to '%s'\n", buffer );
3402 /* modify the value in hkcr */
3403 res = RegSetValueExA(hkcrsub1, "subval1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
3404 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3406 /* check that the value is modified in hklm classes */
3407 res = RegQueryValueExA(hklmsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3408 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3409 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
3411 /* create a subkey in user's classes */
3412 if (RegCreateKeyExA( hkey, "subkey1", 0, NULL, 0,
3413 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkeysub1, NULL )) return;
3414 ok(!IS_HKCR(hkeysub1), "hkcr mask set in %p\n", hkeysub1);
3416 /* set a value in user's classes */
3417 res = RegSetValueExA(hkeysub1, "subval1", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
3418 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3420 /* try to find the value in hkcr */
3421 res = RegQueryValueExA(hkcrsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3422 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", res);
3423 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
3425 /* modify the value in hklm */
3426 res = RegSetValueExA(hklmsub1, "subval1", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
3427 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3429 /* check that the value is not overwritten in hkcr or user's classes */
3430 res = RegQueryValueExA(hkcrsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3431 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", res);
3432 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
3433 res = RegQueryValueExA(hkeysub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3434 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3435 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
3437 /* modify the value in hkcr */
3438 res = RegSetValueExA(hkcrsub1, "subval1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
3439 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3441 /* check that the value is not overwritten in hklm, but in user's classes */
3442 res = RegQueryValueExA(hklmsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3443 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", res);
3444 ok(!strcmp( buffer, "hklm" ), "value set to '%s'\n", buffer );
3445 res = RegQueryValueExA(hkeysub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3446 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3447 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
3449 /* new subkey in hkcr */
3450 if (RegCreateKeyExA( hkcr, "subkey2", 0, NULL, 0,
3451 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkcrsub2, NULL )) return;
3452 ok(IS_HKCR(hkcrsub2), "hkcr mask not set in %p\n", hkcrsub2);
3453 res = RegSetValueExA(hkcrsub2, "subval1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
3454 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld, GLE=%lx\n", res, GetLastError());
3456 /* try to open that new subkey in user's classes and hklm */
3457 res = RegOpenKeyExA( hkey, "subkey2", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hklmsub2 );
3458 ok(res != ERROR_SUCCESS, "test key found in user's classes: %ld\n", res);
3459 hklmsub2 = 0;
3460 res = RegOpenKeyExA( hklm, "subkey2", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hklmsub2 );
3461 ok(res == ERROR_SUCCESS, "test key not found in hklm: %ld\n", res);
3462 ok(!IS_HKCR(hklmsub2), "hkcr mask set in %p\n", hklmsub2);
3464 /* check that the value is present in hklm */
3465 res = RegQueryValueExA(hklmsub2, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3466 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %ld\n", res);
3467 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
3469 /* cleanup */
3470 RegCloseKey( hkeysub1 );
3471 RegCloseKey( hklmsub1 );
3473 /* delete subkey1 from hkcr (should point at user's classes) */
3474 res = RegDeleteKeyA(hkcr, "subkey1");
3475 ok(res == ERROR_SUCCESS, "RegDeleteKey failed: %ld\n", res);
3477 /* confirm key was removed in hkey but not hklm */
3478 res = RegOpenKeyExA(hkey, "subkey1", 0, KEY_READ, &hkeysub1);
3479 ok(res == ERROR_FILE_NOT_FOUND, "test key found in user's classes: %ld\n", res);
3480 res = RegOpenKeyExA(hklm, "subkey1", 0, KEY_READ, &hklmsub1);
3481 ok(res == ERROR_SUCCESS, "test key not found in hklm: %ld\n", res);
3482 ok(!IS_HKCR(hklmsub1), "hkcr mask set in %p\n", hklmsub1);
3484 /* delete subkey1 from hkcr again (which should now point at hklm) */
3485 res = RegDeleteKeyA(hkcr, "subkey1");
3486 ok(res == ERROR_SUCCESS, "RegDeleteKey failed: %ld\n", res);
3488 /* confirm hkey was removed in hklm */
3489 RegCloseKey( hklmsub1 );
3490 res = RegOpenKeyExA(hklm, "subkey1", 0, KEY_READ, &hklmsub1);
3491 ok(res == ERROR_FILE_NOT_FOUND, "test key found in hklm: %ld\n", res);
3493 /* final cleanup */
3494 delete_key( hkey );
3495 delete_key( hklm );
3496 delete_key( hkcr );
3497 delete_key( hkeysub1 );
3498 delete_key( hklmsub1 );
3499 delete_key( hkcrsub1 );
3500 delete_key( hklmsub2 );
3501 delete_key( hkcrsub2 );
3502 RegCloseKey( hkey );
3503 RegCloseKey( hklm );
3504 RegCloseKey( hkcr );
3505 RegCloseKey( hkeysub1 );
3506 RegCloseKey( hklmsub1 );
3507 RegCloseKey( hkcrsub1 );
3508 RegCloseKey( hklmsub2 );
3509 RegCloseKey( hkcrsub2 );
3512 static void test_classesroot_enum(void)
3514 HKEY hkcu=0, hklm=0, hkcr=0, hkcusub[2]={0}, hklmsub[2]={0};
3515 DWORD size;
3516 static CHAR buffer[2];
3517 LONG res;
3519 /* prepare initial testing env in HKCU */
3520 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", &hkcu ))
3522 delete_key( hkcu );
3523 RegCloseKey( hkcu );
3525 res = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", 0, NULL, 0,
3526 KEY_SET_VALUE|KEY_ENUMERATE_SUB_KEYS, NULL, &hkcu, NULL );
3528 if (res != ERROR_SUCCESS)
3530 skip("failed to add a user class\n");
3531 return;
3534 res = RegOpenKeyA( HKEY_CLASSES_ROOT, "WineTestCls", &hkcr );
3535 todo_wine ok(res == ERROR_SUCCESS ||
3536 broken(res == ERROR_FILE_NOT_FOUND /* WinNT */),
3537 "test key not found in hkcr: %ld\n", res);
3538 if (res)
3540 skip("HKCR key merging not supported\n");
3541 delete_key( hkcu );
3542 RegCloseKey( hkcu );
3543 return;
3546 res = RegSetValueExA( hkcu, "X", 0, REG_SZ, (const BYTE *) "AA", 3 );
3547 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld\n", res);
3548 res = RegSetValueExA( hkcu, "Y", 0, REG_SZ, (const BYTE *) "B", 2 );
3549 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld\n", res);
3550 res = RegCreateKeyA( hkcu, "A", &hkcusub[0] );
3551 ok(res == ERROR_SUCCESS, "RegCreateKeyA failed: %ld\n", res);
3552 res = RegCreateKeyA( hkcu, "B", &hkcusub[1] );
3553 ok(res == ERROR_SUCCESS, "RegCreateKeyA failed: %ld\n", res);
3555 /* test on values in HKCU */
3556 size = sizeof(buffer);
3557 res = RegEnumValueA( hkcr, 0, buffer, &size, NULL, NULL, NULL, NULL );
3558 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %ld\n", res );
3559 ok(!strcmp( buffer, "X" ), "expected 'X', got '%s'\n", buffer);
3560 size = sizeof(buffer);
3561 res = RegEnumValueA( hkcr, 1, buffer, &size, NULL, NULL, NULL, NULL );
3562 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %ld\n", res );
3563 ok(!strcmp( buffer, "Y" ), "expected 'Y', got '%s'\n", buffer);
3564 size = sizeof(buffer);
3565 res = RegEnumValueA( hkcr, 2, buffer, &size, NULL, NULL, NULL, NULL );
3566 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %ld\n", res );
3568 res = RegEnumKeyA( hkcr, 0, buffer, size );
3569 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %ld\n", res );
3570 ok(!strcmp( buffer, "A" ), "expected 'A', got '%s'\n", buffer);
3571 res = RegEnumKeyA( hkcr, 1, buffer, size );
3572 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %ld\n", res );
3573 ok(!strcmp( buffer, "B" ), "expected 'B', got '%s'\n", buffer);
3574 res = RegEnumKeyA( hkcr, 2, buffer, size );
3575 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %ld\n", res );
3577 /* prepare test env in HKLM */
3578 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", &hklm ))
3580 delete_key( hklm );
3581 RegCloseKey( hklm );
3584 res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", 0, NULL, 0,
3585 KEY_SET_VALUE|KEY_ENUMERATE_SUB_KEYS, NULL, &hklm, NULL );
3587 if (res == ERROR_ACCESS_DENIED)
3589 RegCloseKey( hkcusub[0] );
3590 RegCloseKey( hkcusub[1] );
3591 delete_key( hkcu );
3592 RegCloseKey( hkcu );
3593 RegCloseKey( hkcr );
3594 skip("not enough privileges to add a system class\n");
3595 return;
3598 res = RegSetValueExA( hklm, "X", 0, REG_SZ, (const BYTE *) "AB", 3 );
3599 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld\n", res);
3600 res = RegSetValueExA( hklm, "Z", 0, REG_SZ, (const BYTE *) "C", 2 );
3601 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %ld\n", res);
3602 res = RegCreateKeyA( hklm, "A", &hklmsub[0] );
3603 ok(res == ERROR_SUCCESS, "RegCreateKeyA failed: %ld\n", res);
3604 res = RegCreateKeyA( hklm, "C", &hklmsub[1] );
3605 ok(res == ERROR_SUCCESS, "RegCreateKeyA failed: %ld\n", res);
3607 /* test on values/keys in both HKCU and HKLM */
3608 size = sizeof(buffer);
3609 res = RegEnumValueA( hkcr, 0, buffer, &size, NULL, NULL, NULL, NULL );
3610 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %ld\n", res );
3611 ok(!strcmp( buffer, "X" ), "expected 'X', got '%s'\n", buffer);
3612 size = sizeof(buffer);
3613 res = RegEnumValueA( hkcr, 1, buffer, &size, NULL, NULL, NULL, NULL );
3614 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %ld\n", res );
3615 ok(!strcmp( buffer, "Y" ), "expected 'Y', got '%s'\n", buffer);
3616 size = sizeof(buffer);
3617 res = RegEnumValueA( hkcr, 2, buffer, &size, NULL, NULL, NULL, NULL );
3618 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %ld\n", res );
3619 ok(!strcmp( buffer, "Z" ), "expected 'Z', got '%s'\n", buffer);
3620 size = sizeof(buffer);
3621 res = RegEnumValueA( hkcr, 3, buffer, &size, NULL, NULL, NULL, NULL );
3622 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %ld\n", res );
3624 res = RegEnumKeyA( hkcr, 0, buffer, size );
3625 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %ld\n", res );
3626 ok(!strcmp( buffer, "A" ), "expected 'A', got '%s'\n", buffer);
3627 res = RegEnumKeyA( hkcr, 1, buffer, size );
3628 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %ld\n", res );
3629 ok(!strcmp( buffer, "B" ), "expected 'B', got '%s'\n", buffer);
3630 res = RegEnumKeyA( hkcr, 2, buffer, size );
3631 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %ld\n", res );
3632 ok(!strcmp( buffer, "C" ), "expected 'C', got '%s'\n", buffer);
3633 res = RegEnumKeyA( hkcr, 3, buffer, size );
3634 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %ld\n", res );
3636 /* delete values/keys from HKCU to test only on HKLM */
3637 RegCloseKey( hkcusub[0] );
3638 RegCloseKey( hkcusub[1] );
3639 delete_key( hkcu );
3640 RegCloseKey( hkcu );
3642 size = sizeof(buffer);
3643 res = RegEnumValueA( hkcr, 0, buffer, &size, NULL, NULL, NULL, NULL );
3644 ok(res == ERROR_KEY_DELETED ||
3645 res == ERROR_NO_SYSTEM_RESOURCES, /* Windows XP */
3646 "expected ERROR_KEY_DELETED, got %ld\n", res);
3647 size = sizeof(buffer);
3648 res = RegEnumKeyA( hkcr, 0, buffer, size );
3649 ok(res == ERROR_KEY_DELETED ||
3650 res == ERROR_NO_SYSTEM_RESOURCES, /* Windows XP */
3651 "expected ERROR_KEY_DELETED, got %ld\n", res);
3653 /* reopen HKCR handle */
3654 RegCloseKey( hkcr );
3655 res = RegOpenKeyA( HKEY_CLASSES_ROOT, "WineTestCls", &hkcr );
3656 ok(res == ERROR_SUCCESS, "test key not found in hkcr: %ld\n", res);
3657 if (res) goto cleanup;
3659 /* test on values/keys in HKLM */
3660 size = sizeof(buffer);
3661 res = RegEnumValueA( hkcr, 0, buffer, &size, NULL, NULL, NULL, NULL );
3662 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %ld\n", res );
3663 ok(!strcmp( buffer, "X" ), "expected 'X', got '%s'\n", buffer);
3664 size = sizeof(buffer);
3665 res = RegEnumValueA( hkcr, 1, buffer, &size, NULL, NULL, NULL, NULL );
3666 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %ld\n", res );
3667 ok(!strcmp( buffer, "Z" ), "expected 'Z', got '%s'\n", buffer);
3668 size = sizeof(buffer);
3669 res = RegEnumValueA( hkcr, 2, buffer, &size, NULL, NULL, NULL, NULL );
3670 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %ld\n", res );
3672 res = RegEnumKeyA( hkcr, 0, buffer, size );
3673 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %ld\n", res );
3674 ok(!strcmp( buffer, "A" ), "expected 'A', got '%s'\n", buffer);
3675 res = RegEnumKeyA( hkcr, 1, buffer, size );
3676 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %ld\n", res );
3677 ok(!strcmp( buffer, "C" ), "expected 'C', got '%s'\n", buffer);
3678 res = RegEnumKeyA( hkcr, 2, buffer, size );
3679 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %ld\n", res );
3681 cleanup:
3682 RegCloseKey( hklmsub[0] );
3683 RegCloseKey( hklmsub[1] );
3684 delete_key( hklm );
3685 RegCloseKey( hklm );
3686 RegCloseKey( hkcr );
3689 static void test_classesroot_mask(void)
3691 HKEY hkey;
3692 LSTATUS res;
3694 res = RegOpenKeyA( HKEY_CLASSES_ROOT, "CLSID", &hkey );
3695 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %ld\n", res);
3696 todo_wine ok(IS_HKCR(hkey) || broken(!IS_HKCR(hkey)) /* WinNT */,
3697 "hkcr mask not set in %p\n", hkey);
3698 RegCloseKey( hkey );
3700 res = RegOpenKeyA( HKEY_CURRENT_USER, "Software", &hkey );
3701 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %ld\n", res);
3702 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3703 RegCloseKey( hkey );
3705 res = RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software", &hkey );
3706 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %ld\n", res);
3707 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3708 RegCloseKey( hkey );
3710 res = RegOpenKeyA( HKEY_USERS, ".Default", &hkey );
3711 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %ld\n", res);
3712 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3713 RegCloseKey( hkey );
3715 res = RegOpenKeyA( HKEY_CURRENT_CONFIG, "Software", &hkey );
3716 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %ld\n", res);
3717 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3718 RegCloseKey( hkey );
3721 static void test_deleted_key(void)
3723 HKEY hkey, hkey2;
3724 char value[20];
3725 DWORD val_count, type;
3726 LONG res;
3728 /* Open the test key, then delete it while it's open */
3729 RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey );
3731 delete_key( hkey_main );
3733 val_count = sizeof(value);
3734 type = 0;
3735 res = RegEnumValueA( hkey, 0, value, &val_count, NULL, &type, 0, 0 );
3736 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %li\n", res);
3738 res = RegEnumKeyA( hkey, 0, value, sizeof(value) );
3739 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %li\n", res);
3741 val_count = sizeof(value);
3742 type = 0;
3743 res = RegQueryValueExA( hkey, "test", NULL, &type, (BYTE *)value, &val_count );
3744 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %li\n", res);
3746 res = RegSetValueExA( hkey, "test", 0, REG_SZ, (const BYTE*)"value", 6);
3747 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %li\n", res);
3749 res = RegOpenKeyA( hkey, "test", &hkey2 );
3750 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %li\n", res);
3751 if (res == 0)
3752 RegCloseKey( hkey2 );
3754 res = RegCreateKeyA( hkey, "test", &hkey2 );
3755 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %li\n", res);
3756 if (res == 0)
3757 RegCloseKey( hkey2 );
3759 res = RegFlushKey( hkey );
3760 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %li\n", res);
3762 RegCloseKey( hkey );
3764 setup_main_key();
3767 static void test_delete_value(void)
3769 LONG res;
3770 char longname[401];
3772 res = RegSetValueExA( hkey_main, "test", 0, REG_SZ, (const BYTE*)"value", 6 );
3773 ok(res == ERROR_SUCCESS, "expect ERROR_SUCCESS, got %li\n", res);
3775 res = RegQueryValueExA( hkey_main, "test", NULL, NULL, NULL, NULL);
3776 ok(res == ERROR_SUCCESS, "expect ERROR_SUCCESS, got %li\n", res);
3778 res = RegDeleteValueA( hkey_main, "test" );
3779 ok(res == ERROR_SUCCESS, "expect ERROR_SUCCESS, got %li\n", res);
3781 res = RegQueryValueExA( hkey_main, "test", NULL, NULL, NULL, NULL);
3782 ok(res == ERROR_FILE_NOT_FOUND, "expect ERROR_FILE_NOT_FOUND, got %li\n", res);
3784 res = RegDeleteValueA( hkey_main, "test" );
3785 ok(res == ERROR_FILE_NOT_FOUND, "expect ERROR_FILE_NOT_FOUND, got %li\n", res);
3787 memset(longname, 'a', 400);
3788 longname[400] = 0;
3789 res = RegDeleteValueA( hkey_main, longname );
3790 ok(res == ERROR_FILE_NOT_FOUND || broken(res == ERROR_MORE_DATA), /* nt4, win2k */
3791 "expect ERROR_FILE_NOT_FOUND, got %li\n", res);
3793 /* Default registry value */
3794 res = RegSetValueExA(hkey_main, "", 0, REG_SZ, (const BYTE *)"value", 6);
3795 ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", res);
3797 res = RegQueryValueExA(hkey_main, "", NULL, NULL, NULL, NULL);
3798 ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", res);
3800 res = RegDeleteValueA(hkey_main, "" );
3801 ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", res);
3803 res = RegQueryValueExA(hkey_main, "", NULL, NULL, NULL, NULL);
3804 ok(res == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %ld\n", res);
3807 static void test_delete_key_value(void)
3809 HKEY subkey;
3810 LONG ret;
3812 if (!pRegDeleteKeyValueA)
3814 win_skip("RegDeleteKeyValue is not available.\n");
3815 return;
3818 ret = pRegDeleteKeyValueA(NULL, NULL, NULL);
3819 ok(ret == ERROR_INVALID_HANDLE, "got %ld\n", ret);
3821 ret = pRegDeleteKeyValueA(hkey_main, NULL, NULL);
3822 ok(ret == ERROR_FILE_NOT_FOUND, "got %ld\n", ret);
3824 ret = RegSetValueExA(hkey_main, "test", 0, REG_SZ, (const BYTE*)"value", 6);
3825 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
3827 ret = RegQueryValueExA(hkey_main, "test", NULL, NULL, NULL, NULL);
3828 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
3830 /* NULL subkey name means delete from open key */
3831 ret = pRegDeleteKeyValueA(hkey_main, NULL, "test");
3832 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
3834 ret = RegQueryValueExA(hkey_main, "test", NULL, NULL, NULL, NULL);
3835 ok(ret == ERROR_FILE_NOT_FOUND, "got %ld\n", ret);
3837 /* now with real subkey */
3838 ret = RegCreateKeyExA(hkey_main, "Subkey1", 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &subkey, NULL);
3839 ok(!ret, "failed with error %ld\n", ret);
3841 ret = RegSetValueExA(subkey, "test", 0, REG_SZ, (const BYTE*)"value", 6);
3842 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
3844 ret = RegQueryValueExA(subkey, "test", NULL, NULL, NULL, NULL);
3845 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
3847 ret = pRegDeleteKeyValueA(hkey_main, "Subkey1", "test");
3848 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
3850 ret = RegQueryValueExA(subkey, "test", NULL, NULL, NULL, NULL);
3851 ok(ret == ERROR_FILE_NOT_FOUND, "got %ld\n", ret);
3853 /* Default registry value */
3854 ret = RegSetValueExA(subkey, "", 0, REG_SZ, (const BYTE *)"value", 6);
3855 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3857 ret = RegQueryValueExA(subkey, "", NULL, NULL, NULL, NULL);
3858 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3860 ret = pRegDeleteKeyValueA(hkey_main, "Subkey1", "" );
3861 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3863 ret = RegQueryValueExA(subkey, "", NULL, NULL, NULL, NULL);
3864 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %ld\n", ret);
3866 RegDeleteKeyA(subkey, "");
3867 RegCloseKey(subkey);
3870 static void test_RegOpenCurrentUser(void)
3872 HKEY key;
3873 LONG ret;
3875 key = HKEY_CURRENT_USER;
3876 ret = RegOpenCurrentUser(KEY_READ, &key);
3877 ok(!ret, "got %ld, error %ld\n", ret, GetLastError());
3878 ok(key != HKEY_CURRENT_USER, "got %p\n", key);
3879 RegCloseKey(key);
3882 struct notify_data {
3883 HKEY key;
3884 DWORD flags;
3885 HANDLE event;
3888 static DWORD WINAPI notify_change_thread(void *arg)
3890 struct notify_data *data = arg;
3891 LONG ret;
3893 ret = RegNotifyChangeKeyValue(data->key, TRUE,
3894 REG_NOTIFY_CHANGE_NAME|data->flags, data->event, TRUE);
3895 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3896 return 0;
3899 static void test_RegNotifyChangeKeyValue(void)
3901 struct notify_data data;
3902 HKEY key, subkey, subsubkey;
3903 HANDLE thread;
3904 HANDLE event;
3905 DWORD dwret;
3906 LONG ret;
3908 event = CreateEventW(NULL, FALSE, TRUE, NULL);
3909 ok(event != NULL, "CreateEvent failed, error %lu\n", GetLastError());
3910 ret = RegCreateKeyA(hkey_main, "TestKey", &key);
3911 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3913 ret = RegNotifyChangeKeyValue(key, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, event, TRUE);
3914 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3915 dwret = WaitForSingleObject(event, 0);
3916 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", dwret);
3918 ret = RegCreateKeyA(key, "SubKey", &subkey);
3919 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3920 dwret = WaitForSingleObject(event, 0);
3921 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", dwret);
3923 /* watching deeper keys */
3924 ret = RegNotifyChangeKeyValue(key, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, event, TRUE);
3925 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3926 dwret = WaitForSingleObject(event, 0);
3927 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", dwret);
3929 ret = RegCreateKeyA(subkey, "SubKey", &subsubkey);
3930 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3931 dwret = WaitForSingleObject(event, 0);
3932 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", dwret);
3934 /* watching deeper values */
3935 ret = RegNotifyChangeKeyValue(key, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, event, TRUE);
3936 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3937 dwret = WaitForSingleObject(event, 0);
3938 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", dwret);
3940 ret = RegSetValueA(subsubkey, NULL, REG_SZ, "SubSubKeyValue", 0);
3941 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3942 dwret = WaitForSingleObject(event, 0);
3943 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", dwret);
3945 /* don't watch deeper values */
3946 RegCloseKey(key);
3947 ret = RegOpenKeyA(hkey_main, "TestKey", &key);
3948 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3950 ret = RegNotifyChangeKeyValue(key, FALSE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, event, TRUE);
3951 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3952 dwret = WaitForSingleObject(event, 0);
3953 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", dwret);
3955 ret = RegSetValueA(subsubkey, NULL, REG_SZ, "SubSubKeyValueNEW", 0);
3956 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3957 dwret = WaitForSingleObject(event, 0);
3958 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", dwret);
3960 RegDeleteKeyA(subkey, "SubKey");
3961 RegDeleteKeyA(key, "SubKey");
3962 RegCloseKey(subsubkey);
3963 RegCloseKey(subkey);
3964 RegCloseKey(key);
3966 /* test same thread with REG_NOTIFY_THREAD_AGNOSTIC */
3967 ret = RegOpenKeyA(hkey_main, "TestKey", &key);
3968 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3969 ret = RegNotifyChangeKeyValue(key, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_THREAD_AGNOSTIC,
3970 event, TRUE);
3971 if (ret == ERROR_INVALID_PARAMETER)
3973 win_skip("REG_NOTIFY_THREAD_AGNOSTIC is not supported\n");
3974 RegCloseKey(key);
3975 CloseHandle(event);
3976 return;
3979 ret = RegCreateKeyA(key, "SubKey", &subkey);
3980 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3981 dwret = WaitForSingleObject(event, 0);
3982 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", dwret);
3984 RegDeleteKeyA(key, "SubKey");
3985 RegCloseKey(subkey);
3986 RegCloseKey(key);
3988 /* test different thread without REG_NOTIFY_THREAD_AGNOSTIC */
3989 ret = RegOpenKeyA(hkey_main, "TestKey", &key);
3990 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
3992 data.key = key;
3993 data.flags = 0;
3994 data.event = event;
3995 thread = CreateThread(NULL, 0, notify_change_thread, &data, 0, NULL);
3996 WaitForSingleObject(thread, INFINITE);
3997 CloseHandle(thread);
3999 /* the thread exiting causes event to signal on Windows
4000 this is worked around on Windows using REG_NOTIFY_THREAD_AGNOSTIC
4001 Wine already behaves as if the flag is set */
4002 dwret = WaitForSingleObject(event, 0);
4003 todo_wine
4004 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", dwret);
4005 RegCloseKey(key);
4007 /* test different thread with REG_NOTIFY_THREAD_AGNOSTIC */
4008 ret = RegOpenKeyA(hkey_main, "TestKey", &key);
4009 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
4011 data.flags = REG_NOTIFY_THREAD_AGNOSTIC;
4012 thread = CreateThread(NULL, 0, notify_change_thread, &data, 0, NULL);
4013 WaitForSingleObject(thread, INFINITE);
4014 CloseHandle(thread);
4016 dwret = WaitForSingleObject(event, 0);
4017 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", dwret);
4019 ret = RegCreateKeyA(key, "SubKey", &subkey);
4020 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
4022 dwret = WaitForSingleObject(event, 0);
4023 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", dwret);
4025 RegDeleteKeyA(key, "SubKey");
4026 RegDeleteKeyA(key, "");
4027 RegCloseKey(subkey);
4028 RegCloseKey(key);
4029 CloseHandle(event);
4032 static const char *find_counter_value(const char *text, const char *index)
4034 const char *p = text;
4036 while (*p)
4038 if (!strcmp(p, index))
4039 return p + strlen(p) + 1;
4041 p += strlen(p) + 1;
4042 p += strlen(p) + 1;
4045 return NULL;
4048 static void test_counter_values(const char *text, HKEY key)
4050 const char *p = text;
4051 const char *name;
4053 ok(!strcmp(p, "1"), "got first index %s\n", debugstr_a(p));
4054 p += strlen(p) + 1;
4055 ok(!strcmp(p, "1847"), "got first name %s\n", debugstr_a(p));
4056 p += strlen(p) + 1;
4058 while (*p)
4060 unsigned int index = atoi(p);
4062 ok(index > 0, "expected nonzero index\n");
4064 p += strlen(p) + 1;
4065 ok(*p, "name missing for %u\n", index);
4066 p += strlen(p) + 1;
4069 name = find_counter_value(text, "1846");
4070 ok(name != NULL, "did not find name\n");
4071 if (key != HKEY_PERFORMANCE_NLSTEXT)
4072 ok(!strcmp(name, "End Marker"), "got name %s\n", debugstr_a(name));
4075 static void test_help_values(const char *text, HKEY key)
4077 const char *p = text;
4078 const char *name;
4080 while (*p)
4082 unsigned int index = atoi(p);
4084 ok(index > 0, "expected nonzero index\n");
4086 p += strlen(p) + 1;
4087 p += strlen(p) + 1;
4090 name = find_counter_value(text, "1847");
4091 ok(name != NULL, "did not find name\n");
4092 if (key != HKEY_PERFORMANCE_NLSTEXT)
4093 ok(!strcmp(name, "End Marker"), "got name %s\n", debugstr_a(name));
4096 static void test_performance_keys(void)
4098 static const HKEY keys[] = {HKEY_PERFORMANCE_DATA, HKEY_PERFORMANCE_TEXT, HKEY_PERFORMANCE_NLSTEXT};
4099 static const char *const names[] = {NULL, "", "Global", "2", "invalid counter name", "System"};
4100 DWORD size, type, sysname_len, expect_size, key_count, value_count;
4101 LARGE_INTEGER perftime1, perftime2, systime1, systime2, freq;
4102 WCHAR sysname[MAX_COMPUTERNAME_LENGTH + 1];
4103 unsigned int buffer_size = 1024 * 1024;
4104 void *buffer, *bufferW;
4105 PERF_DATA_BLOCK *data;
4106 union
4108 FILETIME f;
4109 LONGLONG l;
4110 } file_time;
4111 unsigned int i, j;
4112 HKEY key;
4113 LONG ret;
4115 buffer = malloc(buffer_size);
4117 sysname_len = ARRAY_SIZE(sysname);
4118 GetComputerNameW(sysname, &sysname_len);
4120 for (i = 0; i < ARRAY_SIZE(keys); ++i)
4122 winetest_push_context("key %p", keys[i]);
4124 for (j = 0; j < ARRAY_SIZE(names); ++j)
4126 winetest_push_context("value %s", debugstr_a(names[j]));
4128 QueryPerformanceFrequency(&freq);
4130 size = 0;
4131 ret = RegQueryValueExA(keys[i], names[j], NULL, NULL, NULL, &size);
4132 ok(ret == ERROR_MORE_DATA, "got %lu\n", ret);
4133 ok(!size, "got size %lu\n", size);
4135 size = 10;
4136 ret = RegQueryValueExA(keys[i], names[j], NULL, NULL, buffer, &size);
4137 ok(ret == ERROR_MORE_DATA, "got %lu\n", ret);
4138 todo_wine
4139 ok(size == 10, "got size %lu\n", size);
4141 size = buffer_size;
4142 ret = RegQueryValueExA(keys[i], names[j], NULL, NULL, NULL, &size);
4143 ok(ret == ERROR_MORE_DATA, "got %lu\n", ret);
4145 QueryPerformanceCounter(&perftime1);
4146 NtQuerySystemTime(&systime1);
4148 size = buffer_size;
4149 type = 0xdeadbeef;
4150 ret = RegQueryValueExA(keys[i], names[j], NULL, &type, buffer, &size);
4151 ok(!ret, "got %lu\n", ret);
4152 ok(type == REG_BINARY, "got type %lu\n", type);
4153 ok(size >= sizeof(PERF_DATA_BLOCK) && size < buffer_size, "got size %lu\n", size);
4155 QueryPerformanceCounter(&perftime2);
4156 NtQuerySystemTime(&systime2);
4158 data = buffer;
4159 ok(!wcsncmp(data->Signature, L"PERF", 4), "got signature %s\n",
4160 debugstr_wn(data->Signature, 4));
4161 ok(data->LittleEndian == 1, "got endianness %lu\n", data->LittleEndian);
4162 ok(data->Version == 1, "got version %lu\n", data->Version);
4163 ok(data->Revision == 1, "got version %lu\n", data->Revision);
4164 ok(data->TotalByteLength == size, "expected size %lu, got %lu\n",
4165 size, data->TotalByteLength);
4167 expect_size = sizeof(PERF_DATA_BLOCK) + data->SystemNameLength;
4168 expect_size = (expect_size + 7) & ~7;
4170 ok(data->HeaderLength == expect_size, "expected header size %lu, got %lu\n",
4171 expect_size, data->HeaderLength);
4172 /* todo: test objects... */
4173 todo_wine ok(data->DefaultObject == 238, "got default object %lu\n", data->DefaultObject);
4175 ok(data->PerfTime.QuadPart >= perftime1.QuadPart
4176 && data->PerfTime.QuadPart <= perftime2.QuadPart,
4177 "got times %I64d, %I64d, %I64d\n",
4178 perftime1.QuadPart, data->PerfTime.QuadPart, perftime2.QuadPart);
4179 ok(data->PerfFreq.QuadPart == freq.QuadPart, "expected frequency %I64d, got %I64d\n",
4180 freq.QuadPart, data->PerfFreq.QuadPart);
4181 ok(data->PerfTime100nSec.QuadPart >= systime1.QuadPart
4182 && data->PerfTime100nSec.QuadPart <= systime2.QuadPart,
4183 "got times %I64d, %I64d, %I64d\n",
4184 systime1.QuadPart, data->PerfTime100nSec.QuadPart, systime2.QuadPart);
4185 SystemTimeToFileTime(&data->SystemTime, &file_time.f);
4186 /* SYSTEMTIME has a granularity of 1 ms */
4187 ok(file_time.l >= systime1.QuadPart - 10000 && file_time.l <= systime2.QuadPart,
4188 "got times %I64d, %I64d, %I64d\n", systime1.QuadPart, file_time.l, systime2.QuadPart);
4190 ok(data->SystemNameLength == (sysname_len + 1) * sizeof(WCHAR),
4191 "expected name len %Iu, got %lu\n",
4192 (sysname_len + 1) * sizeof(WCHAR), data->SystemNameLength);
4193 ok(data->SystemNameOffset == sizeof(PERF_DATA_BLOCK),
4194 "got name offset %lu\n", data->SystemNameOffset);
4195 ok(!wcscmp(sysname, (const WCHAR *)(data + 1)), "expected name %s, got %s\n",
4196 debugstr_w(sysname), debugstr_w((const WCHAR *)(data + 1)));
4198 winetest_pop_context();
4201 /* test the "Counter" value */
4203 size = 0xdeadbeef;
4204 ret = RegQueryValueExA(keys[i], "cOuNtEr", NULL, NULL, NULL, &size);
4205 ok(!ret, "got %lu\n", ret);
4206 ok(size > 0 && size < 0xdeadbeef, "got size %lu\n", size);
4208 type = 0xdeadbeef;
4209 size = 0;
4210 ret = RegQueryValueExA(keys[i], "cOuNtEr", NULL, &type, buffer, &size);
4211 ok(ret == ERROR_MORE_DATA, "got %lu\n", ret);
4212 ok(size > 0, "got size %lu\n", size);
4214 type = 0xdeadbeef;
4215 size = buffer_size;
4216 ret = RegQueryValueExA(keys[i], "cOuNtEr", NULL, &type, buffer, &size);
4217 ok(!ret, "got %lu\n", ret);
4218 ok(type == REG_MULTI_SZ, "got type %lu\n", type);
4219 test_counter_values(buffer, keys[i]);
4221 type = 0xdeadbeef;
4222 size = buffer_size;
4223 ret = RegQueryValueExA(keys[i], "cOuNtErwine", NULL, &type, buffer, &size);
4224 ok(!ret, "got %lu\n", ret);
4225 ok(type == REG_MULTI_SZ, "got type %lu\n", type);
4226 test_counter_values(buffer, keys[i]);
4228 size = 0;
4229 ret = RegQueryValueExW(keys[i], L"cOuNtEr", NULL, NULL, NULL, &size);
4230 ok(!ret, "got %lu\n", ret);
4231 ok(size > 0, "got size %lu\n", size);
4233 bufferW = malloc(size);
4235 type = 0xdeadbeef;
4236 ret = RegQueryValueExW(keys[i], L"cOuNtEr", NULL, &type, bufferW, &size);
4237 ok(!ret, "got %lu\n", ret);
4238 ok(type == REG_MULTI_SZ, "got type %lu\n", type);
4239 WideCharToMultiByte(CP_ACP, 0, bufferW, size / sizeof(WCHAR), buffer, buffer_size, NULL, NULL);
4240 test_counter_values(buffer, keys[i]);
4242 /* test the "Help" value */
4244 size = 0xdeadbeef;
4245 ret = RegQueryValueExA(keys[i], "hElP", NULL, NULL, NULL, &size);
4246 ok(!ret, "got %lu\n", ret);
4247 ok(size > 0 && size < 0xdeadbeef, "got size %lu\n", size);
4249 type = 0xdeadbeef;
4250 size = 0;
4251 ret = RegQueryValueExA(keys[i], "hElP", NULL, &type, buffer, &size);
4252 ok(ret == ERROR_MORE_DATA, "got %lu\n", ret);
4253 ok(size > 0, "got size %lu\n", size);
4255 type = 0xdeadbeef;
4256 size = buffer_size;
4257 ret = RegQueryValueExA(keys[i], "hElP", NULL, &type, buffer, &size);
4258 test_help_values(buffer, keys[i]);
4260 type = 0xdeadbeef;
4261 size = buffer_size;
4262 ret = RegQueryValueExA(keys[i], "hElPwine", NULL, &type, buffer, &size);
4263 ok(!ret, "got %lu\n", ret);
4264 ok(type == REG_MULTI_SZ, "got type %lu\n", type);
4265 test_help_values(buffer, keys[i]);
4267 size = 0;
4268 ret = RegQueryValueExW(keys[i], L"hElP", NULL, NULL, NULL, &size);
4269 ok(!ret, "got %lu\n", ret);
4270 ok(size > 0, "got size %lu\n", size);
4272 bufferW = malloc(size);
4274 type = 0xdeadbeef;
4275 ret = RegQueryValueExW(keys[i], L"hElP", NULL, &type, bufferW, &size);
4276 ok(!ret, "got %lu\n", ret);
4277 ok(type == REG_MULTI_SZ, "got type %lu\n", type);
4278 WideCharToMultiByte(CP_ACP, 0, bufferW, size / sizeof(WCHAR), buffer, buffer_size, NULL, NULL);
4279 test_help_values(buffer, keys[i]);
4281 /* test other registry APIs */
4283 ret = RegOpenKeyA(keys[i], NULL, &key);
4284 todo_wine ok(ret == ERROR_INVALID_HANDLE, "got %lu\n", ret);
4286 ret = RegOpenKeyA(keys[i], "Global", &key);
4287 ok(ret == ERROR_INVALID_HANDLE, "got %lu\n", ret);
4289 ret = RegOpenKeyExA(keys[i], "Global", 0, KEY_READ, &key);
4290 ok(ret == ERROR_INVALID_HANDLE, "got %lu\n", ret);
4292 size = 0;
4293 ret = RegQueryValueA(keys[i], "Global", NULL, (LONG *)&size);
4294 ok(ret == ERROR_INVALID_HANDLE, "got %lu\n", ret);
4296 ret = RegSetValueA(keys[i], "Global", REG_SZ, "dummy", 5);
4297 ok(ret == ERROR_INVALID_HANDLE, "got %lu\n", ret);
4299 key_count = 0x900ddeed;
4300 ret = RegQueryInfoKeyA(keys[i], NULL, NULL, NULL, &key_count, NULL,
4301 NULL, &value_count, NULL, NULL, NULL, NULL);
4302 todo_wine ok(!ret, "got %lu\n", ret);
4303 todo_wine ok(!key_count, "got %lu subkeys\n", key_count);
4304 todo_wine ok(value_count == 2, "got %lu values\n", value_count);
4306 size = buffer_size;
4307 ret = RegEnumValueA(keys[i], 0, buffer, &size, NULL, NULL, NULL, NULL);
4308 todo_wine ok(ret == ERROR_MORE_DATA, "got %lu\n", ret);
4309 ok(size == buffer_size, "got size %lu\n", size);
4311 ret = RegCloseKey(keys[i]);
4312 ok(!ret, "got %lu\n", ret);
4314 ret = RegCloseKey(keys[i]);
4315 ok(!ret, "got %lu\n", ret);
4317 winetest_pop_context();
4320 ret = RegSetValueExA(HKEY_PERFORMANCE_DATA, "Global", 0, REG_SZ, (const BYTE *)"dummy", 5);
4321 ok(ret == ERROR_INVALID_HANDLE, "got %lu\n", ret);
4323 ret = RegSetValueExA(HKEY_PERFORMANCE_TEXT, "Global", 0, REG_SZ, (const BYTE *)"dummy", 5);
4324 todo_wine ok(ret == ERROR_BADKEY, "got %lu\n", ret);
4326 ret = RegSetValueExA(HKEY_PERFORMANCE_NLSTEXT, "Global", 0, REG_SZ, (const BYTE *)"dummy", 5);
4327 todo_wine ok(ret == ERROR_BADKEY, "got %lu\n", ret);
4329 if (pRegSetKeyValueW)
4331 ret = pRegSetKeyValueW(HKEY_PERFORMANCE_DATA, NULL, L"Global", REG_SZ, L"dummy", 10);
4332 ok(ret == ERROR_INVALID_HANDLE, "got %lu\n", ret);
4334 ret = pRegSetKeyValueW(HKEY_PERFORMANCE_TEXT, NULL, L"Global", REG_SZ, L"dummy", 10);
4335 todo_wine ok(ret == ERROR_BADKEY, "got %lu\n", ret);
4337 ret = pRegSetKeyValueW(HKEY_PERFORMANCE_NLSTEXT, NULL, L"Global", REG_SZ, L"dummy", 10);
4338 todo_wine ok(ret == ERROR_BADKEY, "got %lu\n", ret);
4341 ret = RegEnumKeyA(HKEY_PERFORMANCE_DATA, 0, buffer, buffer_size);
4342 ok(ret == ERROR_INVALID_HANDLE, "got %lu\n", ret);
4344 ret = RegEnumKeyA(HKEY_PERFORMANCE_TEXT, 0, buffer, buffer_size);
4345 todo_wine ok(ret == ERROR_NO_MORE_ITEMS, "got %lu\n", ret);
4347 ret = RegEnumKeyA(HKEY_PERFORMANCE_NLSTEXT, 0, buffer, buffer_size);
4348 todo_wine ok(ret == ERROR_NO_MORE_ITEMS, "got %lu\n", ret);
4350 free(buffer);
4353 static void test_perflib_key(void)
4355 unsigned int primary_lang = PRIMARYLANGID(GetUserDefaultLangID());
4356 unsigned int buffer_size = 1024 * 1024;
4357 OBJECT_NAME_INFORMATION *name_info;
4358 HKEY perflib_key, key, key2;
4359 OBJECT_ATTRIBUTES attr;
4360 UNICODE_STRING string;
4361 char lang_name[5];
4362 const char *knames[2] = {"009", "CurrentLanguage"};
4363 char *buffer;
4364 DWORD size;
4365 LONG ret, l;
4367 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
4368 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Perflib", 0, KEY_READ, &perflib_key);
4369 ok(!ret, "got %lu\n", ret);
4371 ret = RegOpenKeyExA(perflib_key, "009", 0, KEY_READ, &key);
4372 ok(!ret, "got %lu\n", ret);
4373 /* English always returns TEXT; most other languages return NLSTEXT, but
4374 * some (e.g. Hindi) return TEXT */
4375 ok(key == HKEY_PERFORMANCE_TEXT || key == HKEY_PERFORMANCE_NLSTEXT, "got key %p\n", key);
4377 ret = RegCloseKey(key);
4378 ok(!ret, "got %lu\n", ret);
4380 RtlInitUnicodeString(&string, L"009");
4381 InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE, perflib_key, NULL);
4382 ret = NtOpenKey((HANDLE *)&key, KEY_ALL_ACCESS, &attr);
4383 ok(ret == STATUS_PREDEFINED_HANDLE || ret == STATUS_ACCESS_DENIED
4384 || ret == STATUS_SUCCESS /* Win < 7 */, "got %#lx\n", ret);
4385 if (ret == STATUS_PREDEFINED_HANDLE)
4386 ok(!is_special_key(key), "expected a normal handle, got %p\n", key);
4387 else if (ret == STATUS_SUCCESS)
4388 ok(key == HKEY_PERFORMANCE_TEXT, "got key %p\n", key);
4389 else
4391 skip("Not enough permissions to test the perflib key.\n");
4392 RegCloseKey(perflib_key);
4393 return;
4396 buffer = malloc(buffer_size);
4398 ret = NtQueryKey(key, KeyFullInformation, buffer, buffer_size, &size);
4399 ok(ret == STATUS_INVALID_HANDLE, "got %#lx\n", ret);
4401 ret = NtEnumerateKey(key, 0, KeyFullInformation, buffer, buffer_size, &size);
4402 ok(ret == STATUS_INVALID_HANDLE, "got %#lx\n", ret);
4404 RtlInitUnicodeString(&string, L"counter");
4405 ret = NtQueryValueKey(key, &string, KeyValuePartialInformation, buffer, buffer_size, &size);
4406 ok(ret == STATUS_INVALID_HANDLE, "got %#lx\n", ret);
4408 ret = NtEnumerateValueKey(key, 0, KeyValuePartialInformation, buffer, buffer_size, &size);
4409 ok(ret == STATUS_INVALID_HANDLE, "got %#lx\n", ret);
4411 ret = NtSetValueKey(key, &string, 0, REG_SZ, "test", 5);
4412 ok(ret == STATUS_INVALID_HANDLE, "got %#lx\n", ret);
4414 ret = NtDeleteValueKey(key, &string);
4415 ok(ret == STATUS_INVALID_HANDLE, "got %#lx\n", ret);
4417 ret = NtDeleteKey(key);
4418 ok(ret == STATUS_INVALID_HANDLE, "got %#lx\n", ret);
4420 RtlInitUnicodeString(&string, L"subkey");
4421 InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE, key, NULL);
4422 ret = NtOpenKey((HANDLE *)&key2, KEY_READ, &attr);
4423 if (is_special_key(key))
4424 ok(ret == STATUS_INVALID_HANDLE, "got %#lx\n", ret);
4425 else
4426 ok(ret == STATUS_OBJECT_NAME_NOT_FOUND
4427 || broken(ret == STATUS_INVALID_HANDLE) /* WoW64 */, "got %#lx\n", ret);
4429 ret = NtCreateKey((HANDLE *)&key2, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL);
4430 if (is_special_key(key))
4431 ok(ret == STATUS_INVALID_HANDLE, "got %#lx\n", ret);
4432 else
4433 ok(!ret || broken(ret == STATUS_ACCESS_DENIED) /* w8adm */
4434 || broken(ret == STATUS_INVALID_HANDLE) /* WoW64 */, "got %#lx\n", ret);
4435 if (!ret)
4437 NtDeleteKey(key2);
4438 NtClose(key2);
4441 /* it's a real handle, though */
4442 ret = NtQueryObject(key, ObjectNameInformation, buffer, buffer_size, &size);
4443 if (is_special_key(key))
4444 ok(ret == STATUS_INVALID_HANDLE, "got %#lx\n", ret);
4445 else
4446 ok(!ret, "got %#lx\n", ret);
4447 if (!ret)
4449 name_info = (OBJECT_NAME_INFORMATION *)buffer;
4450 ok(!wcsicmp(name_info->Name.Buffer, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT"
4451 "\\CurrentVersion\\Perflib\\009"), "got name %s\n", debugstr_w(name_info->Name.Buffer));
4454 ret = NtClose(key);
4455 if (is_special_key(key))
4456 ok(ret == STATUS_INVALID_HANDLE, "got %#lx\n", ret);
4457 else
4458 ok(!ret, "got %#lx\n", ret);
4460 for (l = 0; l < ARRAY_SIZE(knames); l++)
4462 winetest_push_context("%ld", l);
4463 todo_wine_if(l == 1) {
4464 ret = RegOpenKeyExA(perflib_key, knames[l], 0, KEY_READ, &key);
4465 ok(!ret, "got %lu\n", ret);
4466 if (is_special_key(key))
4468 size = buffer_size;
4469 ret = RegQueryValueExA(key, "counter", NULL, NULL, (BYTE *)buffer, &size);
4470 ok(!ret, "got %lu\n", ret);
4471 if (!ret)
4473 char *str;
4474 int c = 0;
4475 for (str = buffer; *str; str += strlen(str) + 1)
4476 c++;
4477 /* Note that the two keys may not have the same number of
4478 * entries if they are in different languages.
4480 ok(c >= 2 && (c % 2) == 0, "%d is not a valid number of entries in %s\n", c, knames[l]);
4481 trace("%s has %d entries\n", knames[l], c);
4484 else
4486 /* Windows 7 does not always return a special key for 009
4487 * when running without elevated privileges.
4489 ok(broken(l == 0), "expected a special handle, got %p\n", key);
4492 ret = RegCloseKey(key);
4493 ok(!ret, "got %lu\n", ret);
4495 winetest_pop_context();
4498 /* multilingual support was not really completely thought through */
4499 switch (primary_lang)
4501 case LANG_PORTUGUESE:
4502 case LANG_CHINESE:
4503 sprintf(lang_name, "%04x", GetUserDefaultLangID());
4504 break;
4505 default:
4506 sprintf(lang_name, "%03x", primary_lang);
4507 break;
4509 if (primary_lang != LANG_ENGLISH &&
4510 !RegOpenKeyExA(perflib_key, lang_name, 0, KEY_READ, &key))
4512 ok(!is_special_key(key), "expected a normal handle, got %p\n", key);
4514 size = buffer_size;
4515 ret = RegQueryValueExA(key, "counter", NULL, NULL, (BYTE *)buffer, &size);
4516 todo_wine ok(ret == ERROR_FILE_NOT_FOUND, "got %lu\n", ret);
4518 ret = RegCloseKey(key);
4519 todo_wine ok(!ret, "got %lu\n", ret);
4521 /* else some languages don't have their own key. The keys are not really
4522 * usable anyway so assume it does not really matter.
4525 ret = RegCloseKey(perflib_key);
4526 ok(!ret, "got %lu\n", ret);
4528 RtlInitUnicodeString(&string, L"\\Registry\\PerfData");
4529 InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE, NULL, NULL);
4530 ret = NtOpenKey((HANDLE *)&key, KEY_READ, &attr);
4531 ok(ret == STATUS_OBJECT_NAME_NOT_FOUND, "got %#lx\n", ret);
4533 free(buffer);
4536 static void test_RegLoadMUIString(void)
4538 HMODULE hUser32, hResDll, hFile;
4539 int (WINAPI *pLoadStringW)(HMODULE, UINT, WCHAR *, int);
4540 LONG ret;
4541 HKEY hkey;
4542 DWORD type, size, text_size;
4543 UINT i;
4544 char buf[64], *p, sysdir[MAX_PATH];
4545 char with_env_var[128], filename[MAX_PATH], tmp_path[MAX_PATH];
4546 WCHAR textW[64], bufW[64];
4547 WCHAR curdirW[MAX_PATH], sysdirW[MAX_PATH];
4548 const static char tz_value[] = "MUI_Std";
4549 const static WCHAR tz_valueW[] = L"MUI_Std";
4550 struct {
4551 const char* value;
4552 DWORD type;
4553 BOOL use_sysdir;
4554 DWORD expected;
4555 DWORD broken_ret;
4556 } test_case[] = {
4557 /* 0 */
4558 { "", REG_SZ, FALSE, ERROR_INVALID_DATA },
4559 { "not a MUI string", REG_SZ, FALSE, ERROR_INVALID_DATA },
4560 { "@unknown.dll", REG_SZ, TRUE, ERROR_INVALID_DATA },
4561 { "@unknown.dll,-10", REG_SZ, TRUE, ERROR_FILE_NOT_FOUND },
4562 /* 4 */
4563 { with_env_var, REG_SZ, FALSE, ERROR_SUCCESS },
4564 { with_env_var, REG_EXPAND_SZ, FALSE, ERROR_SUCCESS },
4565 { "%WineMuiTest1%", REG_EXPAND_SZ, TRUE, ERROR_INVALID_DATA },
4566 { "@%WineMuiTest2%", REG_EXPAND_SZ, TRUE, ERROR_SUCCESS },
4567 /* 8 */
4568 { "@%WineMuiExe%,a", REG_SZ, FALSE, ERROR_INVALID_DATA },
4569 { "@%WineMuiExe%,-4", REG_SZ, FALSE, ERROR_NOT_FOUND, ERROR_FILE_NOT_FOUND },
4570 { "@%WineMuiExe%,-39", REG_SZ, FALSE, ERROR_RESOURCE_NAME_NOT_FOUND },
4571 { "@%WineMuiDat%,-16", REG_EXPAND_SZ, FALSE, ERROR_BAD_EXE_FORMAT, ERROR_FILE_NOT_FOUND },
4574 if (!pRegLoadMUIStringA || !pRegLoadMUIStringW)
4576 win_skip("RegLoadMUIString is not available\n");
4577 return;
4580 hUser32 = LoadLibraryA("user32.dll");
4581 ok(hUser32 != NULL, "cannot load user32.dll\n");
4582 pLoadStringW = (void *)GetProcAddress(hUser32, "LoadStringW");
4583 ok(pLoadStringW != NULL, "failed to get LoadStringW address\n");
4585 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
4586 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\UTC", 0,
4587 KEY_READ, &hkey);
4588 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
4590 size = ARRAY_SIZE(buf);
4591 ret = RegQueryValueExA(hkey, tz_value, NULL, &type, (BYTE *)buf, &size);
4592 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
4593 ok(buf[0] == '@', "got %s\n", buf);
4595 /* setup MUI string for tests */
4596 strcpy(with_env_var, "@%windir%\\system32\\");
4597 strcat(with_env_var, &buf[1]);
4598 SetEnvironmentVariableA("WineMuiTest1", buf);
4599 SetEnvironmentVariableA("WineMuiTest2", &buf[1]);
4601 /* load expecting text */
4602 p = strrchr(buf, ',');
4603 *p = '\0';
4604 i = atoi(p + 2); /* skip ',-' */
4605 hResDll = LoadLibraryExA(&buf[1], NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
4606 memset(textW, 0xaa, sizeof(textW));
4607 ret = pLoadStringW(hResDll, i, textW, ARRAY_SIZE(textW));
4608 ok(ret > 0, "failed to load string resource\n");
4609 text_size = (ret + 1) * sizeof(WCHAR);
4610 FreeLibrary(hResDll);
4611 FreeLibrary(hUser32);
4613 ret = GetSystemDirectoryW(sysdirW, ARRAY_SIZE(sysdirW));
4614 ok(ret > 0, "GetSystemDirectoryW failed\n");
4615 ret = GetSystemDirectoryA(sysdir, ARRAY_SIZE(sysdir));
4616 ok(ret > 0, "GetSystemDirectoryA failed\n");
4618 /* change the current directory to system32 */
4619 GetCurrentDirectoryW(ARRAY_SIZE(curdirW), curdirW);
4620 SetCurrentDirectoryW(sysdirW);
4622 size = 0xdeadbeef;
4623 ret = pRegLoadMUIStringW(hkey, tz_valueW, NULL, 0, &size, 0, NULL);
4624 ok(ret == ERROR_MORE_DATA, "got %ld, expected ERROR_MORE_DATA\n", ret);
4625 ok(size == text_size, "got %lu, expected %lu\n", size, text_size);
4627 memset(bufW, 0xff, sizeof(bufW));
4628 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)+1, &size, 0, NULL);
4629 ok(ret == ERROR_INVALID_PARAMETER, "got %ld, expected ERROR_INVALID_PARAMETER\n", ret);
4630 ok(bufW[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW[0]);
4632 size = 0xdeadbeef;
4633 memset(bufW, 0xff, sizeof(bufW));
4634 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)*2, &size, 0, NULL);
4635 ok(ret == ERROR_MORE_DATA, "got %ld, expected ERROR_MORE_DATA\n", ret);
4636 ok(size == text_size || broken(size == text_size + sizeof(WCHAR) /* vista */),
4637 "got %lu, expected %lu\n", size, text_size);
4638 ok(bufW[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW[0]);
4640 memset(bufW, 0xff, sizeof(bufW));
4641 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)*2, &size, REG_MUI_STRING_TRUNCATE, NULL);
4642 ok(ret == ERROR_INVALID_PARAMETER, "got %ld, expected ERROR_INVALID_PARAMETER\n", ret);
4643 ok(bufW[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW[0]);
4645 memset(bufW, 0xff, sizeof(bufW));
4646 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)*2, NULL, 0xdeadbeef, NULL);
4647 ok(ret == ERROR_INVALID_PARAMETER, "got %ld, expected ERROR_INVALID_PARAMETER\n", ret);
4648 ok(bufW[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW[0]);
4650 memset(bufW, 0xff, sizeof(bufW));
4651 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)*2, NULL, REG_MUI_STRING_TRUNCATE, NULL);
4652 ok(ret == ERROR_SUCCESS, "got %ld, expected ERROR_SUCCESS\n", ret);
4653 ok(bufW[0] == textW[0], "got 0x%04x, expected 0x%04x\n", bufW[0], textW[0]);
4654 ok(bufW[1] == 0, "got 0x%04x, expected nul\n", bufW[1]);
4656 size = 0xdeadbeef;
4657 memset(bufW, 0xff, sizeof(bufW));
4658 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, ARRAY_SIZE(bufW), &size, 0, NULL);
4659 ok(ret == ERROR_SUCCESS, "got %ld, expected ERROR_SUCCESS\n", ret);
4660 ok(size == text_size, "got %lu, expected %lu\n", size, text_size);
4661 ok(!memcmp(textW, bufW, size), "got %s, expected %s\n",
4662 wine_dbgstr_wn(bufW, size / sizeof(WCHAR)), wine_dbgstr_wn(textW, text_size / sizeof(WCHAR)));
4664 ret = pRegLoadMUIStringA(hkey, tz_value, buf, ARRAY_SIZE(buf), &size, 0, NULL);
4665 ok(ret == ERROR_CALL_NOT_IMPLEMENTED, "got %ld, expected ERROR_CALL_NOT_IMPLEMENTED\n", ret);
4667 /* change the current directory to other than system32 directory */
4668 SetCurrentDirectoryA("\\");
4670 size = 0xdeadbeef;
4671 memset(bufW, 0xff, sizeof(bufW));
4672 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, ARRAY_SIZE(bufW), &size, 0, sysdirW);
4673 ok(ret == ERROR_SUCCESS, "got %ld, expected ERROR_SUCCESS\n", ret);
4674 ok(size == text_size, "got %lu, expected %lu\n", size, text_size);
4675 ok(!memcmp(textW, bufW, size), "got %s, expected %s\n",
4676 wine_dbgstr_wn(bufW, size / sizeof(WCHAR)), wine_dbgstr_wn(textW, text_size / sizeof(WCHAR)));
4678 ret = pRegLoadMUIStringA(hkey, tz_value, buf, ARRAY_SIZE(buf), &size, 0, sysdir);
4679 ok(ret == ERROR_CALL_NOT_IMPLEMENTED, "got %ld, expected ERROR_CALL_NOT_IMPLEMENTED\n", ret);
4681 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, ARRAY_SIZE(bufW), &size, 0, NULL);
4682 ok(ret == ERROR_FILE_NOT_FOUND, "got %ld, expected ERROR_FILE_NOT_FOUND\n", ret);
4684 ret = pRegLoadMUIStringA(hkey, tz_value, buf, ARRAY_SIZE(buf), &size, 0, NULL);
4685 ok(ret == ERROR_CALL_NOT_IMPLEMENTED, "got %ld, expected ERROR_CALL_NOT_IMPLEMENTED\n", ret);
4687 RegCloseKey(hkey);
4689 GetModuleFileNameA(NULL, filename, ARRAY_SIZE(filename));
4690 SetEnvironmentVariableA("WineMuiExe", filename);
4692 GetTempPathA(ARRAY_SIZE(tmp_path), tmp_path);
4693 GetTempFileNameA(tmp_path, "mui", 0, filename);
4694 SetEnvironmentVariableA("WineMuiDat", filename);
4696 /* write dummy data to the file, i.e. it's not a PE file. */
4697 hFile = CreateFileA(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
4698 ok(hFile != INVALID_HANDLE_VALUE, "can't open %s\n", filename);
4699 WriteFile(hFile, filename, strlen(filename), &size, NULL);
4700 CloseHandle(hFile);
4702 for (i = 0; i < ARRAY_SIZE(test_case); i++)
4704 size = test_case[i].value ? strlen(test_case[i].value) + 1 : 0;
4705 ret = RegSetValueExA(hkey_main, tz_value, 0, test_case[i].type,
4706 (const BYTE *)test_case[i].value, size);
4707 ok(ret == ERROR_SUCCESS, "[%2u] got %ld\n", i, ret);
4709 size = 0xdeadbeef;
4710 memset(bufW, 0xff, sizeof(bufW));
4711 ret = pRegLoadMUIStringW(hkey_main, tz_valueW, bufW, ARRAY_SIZE(bufW),
4712 &size, 0,
4713 test_case[i].use_sysdir ? sysdirW : NULL);
4714 ok(ret == test_case[i].expected ||
4715 broken(test_case[i].value[0] == '%' && ret == ERROR_SUCCESS /* vista */) ||
4716 broken(test_case[i].broken_ret && ret == test_case[i].broken_ret /* vista */),
4717 "[%2u] expected %ld, got %ld\n", i, test_case[i].expected, ret);
4718 if (ret == ERROR_SUCCESS && test_case[i].expected == ERROR_SUCCESS)
4720 ok(size == text_size, "[%2u] got %lu, expected %lu\n", i, size, text_size);
4721 ok(!memcmp(bufW, textW, size), "[%2u] got %s, expected %s\n", i,
4722 wine_dbgstr_wn(bufW, size/sizeof(WCHAR)),
4723 wine_dbgstr_wn(textW, text_size/sizeof(WCHAR)));
4727 SetCurrentDirectoryW(curdirW);
4728 DeleteFileA(filename);
4729 SetEnvironmentVariableA("WineMuiTest1", NULL);
4730 SetEnvironmentVariableA("WineMuiTest2", NULL);
4731 SetEnvironmentVariableA("WineMuiExe", NULL);
4732 SetEnvironmentVariableA("WineMuiDat", NULL);
4735 static void test_EnumDynamicTimeZoneInformation(void)
4737 LSTATUS status;
4738 HKEY key, subkey;
4739 WCHAR name[128];
4740 WCHAR keyname[128];
4741 WCHAR sysdir[MAX_PATH];
4742 DWORD index, ret, gle, size;
4743 DYNAMIC_TIME_ZONE_INFORMATION bogus_dtzi, dtzi;
4744 struct tz_reg_data
4746 LONG bias;
4747 LONG std_bias;
4748 LONG dlt_bias;
4749 SYSTEMTIME std_date;
4750 SYSTEMTIME dlt_date;
4751 } tz_data;
4753 if (!pEnumDynamicTimeZoneInformation)
4755 win_skip("EnumDynamicTimeZoneInformation is not supported.\n");
4756 return;
4759 if (pRegLoadMUIStringW)
4760 GetSystemDirectoryW(sysdir, ARRAY_SIZE(sysdir));
4762 SetLastError(0xdeadbeef);
4763 ret = pEnumDynamicTimeZoneInformation(0, NULL);
4764 gle = GetLastError();
4765 ok(gle == 0xdeadbeef, "got 0x%lx\n", gle);
4766 ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret);
4768 memset(&bogus_dtzi, 0xcc, sizeof(bogus_dtzi));
4769 memset(&dtzi, 0xcc, sizeof(dtzi));
4770 SetLastError(0xdeadbeef);
4771 ret = pEnumDynamicTimeZoneInformation(-1, &dtzi);
4772 gle = GetLastError();
4773 ok(gle == 0xdeadbeef, "got 0x%lx\n", gle);
4774 ok(ret == ERROR_NO_MORE_ITEMS, "got %ld\n", ret);
4775 ok(!memcmp(&dtzi, &bogus_dtzi, sizeof(dtzi)), "mismatch\n");
4777 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
4778 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0,
4779 KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE, &key);
4780 ok(status == ERROR_SUCCESS, "got %ld\n", status);
4781 index = 0;
4782 while (!(status = RegEnumKeyW(key, index, keyname, ARRAY_SIZE(keyname))))
4784 winetest_push_context("%s" , wine_dbgstr_w(keyname));
4785 subkey = NULL;
4786 status = RegOpenKeyExW(key, keyname, 0, KEY_QUERY_VALUE, &subkey);
4787 ok(status == ERROR_SUCCESS, "got %ld\n", status);
4789 memset(&dtzi, 0xcc, sizeof(dtzi));
4790 SetLastError(0xdeadbeef);
4791 ret = pEnumDynamicTimeZoneInformation(index, &dtzi);
4792 gle = GetLastError();
4793 /* recently added time zones may not have MUI strings */
4794 ok(gle == ERROR_SUCCESS ||
4795 gle == ERROR_RESOURCE_TYPE_NOT_FOUND /* Win10 1809 32-bit */ ||
4796 gle == ERROR_MUI_FILE_NOT_FOUND /* Win10 1809 64-bit */,
4797 "got 0x%lx\n", gle);
4798 ok(ret == ERROR_SUCCESS, "got %ld\n", ret);
4799 ok(!lstrcmpW(dtzi.TimeZoneKeyName, keyname), "expected %s, got %s\n",
4800 wine_dbgstr_w(keyname), wine_dbgstr_w(dtzi.TimeZoneKeyName));
4802 if (gle == ERROR_SUCCESS)
4804 size = sizeof(name);
4805 memset(name, 0, sizeof(name));
4806 status = pRegGetValueW(subkey, NULL, L"Std", RRF_RT_REG_SZ, NULL, name, &size);
4807 ok(status == ERROR_SUCCESS, "status %ld Std %s\n", status,
4808 wine_dbgstr_w(name));
4809 ok(*name, "Std name is empty\n");
4810 if (pRegLoadMUIStringW)
4812 size = sizeof(name);
4813 memset(name, 0, sizeof(name));
4814 status = pRegLoadMUIStringW(subkey, L"MUI_Std", name, size, &size, 0, sysdir);
4815 ok(status == ERROR_SUCCESS, "status %ld MUI_Std %s\n",
4816 status, wine_dbgstr_w(name));
4817 ok(*name, "MUI_Std name is empty\n");
4819 ok(!memcmp(&dtzi.StandardName, name, size), "expected %s, got %s\n",
4820 wine_dbgstr_w(name), wine_dbgstr_w(dtzi.StandardName));
4822 size = sizeof(name);
4823 memset(name, 0, sizeof(name));
4824 status = pRegGetValueW(subkey, NULL, L"Dlt", RRF_RT_REG_SZ, NULL, name, &size);
4825 ok(status == ERROR_SUCCESS, "status %ld %s Dlt %s\n",
4826 status, wine_dbgstr_w(keyname), wine_dbgstr_w(name));
4827 ok(*name, "Dlt name is empty\n");
4828 if (pRegLoadMUIStringW)
4830 size = sizeof(name);
4831 memset(name, 0, sizeof(name));
4832 status = pRegLoadMUIStringW(subkey, L"MUI_Dlt", name, size, &size, 0, sysdir);
4833 ok(status == ERROR_SUCCESS, "status %ld %s MUI_Dlt %s\n",
4834 status, wine_dbgstr_w(keyname), wine_dbgstr_w(name));
4835 ok(*name, "MUI_Dlt name is empty\n");
4837 ok(!memcmp(&dtzi.DaylightName, name, size), "expected %s, got %s\n",
4838 wine_dbgstr_w(name), wine_dbgstr_w(dtzi.DaylightName));
4840 size = sizeof(name);
4841 memset(name, 0, sizeof(name));
4842 status = pRegGetValueW(subkey, NULL, L"Display", RRF_RT_REG_SZ, NULL, name, &size);
4843 ok(status == ERROR_SUCCESS, "status %ld %s Display %s\n",
4844 status, wine_dbgstr_w(keyname), wine_dbgstr_w(name));
4845 ok(*name, "Display name is empty\n");
4846 if (pRegLoadMUIStringW)
4848 size = sizeof(name);
4849 memset(name, 0, sizeof(name));
4850 status = pRegLoadMUIStringW(subkey, L"MUI_Display", name, size, &size, 0, sysdir);
4851 /* recently added time zones may not have MUI strings */
4852 ok((status == ERROR_SUCCESS && *name) ||
4853 broken(status == ERROR_RESOURCE_TYPE_NOT_FOUND) /* Win10 1809 32-bit */ ||
4854 broken(status == ERROR_MUI_FILE_NOT_FOUND) /* Win10 1809 64-bit */,
4855 "status %ld MUI_Display %s\n", status, wine_dbgstr_w(name));
4858 else
4860 ok(!dtzi.StandardName[0], "expected empty StandardName\n");
4861 ok(!dtzi.DaylightName[0], "expected empty DaylightName\n");
4864 ok(!dtzi.DynamicDaylightTimeDisabled, "got %d\n", dtzi.DynamicDaylightTimeDisabled);
4866 size = sizeof(tz_data);
4867 status = pRegGetValueW(key, keyname, L"TZI", RRF_RT_REG_BINARY, NULL, &tz_data, &size);
4868 ok(status == ERROR_SUCCESS, "got %ld\n", status);
4870 ok(dtzi.Bias == tz_data.bias, "expected %ld, got %ld\n",
4871 tz_data.bias, dtzi.Bias);
4872 ok(dtzi.StandardBias == tz_data.std_bias, "expected %ld, got %ld\n",
4873 tz_data.std_bias, dtzi.StandardBias);
4874 ok(dtzi.DaylightBias == tz_data.dlt_bias, "expected %ld, got %ld\n",
4875 tz_data.dlt_bias, dtzi.DaylightBias);
4877 ok(!memcmp(&dtzi.StandardDate, &tz_data.std_date, sizeof(dtzi.StandardDate)),
4878 "expected %s, got %s\n",
4879 dbgstr_SYSTEMTIME(&tz_data.std_date), dbgstr_SYSTEMTIME(&dtzi.StandardDate));
4881 ok(!memcmp(&dtzi.DaylightDate, &tz_data.dlt_date, sizeof(dtzi.DaylightDate)),
4882 "expected %s, got %s\n",
4883 dbgstr_SYSTEMTIME(&tz_data.dlt_date), dbgstr_SYSTEMTIME(&dtzi.DaylightDate));
4885 winetest_pop_context();
4886 RegCloseKey(subkey);
4887 index++;
4889 ok(status == ERROR_NO_MORE_ITEMS, "got %ld\n", status);
4891 memset(&dtzi, 0xcc, sizeof(dtzi));
4892 SetLastError(0xdeadbeef);
4893 ret = pEnumDynamicTimeZoneInformation(index, &dtzi);
4894 gle = GetLastError();
4895 ok(gle == 0xdeadbeef, "got 0x%lx\n", gle);
4896 ok(ret == ERROR_NO_MORE_ITEMS, "got %ld\n", ret);
4897 ok(!memcmp(&dtzi, &bogus_dtzi, sizeof(dtzi)), "mismatch\n");
4899 RegCloseKey(key);
4902 static void test_RegRenameKey(void)
4904 HKEY key, key2;
4905 LSTATUS ret;
4907 ret = RegRenameKey(NULL, NULL, NULL);
4908 ok(ret == ERROR_INVALID_PARAMETER, "Unexpected return value %ld.\n", ret);
4909 ret = RegRenameKey(NULL, NULL, L"newname");
4910 ok(ret == ERROR_INVALID_HANDLE, "Unexpected return value %ld.\n", ret);
4911 ret = RegRenameKey(NULL, L"oldname", NULL);
4912 ok(ret == ERROR_INVALID_HANDLE, "Unexpected return value %ld.\n", ret);
4913 ret = RegRenameKey(NULL, L"oldname", L"newname");
4914 ok(ret == ERROR_INVALID_HANDLE, "Unexpected return value %ld.\n", ret);
4916 ret = RegCreateKeyExA(hkey_main, "TestRenameKey", 0, NULL, 0, KEY_READ, NULL, &key, NULL);
4917 ok(!ret, "Unexpected return value %ld.\n", ret);
4918 ret = RegRenameKey(key, NULL, L"TestNewRenameKey");
4919 ok(ret == ERROR_ACCESS_DENIED, "Unexpected return value %ld.\n", ret);
4920 RegCloseKey(key);
4922 /* Rename itself. */
4923 ret = RegCreateKeyExA(hkey_main, "TestRenameKey", 0, NULL, 0, KEY_WRITE, NULL, &key, NULL);
4924 ok(!ret, "Unexpected return value %ld.\n", ret);
4925 ret = RegRenameKey(key, NULL, NULL);
4926 ok(ret == ERROR_INVALID_PARAMETER, "Unexpected return value %ld.\n", ret);
4927 ret = RegRenameKey(key, NULL, L"TestNewRenameKey");
4928 ok(!ret, "Unexpected return value %ld.\n", ret);
4929 RegCloseKey(key);
4931 ret = RegDeleteKeyA(hkey_main, "TestNewRenameKey");
4932 ok(!ret, "Unexpected return value %ld.\n", ret);
4933 ret = RegDeleteKeyA(hkey_main, "TestRenameKey");
4934 ok(ret, "Unexpected return value %ld.\n", ret);
4936 /* Subkey does not exist. */
4937 ret = RegCreateKeyExA(hkey_main, "TestRenameKey", 0, NULL, 0, KEY_WRITE, NULL, &key, NULL);
4938 ok(!ret, "Unexpected return value %ld.\n", ret);
4939 ret = RegRenameKey(key, L"unknown_subkey", NULL);
4940 ok(ret == ERROR_FILE_NOT_FOUND, "Unexpected return value %ld.\n", ret);
4941 ret = RegRenameKey(key, L"unknown_subkey", L"known_subkey");
4942 ok(ret == ERROR_FILE_NOT_FOUND, "Unexpected return value %ld.\n", ret);
4944 /* Rename existing subkey. */
4945 ret = RegCreateKeyExA(key, "known_subkey", 0, NULL, 0, KEY_WRITE, NULL, &key2, NULL);
4946 ok(!ret, "Unexpected return value %ld.\n", ret);
4947 RegCloseKey(key2);
4949 ret = RegRenameKey(key, L"known_subkey", L"renamed_subkey");
4950 ok(!ret, "Unexpected return value %ld.\n", ret);
4952 ret = RegDeleteKeyA(key, "renamed_subkey");
4953 ok(!ret, "Unexpected return value %ld.\n", ret);
4954 ret = RegDeleteKeyA(key, "known_subkey");
4955 ok(ret, "Unexpected return value %ld.\n", ret);
4957 RegCloseKey(key);
4960 START_TEST(registry)
4962 /* Load pointers for functions that are not available in all Windows versions */
4963 InitFunctionPtrs();
4965 setup_main_key();
4966 check_user_privs();
4967 test_set_value();
4968 create_test_entries();
4969 test_enum_value();
4970 test_query_value_ex();
4971 test_get_value();
4972 test_reg_open_key();
4973 test_reg_create_key();
4974 test_reg_close_key();
4975 test_reg_delete_key();
4976 test_reg_query_value();
4977 test_reg_query_info();
4978 test_string_termination();
4979 test_symlinks();
4980 test_redirection();
4981 test_classesroot();
4982 test_classesroot_enum();
4983 test_classesroot_mask();
4984 test_reg_save_key();
4985 test_reg_load_key();
4986 test_reg_unload_key();
4987 test_reg_load_app_key();
4988 test_reg_copy_tree();
4989 test_reg_delete_tree();
4990 test_rw_order();
4991 test_deleted_key();
4992 test_delete_value();
4993 test_delete_key_value();
4994 test_RegOpenCurrentUser();
4995 test_RegNotifyChangeKeyValue();
4996 test_performance_keys();
4997 test_RegLoadMUIString();
4998 test_EnumDynamicTimeZoneInformation();
4999 test_perflib_key();
5000 test_RegRenameKey();
5002 /* cleanup */
5003 delete_key( hkey_main );
5005 test_regconnectregistry();