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
26 #define WIN32_NO_STATUS
27 #include "wine/test.h"
37 #define IS_HKCR(hk) ((UINT_PTR)hk > 0 && ((UINT_PTR)hk & 3) == 2)
39 static HKEY hkey_main
;
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
)
113 if ((ret
= RegOpenKeyExA( hkey
, "", 0, KEY_ENUMERATE_SUB_KEYS
, &hkey
))) return ret
;
114 while (!(ret
= RegEnumKeyA(hkey
, 0, name
, sizeof(name
))))
117 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, KEY_ENUMERATE_SUB_KEYS
, &tmp
)))
119 ret
= delete_key( tmp
);
124 if (ret
!= ERROR_NO_MORE_ITEMS
) return ret
;
125 RegDeleteKeyA( hkey
, "" );
130 static void setup_main_key(void)
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 %d\n", ret
);
140 static void check_user_privs(void)
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 %i\n", ret
);
147 if (ret
== ERROR_SUCCESS
)
149 ok(hkey
!= NULL
, "RegOpenKeyExA succeeded but returned NULL hkey\n");
154 ok(hkey
== NULL
, "RegOpenKeyExA failed but returned hkey %p\n", hkey
);
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
,
165 DWORD ret
, type
, cbData
;
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: %d, GLE=%d\n", ret
, GLE
);
178 /* It is wrong for the Ansi version to not be implemented */
179 ok(GLE
== 0xdeadbeef, "RegQueryValueExA set GLE = %u\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 %d\n", type
);
184 lok(cbData
== full_byte_len
, "cbData=%d instead of %d or %d\n", cbData
, full_byte_len
, str_byte_len
);
186 value
= HeapAlloc(GetProcessHeap(), 0, cbData
+1);
187 memset(value
, 0xbd, cbData
+1);
189 ret
= RegQueryValueExA(hkey_main
, name
, NULL
, &type
, value
, &cbData
);
190 GLE
= GetLastError();
191 lok(ret
== ERROR_SUCCESS
, "RegQueryValueExA/2 failed: %d, GLE=%d\n", ret
, GLE
);
194 /* When cbData == 0, RegQueryValueExA() should not modify the buffer */
195 lok(*value
== 0xbd, "RegQueryValueExA overflowed: cbData=%u *value=%02x\n", cbData
, *value
);
199 lok(memcmp(value
, string
, cbData
) == 0, "RegQueryValueExA/2 failed: %s/%d != %s/%d\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 %u: %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
,
211 DWORD ret
, type
, cbData
;
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: %d, GLE=%d\n", ret
, GLE
);
223 if(GLE
== ERROR_CALL_NOT_IMPLEMENTED
)
225 win_skip("RegQueryValueExW() is not implemented\n");
229 lok(type
== REG_SZ
, "RegQueryValueExW/1 returned type %d\n", type
);
230 lok(cbData
== full_byte_len
,
231 "cbData=%d instead of %d\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);
237 ret
= RegQueryValueExW(hkey_main
, name
, NULL
, &type
, value
, &cbData
);
238 GLE
= GetLastError();
239 lok(ret
== ERROR_SUCCESS
, "RegQueryValueExW/2 failed: %d, GLE=%d\n", ret
, GLE
);
242 lok(memcmp(value
, string
, cbData
) == 0, "RegQueryValueExW failed: %s/%d != %s/%d\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 %u: %02x != bd\n", cbData
, *(value
+cbData
));
248 lok(*(value
+cbData
+1) == 0xbd, "RegQueryValueExW/2 overflowed at %u+1: %02x != bd\n", cbData
, *(value
+cbData
+1));
249 HeapFree(GetProcessHeap(), 0, value
);
252 static void test_set_value(void)
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";
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 %d\n", ret
);
277 ret
= RegSetValueA(hkey_main
, NULL
, REG_SZ
, string1A
, sizeof(string1A
));
278 ok(ret
== ERROR_SUCCESS
, "RegSetValueA failed: %d, GLE=%d\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: %d, GLE=%d\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: %d, GLE=%d\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 %d (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 %d (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 %d (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: %d, GLE=%d\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: %d, GLE=%d\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: %d, GLE=%d\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: %d, GLE=%d\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: %d, GLE=%d\n", ret
, GetLastError());
333 test_hkey_main_Value_A(name2A
, string2A
, sizeof(string2A
));
334 test_hkey_main_Value_W(name2W
, string2W
, sizeof(string2W
));
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 %d\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: %d, GLE=%d\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: %d, GLE=%d\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: %d, GLE=%d\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: %d, GLE=%d\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 %d\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 %d\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 %d\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: %d, GLE=%d\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: %d, GLE=%d\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: %d, GLE=%d\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: %d, GLE=%d\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: %d, GLE=%d\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: %d, GLE=%d\n", ret
, GetLastError());
405 ret
= RegSetValueExW(hkey_main
, NULL
, 0, REG_SZ
, NULL
, 0);
406 ok(ret
== ERROR_SUCCESS
, "got %d\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: %d, GLE=%d\n", ret
, GetLastError());
411 ret
= RegSetValueExW(hkey_main
, NULL
, 0, REG_DWORD
, NULL
, 0);
412 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
416 if (!pRegSetKeyValueW
)
417 win_skip("RegSetKeyValue() is not supported.\n");
423 ret
= pRegSetKeyValueW(hkey_main
, NULL
, name1W
, REG_SZ
, (const BYTE
*)string2W
, sizeof(string2W
));
424 ok(ret
== ERROR_SUCCESS
, "got %d\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 %d\n", ret
);
431 ret
= RegOpenKeyExW(hkey_main
, L
"subkey", 0, KEY_QUERY_VALUE
, &subkey
);
432 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
434 ret
= RegQueryValueExW(subkey
, name1W
, 0, &type
, NULL
, &len
);
435 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
436 ok(len
== sizeof(string1W
), "got %d\n", len
);
437 ok(type
== REG_SZ
, "got type %d\n", type
);
439 ret
= pRegSetKeyValueW(hkey_main
, L
"subkey", name1W
, REG_SZ
, NULL
, 0);
440 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
442 ret
= pRegSetKeyValueW(hkey_main
, L
"subkey", name1W
, REG_SZ
, NULL
, 4);
443 ok(ret
== ERROR_NOACCESS
, "got %d\n", ret
);
445 ret
= pRegSetKeyValueW(hkey_main
, L
"subkey", name1W
, REG_DWORD
, NULL
, 4);
446 ok(ret
== ERROR_NOACCESS
, "got %d\n", ret
);
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)
479 char value
[20], data
[20];
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 %d\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 %d\n", res
);
492 ok( !res
, "RegSetValueExA returned %d\n", res
);
493 res
= RegSetValueExA( test_key
, "Test", 0, REG_EXPAND_SZ
, NULL
, 0 );
494 ok( ERROR_SUCCESS
== res
|| ERROR_INVALID_PARAMETER
== res
, "RegSetValueExA returned %d\n", res
);
495 res
= RegSetValueExA( test_key
, "Test", 0, REG_BINARY
, NULL
, 0 );
496 ok( ERROR_SUCCESS
== res
|| ERROR_INVALID_PARAMETER
== res
, "RegSetValueExA returned %d\n", res
);
498 /* test reading the value and data without setting them */
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 %d\n", res
);
506 ok( val_count
== 4, "val_count set to %d instead of 4\n", val_count
);
507 ok( data_count
== 0, "data_count set to %d instead of 0\n", data_count
);
508 ok( type
== REG_BINARY
, "type %d 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
);
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 %d\n", res
);
519 ok( val_count
== 4, "val_count set to %d instead of 4\n", val_count
);
520 ok( data_count
== 0, "data_count set to %d instead of 0\n", data_count
);
521 ok( type
== REG_BINARY
, "type %d 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 %d\n", res
);
528 /* overflow both name and data */
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 %d\n", res
);
536 ok( val_count
== 2, "val_count set to %d\n", val_count
);
537 ok( data_count
== 7 || broken( data_count
== 8 ), "data_count set to %d instead of 7\n", data_count
);
538 ok( type
== REG_SZ
, "type %d is not REG_SZ\n", type
);
539 ok( !strcmp( value
, "xxxxxxxxxx" ), "value set to '%s'\n", value
);
540 ok( !strcmp( data
, "xxxxxxxxxx" ), "data set to '%s'\n", data
);
546 strcpy( value
, "xxxxxxxxxx" );
547 strcpy( data
, "xxxxxxxxxx" );
548 res
= RegEnumValueA( test_key
, 0, value
, &val_count
, NULL
, &type
, (LPBYTE
)data
, &data_count
);
549 ok( res
== ERROR_MORE_DATA
, "expected ERROR_MORE_DATA, got %d\n", res
);
550 ok( val_count
== 3, "val_count set to %d\n", val_count
);
551 ok( data_count
== 7 || broken( data_count
== 8 ), "data_count set to %d instead of 7\n", data_count
);
552 ok( type
== REG_SZ
, "type %d is not REG_SZ\n", type
);
553 /* v5.1.2600.0 (XP Home and Professional) does not touch value or data in this case */
554 ok( !strcmp( value
, "Te" ) || !strcmp( value
, "xxxxxxxxxx" ),
555 "value set to '%s' instead of 'Te' or 'xxxxxxxxxx'\n", value
);
556 ok( !strcmp( data
, "foobar" ) || !strcmp( data
, "xxxxxxx" ) || broken( !strcmp( data
, "xxxxxxxx" ) && data_count
== 8 ),
557 "data set to '%s' instead of 'foobar' or 'xxxxxxx'\n", data
);
559 /* overflow empty name */
563 strcpy( value
, "xxxxxxxxxx" );
564 strcpy( data
, "xxxxxxxxxx" );
565 res
= RegEnumValueA( test_key
, 0, value
, &val_count
, NULL
, &type
, (LPBYTE
)data
, &data_count
);
566 ok( res
== ERROR_MORE_DATA
, "expected ERROR_MORE_DATA, got %d\n", res
);
567 ok( val_count
== 0, "val_count set to %d\n", val_count
);
568 ok( data_count
== 7 || broken( data_count
== 8 ), "data_count set to %d instead of 7\n", data_count
);
569 ok( type
== REG_SZ
, "type %d is not REG_SZ\n", type
);
570 ok( !strcmp( value
, "xxxxxxxxxx" ), "value set to '%s'\n", value
);
571 /* v5.1.2600.0 (XP Home and Professional) does not touch data in this case */
572 ok( !strcmp( data
, "foobar" ) || !strcmp( data
, "xxxxxxx" ) || broken( !strcmp( data
, "xxxxxxxx" ) && data_count
== 8 ),
573 "data set to '%s' instead of 'foobar' or 'xxxxxxx'\n", data
);
579 strcpy( value
, "xxxxxxxxxx" );
580 strcpy( data
, "xxxxxxxxxx" );
581 res
= RegEnumValueA( test_key
, 0, value
, &val_count
, NULL
, &type
, (LPBYTE
)data
, &data_count
);
582 ok( res
== ERROR_MORE_DATA
, "expected ERROR_MORE_DATA, got %d\n", res
);
583 ok( val_count
== 20, "val_count set to %d\n", val_count
);
584 ok( data_count
== 7, "data_count set to %d instead of 7\n", data_count
);
585 ok( type
== REG_SZ
, "type %d is not REG_SZ\n", type
);
586 ok( !strcmp( value
, "xxxxxxxxxx" ), "value set to '%s'\n", value
);
587 ok( !strcmp( data
, "xxxxxxxxxx" ), "data set to '%s'\n", data
);
593 strcpy( value
, "xxxxxxxxxx" );
594 strcpy( data
, "xxxxxxxxxx" );
595 res
= RegEnumValueA( test_key
, 0, value
, &val_count
, NULL
, &type
, (LPBYTE
)data
, &data_count
);
596 ok( res
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", res
);
597 ok( val_count
== 4, "val_count set to %d instead of 4\n", val_count
);
598 ok( data_count
== 7, "data_count set to %d instead of 7\n", data_count
);
599 ok( type
== REG_SZ
, "type %d is not REG_SZ\n", type
);
600 ok( !strcmp( value
, "Test" ), "value is '%s' instead of Test\n", value
);
601 ok( !strcmp( data
, "foobar" ), "data is '%s' instead of foobar\n", data
);
603 if (pRegGetValueA
) /* avoid a crash on Windows 2000 */
605 /* no value and no val_count parameter */
608 strcpy( data
, "xxxxxxxxxx" );
609 res
= RegEnumValueA( test_key
, 0, NULL
, NULL
, NULL
, &type
, (BYTE
*)data
, &data_count
);
610 ok( res
== ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", res
);
612 /* no value parameter */
616 strcpy( data
, "xxxxxxxxxx" );
617 res
= RegEnumValueA( test_key
, 0, NULL
, &val_count
, NULL
, &type
, (BYTE
*)data
, &data_count
);
618 ok( res
== ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", res
);
620 /* no val_count parameter */
623 strcpy( value
, "xxxxxxxxxx" );
624 strcpy( data
, "xxxxxxxxxx" );
625 res
= RegEnumValueA( test_key
, 0, value
, NULL
, NULL
, &type
, (BYTE
*)data
, &data_count
);
626 ok( res
== ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", res
);
631 SetLastError(0xdeadbeef);
632 res
= RegSetValueExW( test_key
, L
"Test", 0, REG_SZ
, (const BYTE
*)L
"foobar", 7*sizeof(WCHAR
) );
633 if (res
==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED
)
635 win_skip("RegSetValueExW is not implemented\n");
638 ok( res
== 0, "RegSetValueExW failed error %d\n", res
);
640 /* overflow both name and data */
644 wcscpy( valueW
, L
"xxxxxxxx" );
645 wcscpy( dataW
, L
"xxxxxxxx" );
646 res
= RegEnumValueW( test_key
, 0, valueW
, &val_count
, NULL
, &type
, (BYTE
*)dataW
, &data_count
);
647 ok( res
== ERROR_MORE_DATA
, "expected ERROR_MORE_DATA, got %d\n", res
);
648 ok( val_count
== 2, "val_count set to %d\n", val_count
);
649 ok( data_count
== 7*sizeof(WCHAR
), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count
);
650 ok( type
== REG_SZ
, "type %d is not REG_SZ\n", type
);
651 ok( !wcscmp( valueW
, L
"xxxxxxxx" ), "value modified\n" );
652 ok( !wcscmp( dataW
, L
"xxxxxxxx" ), "data modified\n" );
658 wcscpy( valueW
, L
"xxxxxxxx" );
659 wcscpy( dataW
, L
"xxxxxxxx" );
660 res
= RegEnumValueW( test_key
, 0, valueW
, &val_count
, NULL
, &type
, (BYTE
*)dataW
, &data_count
);
661 ok( res
== ERROR_MORE_DATA
, "expected ERROR_MORE_DATA, got %d\n", res
);
662 ok( val_count
== 3, "val_count set to %d\n", val_count
);
663 ok( data_count
== 7*sizeof(WCHAR
), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count
);
664 ok( type
== REG_SZ
, "type %d is not REG_SZ\n", type
);
665 ok( !wcscmp( valueW
, L
"xxxxxxxx" ), "value modified\n" );
666 ok( !wcscmp( dataW
, L
"xxxxxxxx" ), "data modified\n" );
672 wcscpy( valueW
, L
"xxxxxxxx" );
673 wcscpy( dataW
, L
"xxxxxxxx" );
674 res
= RegEnumValueW( test_key
, 0, valueW
, &val_count
, NULL
, &type
, (BYTE
*)dataW
, &data_count
);
675 ok( res
== ERROR_MORE_DATA
, "expected ERROR_MORE_DATA, got %d\n", res
);
676 ok( val_count
== 4, "val_count set to %d instead of 4\n", val_count
);
677 ok( data_count
== 7*sizeof(WCHAR
), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count
);
678 ok( type
== REG_SZ
, "type %d is not REG_SZ\n", type
);
679 ok( !wcscmp( valueW
, L
"Test" ), "value is not 'Test'\n" );
680 ok( !wcscmp( dataW
, L
"xxxxxxxx" ), "data modified\n" );
686 wcscpy( valueW
, L
"xxxxxxxx" );
687 wcscpy( dataW
, L
"xxxxxxxx" );
688 res
= RegEnumValueW( test_key
, 0, valueW
, &val_count
, NULL
, &type
, (BYTE
*)dataW
, &data_count
);
689 ok( res
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", res
);
690 ok( val_count
== 4, "val_count set to %d instead of 4\n", val_count
);
691 ok( data_count
== 7*sizeof(WCHAR
), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count
);
692 ok( type
== REG_SZ
, "type %d is not REG_SZ\n", type
);
693 ok( !wcscmp( valueW
, L
"Test" ), "value is not 'Test'\n" );
694 ok( !wcscmp( dataW
, L
"foobar" ), "data is not 'foobar'\n" );
696 if (pRegGetValueA
) /* avoid a crash on Windows 2000 */
698 /* no valueW and no val_count parameter */
701 wcscpy( dataW
, L
"xxxxxxxx" );
702 res
= RegEnumValueW( test_key
, 0, NULL
, NULL
, NULL
, &type
, (BYTE
*)dataW
, &data_count
);
703 ok( res
== ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", res
);
705 /* no valueW parameter */
709 wcscpy( dataW
, L
"xxxxxxxx" );
710 res
= RegEnumValueW( test_key
, 0, NULL
, &val_count
, NULL
, &type
, (BYTE
*)dataW
, &data_count
);
711 ok( res
== ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", res
);
713 /* no val_count parameter */
716 wcscpy( valueW
, L
"xxxxxxxx" );
717 wcscpy( dataW
, L
"xxxxxxxx" );
718 res
= RegEnumValueW( test_key
, 0, valueW
, NULL
, NULL
, &type
, (BYTE
*)dataW
, &data_count
);
719 ok( res
== ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", res
);
723 RegDeleteKeyA(test_key
, "");
724 RegCloseKey(test_key
);
727 static void test_query_value_ex(void)
729 DWORD ret
, size
, type
;
732 size
= sizeof(buffer
);
733 ret
= RegQueryValueExA(hkey_main
, "TP1_SZ", NULL
, &type
, NULL
, &size
);
734 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
735 ok(size
== strlen(sTestpath1
) + 1, "(%d,%d)\n", (DWORD
)strlen(sTestpath1
) + 1, size
);
736 ok(type
== REG_SZ
, "type %d is not REG_SZ\n", type
);
740 ret
= RegQueryValueExA(HKEY_CLASSES_ROOT
, "Nonexistent Value", NULL
, &type
, NULL
, &size
);
741 ok(ret
== ERROR_FILE_NOT_FOUND
, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret
);
742 ok(size
== 0, "size should have been set to 0 instead of %d\n", size
);
744 size
= sizeof(buffer
);
745 ret
= RegQueryValueExA(HKEY_CLASSES_ROOT
, "Nonexistent Value", NULL
, &type
, buffer
, &size
);
746 ok(ret
== ERROR_FILE_NOT_FOUND
, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret
);
747 ok(size
== sizeof(buffer
), "size shouldn't have been changed to %d\n", size
);
750 ret
= RegQueryValueExA(hkey_main
, "BIN32", NULL
, &size
, buffer
, &size
);
751 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
754 static void test_get_value(void)
761 CHAR expanded
[] = "bar\\subdir1";
762 CHAR expanded2
[] = "ImARatherLongButIndeedNeededString\\subdir1";
766 win_skip("RegGetValue not available on this platform\n");
770 /* Invalid parameter */
771 ret
= pRegGetValueA(hkey_main
, NULL
, "DWORD", RRF_RT_REG_DWORD
, &type
, &dw
, NULL
);
772 ok(ret
== ERROR_INVALID_PARAMETER
, "ret=%d\n", ret
);
774 /* Query REG_DWORD using RRF_RT_REG_DWORD (ok) */
775 size
= type
= dw
= 0xdeadbeef;
776 ret
= pRegGetValueA(hkey_main
, NULL
, "DWORD", RRF_RT_REG_DWORD
, &type
, &dw
, &size
);
777 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
778 ok(size
== 4, "size=%d\n", size
);
779 ok(type
== REG_DWORD
, "type=%d\n", type
);
780 ok(dw
== 0x12345678, "dw=%d\n", dw
);
782 /* Check RRF_SUBKEY_WOW64*KEY validation on a case without a subkey */
783 ret
= pRegGetValueA(hkey_main
, NULL
, "DWORD", RRF_RT_REG_DWORD
| RRF_SUBKEY_WOW6464KEY
| RRF_SUBKEY_WOW6432KEY
, NULL
, NULL
, NULL
);
784 ok(ret
== ERROR_INVALID_PARAMETER
|| broken(ret
== ERROR_SUCCESS
), /* Before Win10 */
786 ret
= pRegGetValueA(hkey_main
, NULL
, "DWORD", RRF_RT_REG_DWORD
| RRF_SUBKEY_WOW6464KEY
, NULL
, NULL
, NULL
);
787 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
788 ret
= pRegGetValueA(hkey_main
, NULL
, "DWORD", RRF_RT_REG_DWORD
| RRF_SUBKEY_WOW6432KEY
, NULL
, NULL
, NULL
);
789 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
791 /* Query by subkey-name */
792 ret
= pRegGetValueA(HKEY_CURRENT_USER
, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD
, NULL
, NULL
, NULL
);
793 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
795 /* Check RRF_SUBKEY_WOW64*KEY validation on a case with a subkey */
796 ret
= pRegGetValueA(HKEY_CURRENT_USER
, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD
| RRF_SUBKEY_WOW6464KEY
| RRF_SUBKEY_WOW6432KEY
, NULL
, NULL
, NULL
);
797 ok(ret
== ERROR_INVALID_PARAMETER
|| broken(ret
== ERROR_SUCCESS
), /* Before Win10 */
799 ret
= pRegGetValueA(HKEY_CURRENT_USER
, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD
| RRF_SUBKEY_WOW6464KEY
, NULL
, NULL
, NULL
);
800 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
801 ret
= pRegGetValueA(HKEY_CURRENT_USER
, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD
| RRF_SUBKEY_WOW6432KEY
, NULL
, NULL
, NULL
);
802 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
804 /* Query REG_DWORD using RRF_RT_REG_BINARY (restricted) */
805 size
= type
= dw
= 0xdeadbeef;
806 ret
= pRegGetValueA(hkey_main
, NULL
, "DWORD", RRF_RT_REG_BINARY
, &type
, &dw
, &size
);
807 ok(ret
== ERROR_UNSUPPORTED_TYPE
, "ret=%d\n", ret
);
808 /* Although the function failed all values are retrieved */
809 ok(size
== 4, "size=%d\n", size
);
810 ok(type
== REG_DWORD
, "type=%d\n", type
);
811 ok(dw
== 0x12345678, "dw=%d\n", dw
);
813 /* Test RRF_ZEROONFAILURE */
814 type
= dw
= 0xdeadbeef; size
= 4;
815 ret
= pRegGetValueA(hkey_main
, NULL
, "DWORD", RRF_RT_REG_SZ
|RRF_ZEROONFAILURE
, &type
, &dw
, &size
);
816 ok(ret
== ERROR_UNSUPPORTED_TYPE
, "ret=%d\n", ret
);
817 /* Again all values are retrieved ... */
818 ok(size
== 4, "size=%d\n", size
);
819 ok(type
== REG_DWORD
, "type=%d\n", type
);
820 /* ... except the buffer, which is zeroed out */
821 ok(dw
== 0, "dw=%d\n", dw
);
823 /* Test RRF_ZEROONFAILURE with a NULL buffer... */
824 type
= size
= 0xbadbeef;
825 ret
= pRegGetValueA(hkey_main
, NULL
, "DWORD", RRF_RT_REG_SZ
|RRF_ZEROONFAILURE
, &type
, NULL
, &size
);
826 ok(ret
== ERROR_UNSUPPORTED_TYPE
, "ret=%d\n", ret
);
827 ok(size
== 4, "size=%d\n", size
);
828 ok(type
== REG_DWORD
, "type=%d\n", type
);
830 /* Query REG_DWORD using RRF_RT_DWORD (ok) */
831 size
= type
= dw
= 0xdeadbeef;
832 ret
= pRegGetValueA(hkey_main
, NULL
, "DWORD", RRF_RT_DWORD
, &type
, &dw
, &size
);
833 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
834 ok(size
== 4, "size=%d\n", size
);
835 ok(type
== REG_DWORD
, "type=%d\n", type
);
836 ok(dw
== 0x12345678, "dw=%d\n", dw
);
838 /* Query 32-bit REG_BINARY using RRF_RT_DWORD (ok) */
839 size
= type
= dw
= 0xdeadbeef;
840 ret
= pRegGetValueA(hkey_main
, NULL
, "BIN32", RRF_RT_DWORD
, &type
, &dw
, &size
);
841 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
842 ok(size
== 4, "size=%d\n", size
);
843 ok(type
== REG_BINARY
, "type=%d\n", type
);
844 ok(dw
== 0x12345678, "dw=%d\n", dw
);
846 /* Query 64-bit REG_BINARY using RRF_RT_DWORD (type mismatch) */
847 qw
[0] = qw
[1] = size
= type
= 0xdeadbeef;
848 ret
= pRegGetValueA(hkey_main
, NULL
, "BIN64", RRF_RT_DWORD
, &type
, qw
, &size
);
849 ok(ret
== ERROR_DATATYPE_MISMATCH
, "ret=%d\n", ret
);
850 ok(size
== 8, "size=%d\n", size
);
851 ok(type
== REG_BINARY
, "type=%d\n", type
);
852 ok(qw
[0] == 0x12345678 &&
853 qw
[1] == 0x87654321, "qw={%d,%d}\n", qw
[0], qw
[1]);
855 /* Query 64-bit REG_BINARY using 32-bit buffer (buffer too small) */
856 type
= dw
= 0xdeadbeef; size
= 4;
857 ret
= pRegGetValueA(hkey_main
, NULL
, "BIN64", RRF_RT_REG_BINARY
, &type
, &dw
, &size
);
858 ok(ret
== ERROR_MORE_DATA
, "ret=%d\n", ret
);
859 ok(dw
== 0xdeadbeef, "dw=%d\n", dw
);
860 ok(size
== 8, "size=%d\n", size
);
862 /* Query 64-bit REG_BINARY using RRF_RT_QWORD (ok) */
863 qw
[0] = qw
[1] = size
= type
= 0xdeadbeef;
864 ret
= pRegGetValueA(hkey_main
, NULL
, "BIN64", RRF_RT_QWORD
, &type
, qw
, &size
);
865 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
866 ok(size
== 8, "size=%d\n", size
);
867 ok(type
== REG_BINARY
, "type=%d\n", type
);
868 ok(qw
[0] == 0x12345678 &&
869 qw
[1] == 0x87654321, "qw={%d,%d}\n", qw
[0], qw
[1]);
871 /* Query REG_SZ using RRF_RT_REG_SZ (ok) */
872 buf
[0] = 0; type
= 0xdeadbeef; size
= sizeof(buf
);
873 ret
= pRegGetValueA(hkey_main
, NULL
, "TP1_SZ", RRF_RT_REG_SZ
, &type
, buf
, &size
);
874 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
875 ok(size
== strlen(sTestpath1
)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1
), size
);
876 ok(type
== REG_SZ
, "type=%d\n", type
);
877 ok(!strcmp(sTestpath1
, buf
), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1
, buf
);
879 /* Query REG_SZ using RRF_RT_REG_SZ and no buffer (ok) */
880 type
= 0xdeadbeef; size
= 0;
881 ret
= pRegGetValueA(hkey_main
, NULL
, "TP1_SZ", RRF_RT_REG_SZ
, &type
, NULL
, &size
);
882 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
883 /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
884 ok(size
== strlen(sTestpath1
)+1 || broken(size
== strlen(sTestpath1
)+2),
885 "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1
), size
);
886 ok(type
== REG_SZ
, "type=%d\n", type
);
888 /* Query REG_SZ using RRF_RT_REG_SZ on a zero-byte value (ok) */
889 strcpy(buf
, sTestpath1
);
892 ret
= pRegGetValueA(hkey_main
, NULL
, "TP1_ZB_SZ", RRF_RT_REG_SZ
, &type
, buf
, &size
);
893 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
894 /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
896 size
== 1, /* win2k3 */
898 ok(type
== REG_SZ
, "type=%d\n", type
);
899 ok(!strcmp(sTestpath1
, buf
) ||
901 "Expected \"%s\" or \"\", got \"%s\"\n", sTestpath1
, buf
);
903 /* Query REG_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (ok) */
904 buf
[0] = 0; type
= 0xdeadbeef; size
= sizeof(buf
);
905 ret
= pRegGetValueA(hkey_main
, NULL
, "TP1_SZ", RRF_RT_REG_SZ
|RRF_NOEXPAND
, &type
, buf
, &size
);
906 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
907 ok(size
== strlen(sTestpath1
)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1
), size
);
908 ok(type
== REG_SZ
, "type=%d\n", type
);
909 ok(!strcmp(sTestpath1
, buf
), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1
, buf
);
911 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ and no buffer (ok, expands) */
913 ret
= pRegGetValueA(hkey_main
, NULL
, "TP2_EXP_SZ", RRF_RT_REG_SZ
, NULL
, NULL
, &size
);
914 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
915 ok((size
== strlen(expanded2
)+1) || /* win2k3 SP1 */
916 (size
== strlen(expanded2
)+2) || /* win2k3 SP2 */
917 (size
== strlen(sTestpath2
)+1),
918 "strlen(expanded2)=%d, strlen(sTestpath2)=%d, size=%d\n", lstrlenA(expanded2
), lstrlenA(sTestpath2
), size
);
920 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ (ok, expands) */
921 buf
[0] = 0; type
= 0xdeadbeef; size
= sizeof(buf
);
922 ret
= pRegGetValueA(hkey_main
, NULL
, "TP1_EXP_SZ", RRF_RT_REG_SZ
, &type
, buf
, &size
);
923 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
924 /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath1 length + 1 here. */
925 ok(size
== strlen(expanded
)+1 || broken(size
== strlen(sTestpath1
)+1),
926 "strlen(expanded)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded
), lstrlenA(sTestpath1
), size
);
927 ok(type
== REG_SZ
, "type=%d\n", type
);
928 ok(!strcmp(expanded
, buf
), "expanded=\"%s\" buf=\"%s\"\n", expanded
, buf
);
930 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ (ok, expands a lot) */
931 buf
[0] = 0; type
= 0xdeadbeef; size
= sizeof(buf
);
932 ret
= pRegGetValueA(hkey_main
, NULL
, "TP2_EXP_SZ", RRF_RT_REG_SZ
, &type
, buf
, &size
);
933 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
934 /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath2 length + 1 here. */
935 ok(size
== strlen(expanded2
)+1 || broken(size
== strlen(sTestpath2
)+1),
936 "strlen(expanded2)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded2
), lstrlenA(sTestpath2
), size
);
937 ok(type
== REG_SZ
, "type=%d\n", type
);
938 ok(!strcmp(expanded2
, buf
), "expanded2=\"%s\" buf=\"%s\"\n", expanded2
, buf
);
940 /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND (ok, doesn't expand) */
941 buf
[0] = 0; type
= 0xdeadbeef; size
= sizeof(buf
);
942 ret
= pRegGetValueA(hkey_main
, NULL
, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ
|RRF_NOEXPAND
, &type
, buf
, &size
);
943 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
944 ok(size
== strlen(sTestpath1
)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1
), size
);
945 ok(type
== REG_EXPAND_SZ
, "type=%d\n", type
);
946 ok(!strcmp(sTestpath1
, buf
), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1
, buf
);
948 /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND and no buffer (ok, doesn't expand) */
950 ret
= pRegGetValueA(hkey_main
, NULL
, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ
|RRF_NOEXPAND
, NULL
, NULL
, &size
);
951 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
952 /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
953 ok(size
== strlen(sTestpath1
)+1 || broken(size
== strlen(sTestpath1
)+2),
954 "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1
), size
);
956 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (type mismatch) */
957 ret
= pRegGetValueA(hkey_main
, NULL
, "TP1_EXP_SZ", RRF_RT_REG_SZ
|RRF_NOEXPAND
, NULL
, NULL
, NULL
);
958 ok(ret
== ERROR_UNSUPPORTED_TYPE
, "ret=%d\n", ret
);
960 /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ (not allowed without RRF_NOEXPAND) */
961 ret
= pRegGetValueA(hkey_main
, NULL
, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ
, NULL
, NULL
, NULL
);
962 /* before win8: ERROR_INVALID_PARAMETER, win8: ERROR_UNSUPPORTED_TYPE */
963 ok(ret
== ERROR_INVALID_PARAMETER
|| ret
== ERROR_UNSUPPORTED_TYPE
, "ret=%d\n", ret
);
965 /* Query REG_EXPAND_SZ using RRF_RT_ANY */
966 buf
[0] = 0; type
= 0xdeadbeef; size
= sizeof(buf
);
967 ret
= pRegGetValueA(hkey_main
, NULL
, "TP1_EXP_SZ", RRF_RT_ANY
, &type
, buf
, &size
);
968 ok(ret
== ERROR_SUCCESS
, "ret=%d\n", ret
);
969 /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath1 length + 1 here. */
970 ok(size
== strlen(expanded
)+1 || broken(size
== strlen(sTestpath1
)+1),
971 "strlen(expanded)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded
), lstrlenA(sTestpath1
), size
);
972 ok(type
== REG_SZ
, "type=%d\n", type
);
973 ok(!strcmp(expanded
, buf
), "expanded=\"%s\" buf=\"%s\"\n", expanded
, buf
);
976 static void test_reg_open_key(void)
979 HKEY hkResult
= NULL
;
980 HKEY hkPreserve
= NULL
;
981 HKEY hkRoot64
= NULL
;
982 HKEY hkRoot32
= NULL
;
984 SID_IDENTIFIER_AUTHORITY sid_authority
= {SECURITY_WORLD_SID_AUTHORITY
};
986 EXPLICIT_ACCESSA access
;
988 SECURITY_DESCRIPTOR
*sd
;
990 /* successful open */
991 ret
= RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Test", &hkResult
);
992 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
993 ok(hkResult
!= NULL
, "expected hkResult != NULL\n");
994 hkPreserve
= hkResult
;
996 /* open same key twice */
997 ret
= RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Test", &hkResult
);
998 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
999 ok(hkResult
!= hkPreserve
, "expected hkResult != hkPreserve\n");
1000 ok(hkResult
!= NULL
, "hkResult != NULL\n");
1001 RegCloseKey(hkResult
);
1003 /* trailing slashes */
1004 ret
= RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Test\\\\", &hkResult
);
1005 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1006 RegCloseKey(hkResult
);
1008 /* open nonexistent key
1009 * check that hkResult is set to NULL
1011 hkResult
= hkPreserve
;
1012 ret
= RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Nonexistent", &hkResult
);
1013 ok(ret
== ERROR_FILE_NOT_FOUND
, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret
);
1014 ok(hkResult
== NULL
, "expected hkResult == NULL\n");
1016 /* open the same nonexistent key again to make sure the key wasn't created */
1017 hkResult
= hkPreserve
;
1018 ret
= RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Nonexistent", &hkResult
);
1019 ok(ret
== ERROR_FILE_NOT_FOUND
, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret
);
1020 ok(hkResult
== NULL
, "expected hkResult == NULL\n");
1022 /* send in NULL lpSubKey
1023 * check that hkResult receives the value of hKey
1025 hkResult
= hkPreserve
;
1026 ret
= RegOpenKeyA(HKEY_CURRENT_USER
, NULL
, &hkResult
);
1027 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1028 ok(hkResult
== HKEY_CURRENT_USER
, "expected hkResult == HKEY_CURRENT_USER\n");
1030 /* send empty-string in lpSubKey */
1031 hkResult
= hkPreserve
;
1032 ret
= RegOpenKeyA(HKEY_CURRENT_USER
, "", &hkResult
);
1033 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1034 ok(hkResult
== HKEY_CURRENT_USER
, "expected hkResult == HKEY_CURRENT_USER\n");
1036 /* send in NULL lpSubKey and NULL hKey
1037 * hkResult is set to NULL
1039 hkResult
= hkPreserve
;
1040 ret
= RegOpenKeyA(NULL
, NULL
, &hkResult
);
1041 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1042 ok(hkResult
== NULL
, "expected hkResult == NULL\n");
1044 /* only send NULL hKey
1045 * the value of hkResult remains unchanged
1047 hkResult
= hkPreserve
;
1048 ret
= RegOpenKeyA(NULL
, "Software\\Wine\\Test", &hkResult
);
1049 ok(ret
== ERROR_INVALID_HANDLE
|| ret
== ERROR_BADKEY
, /* Windows 95 returns BADKEY */
1050 "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret
);
1051 ok(hkResult
== hkPreserve
, "expected hkResult == hkPreserve\n");
1053 /* send in NULL hkResult */
1054 ret
= RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Test", NULL
);
1055 ok(ret
== ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", ret
);
1057 ret
= RegOpenKeyA(HKEY_CURRENT_USER
, NULL
, NULL
);
1058 ok(ret
== ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", ret
);
1060 ret
= RegOpenKeyA(NULL
, NULL
, NULL
);
1061 ok(ret
== ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", ret
);
1063 /* beginning backslash character */
1064 ret
= RegOpenKeyA(HKEY_CURRENT_USER
, "\\Software\\Wine\\Test", &hkResult
);
1065 ok(ret
== ERROR_BAD_PATHNAME
|| /* NT/2k/XP */
1066 broken(ret
== ERROR_SUCCESS
), /* wow64 */
1067 "expected ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret
);
1068 if (!ret
) RegCloseKey(hkResult
);
1071 ret
= RegOpenKeyExA(HKEY_CLASSES_ROOT
, "\\clsid", 0, KEY_QUERY_VALUE
, &hkResult
);
1072 ok(ret
== ERROR_SUCCESS
|| /* 2k/XP */
1073 ret
== ERROR_BAD_PATHNAME
, /* NT */
1074 "expected ERROR_SUCCESS, ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret
);
1075 RegCloseKey(hkResult
);
1077 /* NULL or empty subkey of special root */
1079 ret
= RegOpenKeyExA(HKEY_CLASSES_ROOT
, NULL
, 0, KEY_QUERY_VALUE
, &hkResult
);
1080 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1081 ok(hkResult
== HKEY_CLASSES_ROOT
, "expected hkResult == HKEY_CLASSES_ROOT\n");
1084 ret
= RegOpenKeyExA(HKEY_CLASSES_ROOT
, "", 0, KEY_QUERY_VALUE
, &hkResult
);
1085 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1086 ok(hkResult
== HKEY_CLASSES_ROOT
, "expected hkResult == HKEY_CLASSES_ROOT\n");
1089 ret
= RegOpenKeyExA(HKEY_CLASSES_ROOT
, "\\", 0, KEY_QUERY_VALUE
, &hkResult
);
1090 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1091 ok(hkResult
!= HKEY_CLASSES_ROOT
, "expected hkResult to be a new key\n");
1092 ok(!RegCloseKey(hkResult
), "got invalid hkey\n");
1094 /* empty subkey of existing handle */
1095 hkResult
= hkPreserve
;
1096 ret
= RegOpenKeyExA(hkPreserve
, "", 0, KEY_QUERY_VALUE
, &hkResult
);
1097 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1098 ok(hkResult
!= hkPreserve
, "expected hkResult != hkPreserve\n");
1099 ok(!RegCloseKey(hkResult
), "got invalid hkey\n");
1101 /* NULL subkey of existing handle */
1102 hkResult
= hkPreserve
;
1103 ret
= RegOpenKeyExA(hkPreserve
, NULL
, 0, KEY_QUERY_VALUE
, &hkResult
);
1104 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1105 ok(hkResult
!= hkPreserve
, "expected hkResult != hkPreserve\n");
1106 ok(!RegCloseKey(hkResult
), "got invalid hkey\n");
1108 /* empty subkey of NULL */
1109 hkResult
= hkPreserve
;
1110 ret
= RegOpenKeyExW(NULL
, L
"", 0, KEY_QUERY_VALUE
, &hkResult
);
1111 ok(ret
== ERROR_INVALID_HANDLE
, "expected ERROR_INVALID_HANDLE, got %d\n", ret
);
1112 ok(hkResult
== NULL
|| broken(hkResult
== hkPreserve
/* Windows XP */), "expected hkResult == NULL\n");
1114 hkResult
= hkPreserve
;
1115 ret
= RegOpenKeyExA(NULL
, "", 0, KEY_QUERY_VALUE
, &hkResult
);
1116 ok(ret
== ERROR_INVALID_HANDLE
, "expected ERROR_INVALID_HANDLE, got %d\n", ret
);
1117 ok(hkResult
== hkPreserve
, "expected hkResult == hkPreserve\n");
1119 RegCloseKey(hkPreserve
);
1123 ret
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
, "Software", 0, KEY_READ
|KEY_WOW64_32KEY
, &hkResult
);
1124 ok((ret
== ERROR_SUCCESS
&& hkResult
!= NULL
) || broken(ret
== ERROR_ACCESS_DENIED
/* NT4, win2k */),
1125 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret
);
1126 RegCloseKey(hkResult
);
1129 ret
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
, "Software", 0, KEY_READ
|KEY_WOW64_64KEY
, &hkResult
);
1130 ok((ret
== ERROR_SUCCESS
&& hkResult
!= NULL
) || broken(ret
== ERROR_ACCESS_DENIED
/* NT4, win2k */),
1131 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret
);
1132 RegCloseKey(hkResult
);
1134 /* check special HKEYs on 64bit
1135 * only the lower 4 bytes of the supplied key are used
1139 /* HKEY_CURRENT_USER */
1140 ret
= RegOpenKeyA(UlongToHandle(HandleToUlong(HKEY_CURRENT_USER
)), "Software", &hkResult
);
1141 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1142 ok(hkResult
!= NULL
, "expected hkResult != NULL\n");
1143 RegCloseKey(hkResult
);
1145 ret
= RegOpenKeyA((HKEY
)(HandleToUlong(HKEY_CURRENT_USER
) | (ULONG64
)1 << 32), "Software", &hkResult
);
1146 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1147 ok(hkResult
!= NULL
, "expected hkResult != NULL\n");
1148 RegCloseKey(hkResult
);
1150 ret
= RegOpenKeyA((HKEY
)(HandleToUlong(HKEY_CURRENT_USER
) | (ULONG64
)0xdeadbeef << 32), "Software", &hkResult
);
1151 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1152 ok(hkResult
!= NULL
, "expected hkResult != NULL\n");
1153 RegCloseKey(hkResult
);
1155 ret
= RegOpenKeyA((HKEY
)(HandleToUlong(HKEY_CURRENT_USER
) | (ULONG64
)0xffffffff << 32), "Software", &hkResult
);
1156 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1157 ok(hkResult
!= NULL
, "expected hkResult != NULL\n");
1158 RegCloseKey(hkResult
);
1160 /* HKEY_LOCAL_MACHINE */
1161 ret
= RegOpenKeyA((HKEY
)(HandleToUlong(HKEY_LOCAL_MACHINE
) | (ULONG64
)0xdeadbeef << 32), "Software", &hkResult
);
1162 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1163 ok(hkResult
!= NULL
, "expected hkResult != NULL\n");
1164 RegCloseKey(hkResult
);
1167 /* Try using WOW64 flags when opening a key with a DACL set to verify that
1168 * the registry access check is performed correctly. Redirection isn't
1169 * being tested, so the tests don't care about whether the process is
1170 * running under WOW64. */
1171 if (!pIsWow64Process
)
1173 win_skip("WOW64 flags are not recognized\n");
1177 ret
= RegCreateKeyExA(HKEY_LOCAL_MACHINE
, "Software\\Wine", 0, NULL
, 0,
1178 KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, NULL
, &hkRoot32
, NULL
);
1180 ok(ret
== ERROR_ACCESS_DENIED
&& hkRoot32
== NULL
,
1181 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret
);
1183 ok(ret
== ERROR_SUCCESS
&& hkRoot32
!= NULL
,
1184 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret
);
1186 ret
= RegCreateKeyExA(HKEY_LOCAL_MACHINE
, "Software\\Wine", 0, NULL
, 0,
1187 KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, NULL
, &hkRoot64
, NULL
);
1189 ok(ret
== ERROR_ACCESS_DENIED
&& hkRoot64
== NULL
,
1190 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret
);
1192 ok(ret
== ERROR_SUCCESS
&& hkRoot64
!= NULL
,
1193 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret
);
1195 bRet
= AllocateAndInitializeSid(&sid_authority
, 1, SECURITY_WORLD_RID
,
1196 0, 0, 0, 0, 0, 0, 0, &world_sid
);
1198 "Expected AllocateAndInitializeSid to return TRUE, got %d, last error %u\n", bRet
, GetLastError());
1200 access
.grfAccessPermissions
= GENERIC_ALL
| STANDARD_RIGHTS_ALL
;
1201 access
.grfAccessMode
= SET_ACCESS
;
1202 access
.grfInheritance
= SUB_CONTAINERS_AND_OBJECTS_INHERIT
;
1203 access
.Trustee
.pMultipleTrustee
= NULL
;
1204 access
.Trustee
.MultipleTrusteeOperation
= NO_MULTIPLE_TRUSTEE
;
1205 access
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
1206 access
.Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
1207 access
.Trustee
.ptstrName
= (char *)world_sid
;
1209 ret
= SetEntriesInAclA(1, &access
, NULL
, &key_acl
);
1210 ok(ret
== ERROR_SUCCESS
,
1211 "Expected SetEntriesInAclA to return ERROR_SUCCESS, got %u, last error %u\n", ret
, GetLastError());
1213 sd
= HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH
);
1214 bRet
= InitializeSecurityDescriptor(sd
, SECURITY_DESCRIPTOR_REVISION
);
1216 "Expected InitializeSecurityDescriptor to return TRUE, got %d, last error %u\n", bRet
, GetLastError());
1218 bRet
= SetSecurityDescriptorDacl(sd
, TRUE
, key_acl
, FALSE
);
1220 "Expected SetSecurityDescriptorDacl to return TRUE, got %d, last error %u\n", bRet
, GetLastError());
1224 skip("not enough privileges to modify HKLM\n");
1230 error
= RegSetKeySecurity(hkRoot64
, DACL_SECURITY_INFORMATION
, sd
);
1231 ok(error
== ERROR_SUCCESS
,
1232 "Expected RegSetKeySecurity to return success, got error %u\n", error
);
1234 error
= RegSetKeySecurity(hkRoot32
, DACL_SECURITY_INFORMATION
, sd
);
1235 ok(error
== ERROR_SUCCESS
,
1236 "Expected RegSetKeySecurity to return success, got error %u\n", error
);
1239 ret
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
, "Software\\Wine", 0, KEY_WOW64_64KEY
| KEY_READ
, &hkResult
);
1240 ok(ret
== ERROR_SUCCESS
&& hkResult
!= NULL
,
1241 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret
);
1242 RegCloseKey(hkResult
);
1245 ret
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
, "Software\\Wine", 0, KEY_WOW64_32KEY
| KEY_READ
, &hkResult
);
1246 ok(ret
== ERROR_SUCCESS
&& hkResult
!= NULL
,
1247 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret
);
1248 RegCloseKey(hkResult
);
1251 HeapFree(GetProcessHeap(), 0, sd
);
1254 RegDeleteKeyA(hkRoot64
, "");
1255 RegCloseKey(hkRoot64
);
1256 RegDeleteKeyA(hkRoot32
, "");
1257 RegCloseKey(hkRoot32
);
1260 static void test_reg_create_key(void)
1264 HKEY hkRoot64
= NULL
;
1265 HKEY hkRoot32
= NULL
;
1268 SID_IDENTIFIER_AUTHORITY sid_authority
= {SECURITY_WORLD_SID_AUTHORITY
};
1270 EXPLICIT_ACCESSA access
;
1272 SECURITY_DESCRIPTOR
*sd
;
1274 ret
= RegCreateKeyExA(hkey_main
, "Subkey1", 0, NULL
, 0, KEY_NOTIFY
, NULL
, &hkey1
, NULL
);
1275 ok(!ret
, "RegCreateKeyExA failed with error %d\n", ret
);
1276 /* should succeed: all versions of Windows ignore the access rights
1277 * to the parent handle */
1278 ret
= RegCreateKeyExA(hkey1
, "Subkey2", 0, NULL
, 0, KEY_SET_VALUE
, NULL
, &hkey2
, NULL
);
1279 ok(!ret
, "RegCreateKeyExA failed with error %d\n", ret
);
1282 RegDeleteKeyA(hkey2
, "");
1283 RegDeleteKeyA(hkey1
, "");
1287 /* test creation of volatile keys */
1288 ret
= RegCreateKeyExA(hkey_main
, "Volatile", 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey1
, NULL
);
1289 ok(!ret
, "RegCreateKeyExA failed with error %d\n", ret
);
1290 ret
= RegCreateKeyExA(hkey1
, "Subkey2", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey2
, NULL
);
1291 ok(ret
== ERROR_CHILD_MUST_BE_VOLATILE
, "RegCreateKeyExA failed with error %d\n", ret
);
1292 if (!ret
) RegCloseKey( hkey2
);
1293 ret
= RegCreateKeyExA(hkey1
, "Subkey2", 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey2
, NULL
);
1294 ok(!ret
, "RegCreateKeyExA failed with error %d\n", ret
);
1296 /* should succeed if the key already exists */
1297 ret
= RegCreateKeyExA(hkey1
, "Subkey2", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey2
, NULL
);
1298 ok(!ret
, "RegCreateKeyExA failed with error %d\n", ret
);
1301 RegDeleteKeyA(hkey2
, "");
1302 RegDeleteKeyA(hkey1
, "");
1306 /* beginning backslash character */
1307 ret
= RegCreateKeyExA(hkey_main
, "\\Subkey3", 0, NULL
, 0, KEY_NOTIFY
, NULL
, &hkey1
, NULL
);
1308 if (!(GetVersion() & 0x80000000))
1309 ok(ret
== ERROR_BAD_PATHNAME
, "expected ERROR_BAD_PATHNAME, got %d\n", ret
);
1311 ok(!ret
, "RegCreateKeyExA failed with error %d\n", ret
);
1312 RegDeleteKeyA(hkey1
, "");
1316 /* trailing backslash characters */
1317 ret
= RegCreateKeyExA(hkey_main
, "Subkey4\\\\", 0, NULL
, 0, KEY_NOTIFY
, NULL
, &hkey1
, NULL
);
1318 ok(ret
== ERROR_SUCCESS
, "RegCreateKeyExA failed with error %d\n", ret
);
1319 RegDeleteKeyA(hkey1
, "");
1322 /* WOW64 flags - open an existing key */
1324 ret
= RegCreateKeyExA(HKEY_LOCAL_MACHINE
, "Software", 0, NULL
, 0, KEY_READ
|KEY_WOW64_32KEY
, NULL
, &hkey1
, NULL
);
1325 ok((ret
== ERROR_SUCCESS
&& hkey1
!= NULL
) || broken(ret
== ERROR_ACCESS_DENIED
/* NT4, win2k */),
1326 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret
);
1330 ret
= RegCreateKeyExA(HKEY_LOCAL_MACHINE
, "Software", 0, NULL
, 0, KEY_READ
|KEY_WOW64_64KEY
, NULL
, &hkey1
, NULL
);
1331 ok((ret
== ERROR_SUCCESS
&& hkey1
!= NULL
) || broken(ret
== ERROR_ACCESS_DENIED
/* NT4, win2k */),
1332 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret
);
1335 /* Try using WOW64 flags when opening a key with a DACL set to verify that
1336 * the registry access check is performed correctly. Redirection isn't
1337 * being tested, so the tests don't care about whether the process is
1338 * running under WOW64. */
1339 if (!pIsWow64Process
)
1341 win_skip("WOW64 flags are not recognized\n");
1345 ret
= RegCreateKeyExA(HKEY_LOCAL_MACHINE
, "Software\\Wine", 0, NULL
, 0,
1346 KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, NULL
, &hkRoot32
, NULL
);
1348 ok(ret
== ERROR_ACCESS_DENIED
&& hkRoot32
== NULL
,
1349 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%d)\n", ret
);
1351 ok(ret
== ERROR_SUCCESS
&& hkRoot32
!= NULL
,
1352 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%d)\n", ret
);
1354 ret
= RegCreateKeyExA(HKEY_LOCAL_MACHINE
, "Software\\Wine", 0, NULL
, 0,
1355 KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, NULL
, &hkRoot64
, NULL
);
1357 ok(ret
== ERROR_ACCESS_DENIED
&& hkRoot64
== NULL
,
1358 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%d)\n", ret
);
1360 ok(ret
== ERROR_SUCCESS
&& hkRoot64
!= NULL
,
1361 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%d)\n", ret
);
1363 bRet
= AllocateAndInitializeSid(&sid_authority
, 1, SECURITY_WORLD_RID
,
1364 0, 0, 0, 0, 0, 0, 0, &world_sid
);
1366 "Expected AllocateAndInitializeSid to return TRUE, got %d, last error %u\n", bRet
, GetLastError());
1368 access
.grfAccessPermissions
= GENERIC_ALL
| STANDARD_RIGHTS_ALL
;
1369 access
.grfAccessMode
= SET_ACCESS
;
1370 access
.grfInheritance
= SUB_CONTAINERS_AND_OBJECTS_INHERIT
;
1371 access
.Trustee
.pMultipleTrustee
= NULL
;
1372 access
.Trustee
.MultipleTrusteeOperation
= NO_MULTIPLE_TRUSTEE
;
1373 access
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
1374 access
.Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
1375 access
.Trustee
.ptstrName
= (char *)world_sid
;
1377 dwRet
= SetEntriesInAclA(1, &access
, NULL
, &key_acl
);
1378 ok(dwRet
== ERROR_SUCCESS
,
1379 "Expected SetEntriesInAclA to return ERROR_SUCCESS, got %u, last error %u\n", dwRet
, GetLastError());
1381 sd
= HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH
);
1382 bRet
= InitializeSecurityDescriptor(sd
, SECURITY_DESCRIPTOR_REVISION
);
1384 "Expected InitializeSecurityDescriptor to return TRUE, got %d, last error %u\n", bRet
, GetLastError());
1386 bRet
= SetSecurityDescriptorDacl(sd
, TRUE
, key_acl
, FALSE
);
1388 "Expected SetSecurityDescriptorDacl to return TRUE, got %d, last error %u\n", bRet
, GetLastError());
1392 skip("not enough privileges to modify HKLM\n");
1396 ret
= RegSetKeySecurity(hkRoot64
, DACL_SECURITY_INFORMATION
, sd
);
1397 ok(ret
== ERROR_SUCCESS
,
1398 "Expected RegSetKeySecurity to return success, got error %u\n", ret
);
1400 ret
= RegSetKeySecurity(hkRoot32
, DACL_SECURITY_INFORMATION
, sd
);
1401 ok(ret
== ERROR_SUCCESS
,
1402 "Expected RegSetKeySecurity to return success, got error %u\n", ret
);
1405 ret
= RegCreateKeyExA(HKEY_LOCAL_MACHINE
, "Software\\Wine", 0, NULL
, 0,
1406 KEY_WOW64_64KEY
| KEY_READ
, NULL
, &hkey1
, NULL
);
1407 ok(ret
== ERROR_SUCCESS
&& hkey1
!= NULL
,
1408 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret
);
1412 ret
= RegCreateKeyExA(HKEY_LOCAL_MACHINE
, "Software\\Wine", 0, NULL
, 0,
1413 KEY_WOW64_32KEY
| KEY_READ
, NULL
, &hkey1
, NULL
);
1414 ok(ret
== ERROR_SUCCESS
&& hkey1
!= NULL
,
1415 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret
);
1419 HeapFree(GetProcessHeap(), 0, sd
);
1422 RegDeleteKeyA(hkRoot64
, "");
1423 RegCloseKey(hkRoot64
);
1424 RegDeleteKeyA(hkRoot32
, "");
1425 RegCloseKey(hkRoot32
);
1428 static void test_reg_close_key(void)
1433 /* successfully close key
1434 * hkHandle remains changed after call to RegCloseKey
1436 ret
= RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Test", &hkHandle
);
1437 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1438 ret
= RegCloseKey(hkHandle
);
1439 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1441 /* try to close the key twice */
1442 ret
= RegCloseKey(hkHandle
); /* Windows 95 doesn't mind. */
1443 ok(ret
== ERROR_INVALID_HANDLE
|| ret
== ERROR_SUCCESS
,
1444 "expected ERROR_INVALID_HANDLE or ERROR_SUCCESS, got %d\n", ret
);
1446 /* try to close a NULL handle */
1447 ret
= RegCloseKey(NULL
);
1448 ok(ret
== ERROR_INVALID_HANDLE
|| ret
== ERROR_BADKEY
, /* Windows 95 returns BADKEY */
1449 "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret
);
1451 /* Check to see if we didn't potentially close our main handle, which could happen on win98 as
1452 * win98 doesn't give a new handle when the same key is opened.
1453 * Not re-opening will make some next tests fail.
1455 if (hkey_main
== hkHandle
)
1457 trace("The main handle is most likely closed, so re-opening\n");
1458 RegOpenKeyA( HKEY_CURRENT_USER
, "Software\\Wine\\Test", &hkey_main
);
1462 static void test_reg_delete_key(void)
1467 ret
= RegDeleteKeyA(hkey_main
, NULL
);
1469 /* There is a bug in NT4 and W2K that doesn't check if the subkey is NULL. If
1470 * there are also no subkeys available it will delete the key pointed to by hkey_main.
1471 * Not re-creating will make some next tests fail.
1473 if (ret
== ERROR_SUCCESS
)
1475 trace("We are probably running on NT4 or W2K as the main key is deleted,"
1476 " re-creating the main key\n");
1480 ok(ret
== ERROR_INVALID_PARAMETER
||
1481 ret
== ERROR_ACCESS_DENIED
||
1482 ret
== ERROR_BADKEY
, /* Win95 */
1485 ret
= RegCreateKeyA(hkey_main
, "deleteme", &key
);
1486 ok(ret
== ERROR_SUCCESS
, "Could not create key, got %d\n", ret
);
1487 ret
= RegDeleteKeyA(key
, "");
1488 ok(ret
== ERROR_SUCCESS
, "RegDeleteKeyA failed, got %d\n", ret
);
1490 ret
= RegOpenKeyA(hkey_main
, "deleteme", &key
);
1491 ok(ret
== ERROR_FILE_NOT_FOUND
, "Key was not deleted, got %d\n", ret
);
1495 static BOOL
set_privileges(LPCSTR privilege
, BOOL set
)
1497 TOKEN_PRIVILEGES tp
;
1501 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
, &hToken
))
1504 if(!LookupPrivilegeValueA(NULL
, privilege
, &luid
))
1506 CloseHandle(hToken
);
1510 tp
.PrivilegeCount
= 1;
1511 tp
.Privileges
[0].Luid
= luid
;
1514 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
1516 tp
.Privileges
[0].Attributes
= 0;
1518 AdjustTokenPrivileges(hToken
, FALSE
, &tp
, sizeof(TOKEN_PRIVILEGES
), NULL
, NULL
);
1519 if (GetLastError() != ERROR_SUCCESS
)
1521 CloseHandle(hToken
);
1525 CloseHandle(hToken
);
1529 static void test_reg_save_key(void)
1533 if (!set_privileges(SE_BACKUP_NAME
, TRUE
) ||
1534 !set_privileges(SE_RESTORE_NAME
, FALSE
))
1536 win_skip("Failed to set SE_BACKUP_NAME privileges, skipping tests\n");
1540 ret
= RegSaveKeyA(hkey_main
, "saved_key", NULL
);
1541 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1543 set_privileges(SE_BACKUP_NAME
, FALSE
);
1546 static void test_reg_load_key(void)
1551 if (!set_privileges(SE_RESTORE_NAME
, TRUE
) ||
1552 !set_privileges(SE_BACKUP_NAME
, FALSE
))
1554 win_skip("Failed to set SE_RESTORE_NAME privileges, skipping tests\n");
1558 ret
= RegLoadKeyA(HKEY_LOCAL_MACHINE
, "Test", "saved_key");
1559 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1561 set_privileges(SE_RESTORE_NAME
, FALSE
);
1563 ret
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Test", &hkHandle
);
1564 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1566 RegCloseKey(hkHandle
);
1569 static void test_reg_unload_key(void)
1571 UNICODE_STRING key_name
;
1572 OBJECT_ATTRIBUTES attr
;
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");
1584 ret
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
, "Test", 0, KEY_READ
, &key
);
1585 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1587 /* try to unload though the key handle is live */
1588 pRtlInitUnicodeString(&key_name
, L
"\\REGISTRY\\Machine\\Test");
1589 InitializeObjectAttributes(&attr
, &key_name
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
1590 status
= pNtUnloadKey(&attr
);
1591 ok(status
== STATUS_CANNOT_DELETE
, "expected STATUS_CANNOT_DELETE, got %08x\n", status
);
1595 ret
= RegUnLoadKeyA(HKEY_LOCAL_MACHINE
, "Test");
1596 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
1598 set_privileges(SE_RESTORE_NAME
, FALSE
);
1600 DeleteFileA("saved_key");
1601 DeleteFileA("saved_key.LOG");
1604 /* tests that show that RegConnectRegistry and
1605 OpenSCManager accept computer names without the
1606 \\ prefix (what MSDN says). */
1607 static void test_regconnectregistry( void)
1609 CHAR compName
[MAX_COMPUTERNAME_LENGTH
+ 1];
1610 CHAR netwName
[MAX_COMPUTERNAME_LENGTH
+ 3]; /* 2 chars for double backslash */
1611 DWORD len
= sizeof(compName
) ;
1617 SetLastError(0xdeadbeef);
1618 ret
= GetComputerNameA(compName
, &len
);
1619 ok( ret
, "GetComputerName failed err = %d\n", GetLastError());
1622 lstrcpyA(netwName
, "\\\\");
1623 lstrcpynA(netwName
+2, compName
, MAX_COMPUTERNAME_LENGTH
+ 1);
1625 retl
= RegConnectRegistryA( compName
, HKEY_LOCAL_MACHINE
, &hkey
);
1627 retl
== ERROR_DLL_INIT_FAILED
||
1628 retl
== ERROR_BAD_NETPATH
, /* some win2k */
1629 "RegConnectRegistryA failed err = %d\n", retl
);
1630 if( !retl
) RegCloseKey( hkey
);
1632 retl
= RegConnectRegistryA( netwName
, HKEY_LOCAL_MACHINE
, &hkey
);
1634 retl
== ERROR_DLL_INIT_FAILED
||
1635 retl
== ERROR_BAD_NETPATH
, /* some win2k */
1636 "RegConnectRegistryA failed err = %d\n", retl
);
1637 if( !retl
) RegCloseKey( hkey
);
1639 SetLastError(0xdeadbeef);
1640 schnd
= OpenSCManagerA( compName
, NULL
, GENERIC_READ
);
1641 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1643 win_skip("OpenSCManagerA is not implemented\n");
1647 ok( schnd
!= NULL
, "OpenSCManagerA failed err = %d\n", GetLastError());
1648 CloseServiceHandle( schnd
);
1650 SetLastError(0xdeadbeef);
1651 schnd
= OpenSCManagerA( netwName
, NULL
, GENERIC_READ
);
1652 ok( schnd
!= NULL
, "OpenSCManagerA failed err = %d\n", GetLastError());
1653 CloseServiceHandle( schnd
);
1657 static void test_reg_query_value(void)
1664 ret
= RegCreateKeyA(hkey_main
, "subkey", &subkey
);
1665 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1667 ret
= RegSetValueA(subkey
, NULL
, REG_SZ
, "data", 4);
1668 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1670 /* try an invalid hkey */
1671 SetLastError(0xdeadbeef);
1673 ret
= RegQueryValueA((HKEY
)0xcafebabe, "subkey", val
, &size
);
1674 ok(ret
== ERROR_INVALID_HANDLE
||
1675 ret
== ERROR_BADKEY
|| /* Windows 98 returns BADKEY */
1676 ret
== ERROR_ACCESS_DENIED
, /* non-admin winxp */
1677 "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret
);
1678 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1680 /* try a NULL hkey */
1681 SetLastError(0xdeadbeef);
1683 ret
= RegQueryValueA(NULL
, "subkey", val
, &size
);
1684 ok(ret
== ERROR_INVALID_HANDLE
|| ret
== ERROR_BADKEY
, /* Windows 98 returns BADKEY */
1685 "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret
);
1686 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1688 /* try a NULL value */
1690 ret
= RegQueryValueA(hkey_main
, "subkey", NULL
, &size
);
1691 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1692 ok(size
== 5, "Expected 5, got %d\n", size
);
1694 /* try a NULL size */
1695 SetLastError(0xdeadbeef);
1697 ret
= RegQueryValueA(hkey_main
, "subkey", val
, NULL
);
1698 ok(ret
== ERROR_INVALID_PARAMETER
, "Expected ERROR_INVALID_PARAMETER, got %d\n", ret
);
1699 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1700 ok(!val
[0], "Expected val to be untouched, got %s\n", val
);
1702 /* try a NULL value and size */
1703 ret
= RegQueryValueA(hkey_main
, "subkey", NULL
, NULL
);
1704 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1706 /* try a size too small */
1707 SetLastError(0xdeadbeef);
1710 ret
= RegQueryValueA(hkey_main
, "subkey", val
, &size
);
1711 ok(ret
== ERROR_MORE_DATA
, "Expected ERROR_MORE_DATA, got %d\n", ret
);
1712 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1713 ok(!val
[0], "Expected val to be untouched, got %s\n", val
);
1714 ok(size
== 5, "Expected 5, got %d\n", size
);
1716 /* successfully read the value using 'subkey' */
1718 ret
= RegQueryValueA(hkey_main
, "subkey", val
, &size
);
1719 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1720 ok(!lstrcmpA(val
, "data"), "Expected 'data', got '%s'\n", val
);
1721 ok(size
== 5, "Expected 5, got %d\n", size
);
1723 /* successfully read the value using the subkey key */
1725 ret
= RegQueryValueA(subkey
, NULL
, val
, &size
);
1726 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1727 ok(!lstrcmpA(val
, "data"), "Expected 'data', got '%s'\n", val
);
1728 ok(size
== 5, "Expected 5, got %d\n", size
);
1730 /* unicode - try size too small */
1731 SetLastError(0xdeadbeef);
1734 ret
= RegQueryValueW(subkey
, NULL
, valW
, &size
);
1735 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1737 win_skip("RegQueryValueW is not implemented\n");
1740 ok(ret
== ERROR_MORE_DATA
, "Expected ERROR_MORE_DATA, got %d\n", ret
);
1741 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1742 ok(!valW
[0], "Expected valW to be untouched\n");
1743 ok(size
== 10, "Got wrong size: %d\n", size
);
1745 /* unicode - try size in WCHARS */
1746 SetLastError(0xdeadbeef);
1747 size
= ARRAY_SIZE(valW
);
1748 ret
= RegQueryValueW(subkey
, NULL
, valW
, &size
);
1749 ok(ret
== ERROR_MORE_DATA
, "Expected ERROR_MORE_DATA, got %d\n", ret
);
1750 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1751 ok(!valW
[0], "Expected valW to be untouched\n");
1752 ok(size
== 10, "Got wrong size: %d\n", size
);
1754 /* unicode - successfully read the value */
1755 size
= sizeof(valW
);
1756 ret
= RegQueryValueW(subkey
, NULL
, valW
, &size
);
1757 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1758 ok(!lstrcmpW(valW
, L
"data"), "Got wrong value\n");
1759 ok(size
== 10, "Got wrong size: %d\n", size
);
1761 /* unicode - set the value without a NULL terminator */
1762 ret
= RegSetValueW(subkey
, NULL
, REG_SZ
, L
"data", 8);
1763 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1765 /* unicode - read the unterminated value, value is terminated for us */
1766 memset(valW
, 'a', sizeof(valW
));
1767 size
= sizeof(valW
);
1768 ret
= RegQueryValueW(subkey
, NULL
, valW
, &size
);
1769 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1770 ok(!lstrcmpW(valW
, L
"data"), "Got wrong value\n");
1771 ok(size
== 10, "Got wrong size: %d\n", size
);
1774 RegDeleteKeyA(subkey
, "");
1775 RegCloseKey(subkey
);
1778 static void test_reg_query_info(void)
1783 char classbuffer
[32];
1784 WCHAR classbufferW
[32];
1785 char expectbuffer
[32];
1786 WCHAR expectbufferW
[32];
1787 char subkey_class
[] = "subkey class";
1788 WCHAR subkey_classW
[] = L
"subkey class";
1789 char subsubkey_class
[] = "subsubkey class";
1791 DWORD subkeys
, maxsubkeylen
, maxclasslen
;
1792 DWORD values
, maxvaluenamelen
, maxvaluelen
;
1796 ret
= RegCreateKeyExA(hkey_main
, "subkey", 0, subkey_class
, 0, KEY_ALL_ACCESS
, NULL
, &subkey
, NULL
);
1797 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1799 /* all parameters NULL */
1800 ret
= RegQueryInfoKeyA(NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1801 ok(ret
== ERROR_INVALID_HANDLE
, "ret = %d\n", ret
);
1803 ret
= RegQueryInfoKeyW(NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1804 ok(ret
== ERROR_INVALID_HANDLE
, "ret = %d\n", ret
);
1806 /* not requesting any information */
1807 ret
= RegQueryInfoKeyA(subkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1808 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
1810 ret
= RegQueryInfoKeyW(subkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1811 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
1813 /* class without length is invalid */
1814 memset(classbuffer
, 0x55, sizeof(classbuffer
));
1815 ret
= RegQueryInfoKeyA(subkey
, classbuffer
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1816 ok(ret
== ERROR_INVALID_PARAMETER
, "ret = %d\n", ret
);
1817 ok(classbuffer
[0] == 0x55, "classbuffer[0] = 0x%x\n", classbuffer
[0]);
1819 memset(classbufferW
, 0x55, sizeof(classbufferW
));
1820 ret
= RegQueryInfoKeyW(subkey
, classbufferW
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1821 ok(ret
== ERROR_INVALID_PARAMETER
, "ret = %d\n", ret
);
1822 ok(classbufferW
[0] == 0x5555, "classbufferW[0] = 0x%x\n", classbufferW
[0]);
1825 sdlen
= classlen
=0;
1826 ret
= RegQueryInfoKeyA(subkey
, NULL
, &classlen
, NULL
, &subkeys
, &maxsubkeylen
, &maxclasslen
, &values
, &maxvaluenamelen
, &maxvaluelen
, &sdlen
, &lastwrite
);
1827 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
1828 ok(classlen
== strlen(subkey_class
), "classlen = %u\n", classlen
);
1829 ok(subkeys
== 0, "subkeys = %u\n", subkeys
);
1830 ok(maxsubkeylen
== 0, "maxsubkeylen = %u\n", maxsubkeylen
);
1831 ok(maxclasslen
== 0, "maxclasslen = %u\n", maxclasslen
);
1832 ok(values
== 0, "values = %u\n", values
);
1833 ok(maxvaluenamelen
== 0, "maxvaluenamelen = %u\n", maxvaluenamelen
);
1834 ok(maxvaluelen
== 0, "maxvaluelen = %u\n", maxvaluelen
);
1835 todo_wine
ok(sdlen
!= 0, "sdlen = %u\n", sdlen
);
1836 ok(lastwrite
.dwLowDateTime
!= 0, "lastwrite.dwLowDateTime = %u\n", lastwrite
.dwLowDateTime
);
1837 ok(lastwrite
.dwHighDateTime
!= 0, "lastwrite.dwHighDateTime = %u\n", lastwrite
.dwHighDateTime
);
1839 sdlen
= classlen
= 0;
1840 ret
= RegQueryInfoKeyW(subkey
, NULL
, &classlen
, NULL
, &subkeys
, &maxsubkeylen
, &maxclasslen
, &values
, &maxvaluenamelen
, &maxvaluelen
, &sdlen
, &lastwrite
);
1841 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
1842 ok(classlen
== strlen(subkey_class
), "classlen = %u\n", classlen
);
1843 ok(subkeys
== 0, "subkeys = %u\n", subkeys
);
1844 ok(maxsubkeylen
== 0, "maxsubkeylen = %u\n", maxsubkeylen
);
1845 ok(maxclasslen
== 0, "maxclasslen = %u\n", maxclasslen
);
1846 ok(values
== 0, "values = %u\n", values
);
1847 ok(maxvaluenamelen
== 0, "maxvaluenamelen = %u\n", maxvaluenamelen
);
1848 ok(maxvaluelen
== 0, "maxvaluelen = %u\n", maxvaluelen
);
1849 todo_wine
ok(sdlen
!= 0, "sdlen = %u\n", sdlen
);
1850 ok(lastwrite
.dwLowDateTime
!= 0, "lastwrite.dwLowDateTime = %u\n", lastwrite
.dwLowDateTime
);
1851 ok(lastwrite
.dwHighDateTime
!= 0, "lastwrite.dwHighDateTime = %u\n", lastwrite
.dwHighDateTime
);
1853 ret
= RegCreateKeyExA(subkey
, "subsubkey", 0, subsubkey_class
, 0, KEY_ALL_ACCESS
, NULL
, &subsubkey
, NULL
);
1854 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1856 ret
= RegSetValueExA(subkey
, NULL
, 0, REG_SZ
, (const BYTE
*)"data", 5);
1857 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1859 /* with subkey & default value */
1860 sdlen
= classlen
= 0;
1861 ret
= RegQueryInfoKeyA(subkey
, NULL
, &classlen
, NULL
, &subkeys
, &maxsubkeylen
, &maxclasslen
, &values
, &maxvaluenamelen
, &maxvaluelen
, &sdlen
, &lastwrite
);
1862 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
1863 ok(classlen
== strlen(subkey_class
), "classlen = %u\n", classlen
);
1864 ok(subkeys
== 1, "subkeys = %u\n", subkeys
);
1865 ok(maxsubkeylen
== strlen("subsubkey"), "maxsubkeylen = %u\n", maxsubkeylen
);
1866 ok(maxclasslen
== strlen(subsubkey_class
), "maxclasslen = %u\n", maxclasslen
);
1867 ok(values
== 1, "values = %u\n", values
);
1868 ok(maxvaluenamelen
== 0, "maxvaluenamelen = %u\n", maxvaluenamelen
);
1869 ok(maxvaluelen
== sizeof("data") * sizeof(WCHAR
), "maxvaluelen = %u\n", maxvaluelen
);
1870 todo_wine
ok(sdlen
!= 0, "sdlen = %u\n", sdlen
);
1871 ok(lastwrite
.dwLowDateTime
!= 0, "lastwrite.dwLowDateTime = %u\n", lastwrite
.dwLowDateTime
);
1872 ok(lastwrite
.dwHighDateTime
!= 0, "lastwrite.dwHighDateTime = %u\n", lastwrite
.dwHighDateTime
);
1874 sdlen
= classlen
= 0;
1875 ret
= RegQueryInfoKeyW(subkey
, NULL
, &classlen
, NULL
, &subkeys
, &maxsubkeylen
, &maxclasslen
, &values
, &maxvaluenamelen
, &maxvaluelen
, &sdlen
, &lastwrite
);
1876 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
1877 ok(classlen
== strlen(subkey_class
), "classlen = %u\n", classlen
);
1878 ok(subkeys
== 1, "subkeys = %u\n", subkeys
);
1879 ok(maxsubkeylen
== strlen("subsubkey"), "maxsubkeylen = %u\n", maxsubkeylen
);
1880 ok(maxclasslen
== strlen(subsubkey_class
), "maxclasslen = %u\n", maxclasslen
);
1881 ok(values
== 1, "values = %u\n", values
);
1882 ok(maxvaluenamelen
== 0, "maxvaluenamelen = %u\n", maxvaluenamelen
);
1883 ok(maxvaluelen
== sizeof("data") * sizeof(WCHAR
), "maxvaluelen = %u\n", maxvaluelen
);
1884 todo_wine
ok(sdlen
!= 0, "sdlen = %u\n", sdlen
);
1885 ok(lastwrite
.dwLowDateTime
!= 0, "lastwrite.dwLowDateTime = %u\n", lastwrite
.dwLowDateTime
);
1886 ok(lastwrite
.dwHighDateTime
!= 0, "lastwrite.dwHighDateTime = %u\n", lastwrite
.dwHighDateTime
);
1888 ret
= RegSetValueExA(subkey
, "value one", 0, REG_SZ
, (const BYTE
*)"first value data", 17);
1889 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1891 ret
= RegSetValueExA(subkey
, "value 2", 0, REG_SZ
, (const BYTE
*)"second value data", 18);
1892 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
1894 /* with named value */
1896 ret
= RegQueryInfoKeyA(subkey
, NULL
, &classlen
, NULL
, &subkeys
, &maxsubkeylen
, &maxclasslen
, &values
, &maxvaluenamelen
, &maxvaluelen
, &sdlen
, &lastwrite
);
1897 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
1898 ok(values
== 3, "values = %u\n", values
);
1899 ok(maxvaluenamelen
== strlen("value one"), "maxvaluenamelen = %u\n", maxvaluenamelen
);
1900 ok(maxvaluelen
== sizeof("second value data") * sizeof(WCHAR
), "maxvaluelen = %u\n", maxvaluelen
);
1903 ret
= RegQueryInfoKeyW(subkey
, NULL
, &classlen
, NULL
, &subkeys
, &maxsubkeylen
, &maxclasslen
, &values
, &maxvaluenamelen
, &maxvaluelen
, &sdlen
, &lastwrite
);
1904 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
1905 ok(values
== 3, "values = %u\n", values
);
1906 ok(maxvaluenamelen
== strlen("value one"), "maxvaluenamelen = %u\n", maxvaluenamelen
);
1907 ok(maxvaluelen
== sizeof("second value data") * sizeof(WCHAR
), "maxvaluelen = %u\n", maxvaluelen
);
1909 /* class name with zero size buffer */
1910 memset(classbuffer
, 0x55, sizeof(classbuffer
));
1912 ret
= RegQueryInfoKeyA(subkey
, classbuffer
, &classlen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1913 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
1914 ok(classlen
== strlen(subkey_class
) /* win2k */ ||
1915 classlen
== 0, "classlen = %u\n", classlen
);
1916 memset(expectbuffer
, 0x55, sizeof(expectbuffer
));
1917 ok(!memcmp(classbuffer
, expectbuffer
, sizeof(classbuffer
)), "classbuffer was modified\n");
1919 memset(classbufferW
, 0x55, sizeof(classbufferW
));
1921 ret
= RegQueryInfoKeyW(subkey
, classbufferW
, &classlen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1922 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
1923 ok(classlen
== strlen(subkey_class
) /* win2k */ ||
1924 classlen
== 0, "classlen = %u\n", classlen
);
1925 memset(expectbufferW
, 0x55, sizeof(expectbufferW
));
1926 ok(!memcmp(classbufferW
, expectbufferW
, sizeof(classbufferW
)), "classbufferW was modified\n");
1928 /* class name with one char buffer */
1929 memset(classbuffer
, 0x55, sizeof(classbuffer
));
1931 ret
= RegQueryInfoKeyA(subkey
, classbuffer
, &classlen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1932 ok(ret
== ERROR_MORE_DATA
, "ret = %d\n", ret
);
1933 ok(classlen
== 0, "classlen = %u\n", classlen
);
1934 memset(expectbuffer
, 0x55, sizeof(expectbuffer
));
1935 expectbuffer
[0] = 0;
1936 ok(!memcmp(classbuffer
, expectbuffer
, sizeof(classbuffer
)), "classbuffer was modified\n");
1938 memset(classbufferW
, 0x55, sizeof(classbufferW
));
1940 ret
= RegQueryInfoKeyW(subkey
, classbufferW
, &classlen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1941 /* failure-code changed to ERROR_MORE_DATA in recent win10 */
1942 ok((ret
== ERROR_INSUFFICIENT_BUFFER
) || (ret
== ERROR_MORE_DATA
), "ret = %d\n", ret
);
1943 ok(classlen
== 0 /* win8 */ ||
1944 classlen
== strlen(subkey_class
), "classlen = %u\n", classlen
);
1945 memset(expectbufferW
, 0x55, sizeof(expectbufferW
));
1946 ok(!memcmp(classbufferW
, expectbufferW
, sizeof(classbufferW
)), "classbufferW was modified\n");
1948 /* class name with buffer one char too small */
1949 memset(classbuffer
, 0x55, sizeof(classbuffer
));
1950 classlen
= sizeof(subkey_class
) - 1;
1951 ret
= RegQueryInfoKeyA(subkey
, classbuffer
, &classlen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1952 ok(ret
== ERROR_MORE_DATA
, "ret = %d\n", ret
);
1953 ok(classlen
== sizeof(subkey_class
) - 2, "classlen = %u\n", classlen
);
1954 memset(expectbuffer
, 0x55, sizeof(expectbuffer
));
1955 strcpy(expectbuffer
, subkey_class
);
1956 expectbuffer
[sizeof(subkey_class
) - 2] = 0;
1957 expectbuffer
[sizeof(subkey_class
) - 1] = 0x55;
1958 ok(!memcmp(classbuffer
, expectbuffer
, sizeof(classbuffer
)),
1959 "classbuffer = %.*s, expected %s\n",
1960 (int)sizeof(classbuffer
), classbuffer
, expectbuffer
);
1962 memset(classbufferW
, 0x55, sizeof(classbufferW
));
1963 classlen
= sizeof(subkey_class
) - 1;
1964 ret
= RegQueryInfoKeyW(subkey
, classbufferW
, &classlen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1965 ok(ret
== ERROR_INSUFFICIENT_BUFFER
, "ret = %d\n", ret
);
1966 ok(classlen
== sizeof(subkey_class
) - 2 /* win8 */ ||
1967 classlen
== strlen(subkey_class
), "classlen = %u\n", classlen
);
1968 memset(expectbufferW
, 0x55, sizeof(expectbufferW
));
1969 ok(!memcmp(classbufferW
, expectbufferW
, sizeof(classbufferW
)), "classbufferW was modified\n");
1971 /* class name with large enough buffer */
1972 memset(classbuffer
, 0x55, sizeof(classbuffer
));
1973 classlen
= sizeof(subkey_class
);
1974 ret
= RegQueryInfoKeyA(subkey
, classbuffer
, &classlen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1975 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
1976 ok(classlen
== sizeof(subkey_class
) - 1, "classlen = %u\n", classlen
);
1977 memset(expectbuffer
, 0x55, sizeof(expectbuffer
));
1978 strcpy(expectbuffer
, subkey_class
);
1979 ok(!memcmp(classbuffer
, expectbuffer
, sizeof(classbuffer
)),
1980 "classbuffer = \"%.*s\", expected %s\n",
1981 (int)sizeof(classbuffer
), classbuffer
, expectbuffer
);
1983 memset(classbuffer
, 0x55, sizeof(classbuffer
));
1984 classlen
= 0xdeadbeef;
1985 ret
= RegQueryInfoKeyA(subkey
, classbuffer
, &classlen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1986 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
1987 ok(classlen
== sizeof(subkey_class
) - 1, "classlen = %u\n", classlen
);
1988 memset(expectbuffer
, 0x55, sizeof(expectbuffer
));
1989 strcpy(expectbuffer
, subkey_class
);
1990 ok(!memcmp(classbuffer
, expectbuffer
, sizeof(classbuffer
)),
1991 "classbuffer = \"%.*s\", expected %s\n",
1992 (int)sizeof(classbuffer
), classbuffer
, expectbuffer
);
1994 memset(classbufferW
, 0x55, sizeof(classbufferW
));
1995 classlen
= sizeof(subkey_class
);
1996 ret
= RegQueryInfoKeyW(subkey
, classbufferW
, &classlen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1997 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
1998 ok(classlen
== sizeof(subkey_class
) - 1, "classlen = %u\n", classlen
);
1999 memset(expectbufferW
, 0x55, sizeof(expectbufferW
));
2000 lstrcpyW(expectbufferW
, subkey_classW
);
2001 ok(!memcmp(classbufferW
, expectbufferW
, sizeof(classbufferW
)),
2002 "classbufferW = %s, expected %s\n",
2003 wine_dbgstr_wn(classbufferW
, ARRAY_SIZE(classbufferW
)), wine_dbgstr_w(expectbufferW
));
2005 memset(classbufferW
, 0x55, sizeof(classbufferW
));
2006 classlen
= 0xdeadbeef;
2007 ret
= RegQueryInfoKeyW(subkey
, classbufferW
, &classlen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
2008 ok(ret
== ERROR_SUCCESS
, "ret = %d\n", ret
);
2009 ok(classlen
== sizeof(subkey_class
) - 1, "classlen = %u\n", classlen
);
2010 memset(expectbufferW
, 0x55, sizeof(expectbufferW
));
2011 lstrcpyW(expectbufferW
, subkey_classW
);
2012 ok(!memcmp(classbufferW
, expectbufferW
, sizeof(classbufferW
)),
2013 "classbufferW = %s, expected %s\n",
2014 wine_dbgstr_wn(classbufferW
, ARRAY_SIZE(classbufferW
)), wine_dbgstr_w(expectbufferW
));
2016 RegDeleteKeyA(subsubkey
, "");
2017 RegCloseKey(subsubkey
);
2018 RegDeleteKeyA(subkey
, "");
2019 RegCloseKey(subkey
);
2022 static void test_string_termination(void)
2026 static const char string
[] = "FullString";
2029 DWORD insize
, outsize
, nsize
;
2031 ret
= RegCreateKeyA(hkey_main
, "string_termination", &subkey
);
2032 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2034 /* Off-by-one RegSetValueExA -> adds a trailing '\0'! */
2035 insize
=sizeof(string
)-1;
2036 ret
= RegSetValueExA(subkey
, "stringtest", 0, REG_SZ
, (BYTE
*)string
, insize
);
2037 ok(ret
== ERROR_SUCCESS
, "RegSetValueExA failed: %d\n", ret
);
2039 ret
= RegQueryValueExA(subkey
, "stringtest", NULL
, NULL
, buffer
, &outsize
);
2040 ok(ret
== ERROR_MORE_DATA
, "RegQueryValueExA returned: %d\n", ret
);
2042 /* Off-by-two RegSetValueExA -> no trailing '\0' */
2043 insize
=sizeof(string
)-2;
2044 ret
= RegSetValueExA(subkey
, "stringtest", 0, REG_SZ
, (BYTE
*)string
, insize
);
2045 ok(ret
== ERROR_SUCCESS
, "RegSetValueExA failed: %d\n", ret
);
2047 ret
= RegQueryValueExA(subkey
, "stringtest", NULL
, NULL
, NULL
, &outsize
);
2048 ok(ret
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", ret
);
2049 ok(outsize
== insize
, "wrong size %u != %u\n", outsize
, insize
);
2051 /* RegQueryValueExA may return a string with no trailing '\0' */
2053 memset(buffer
, 0xbd, sizeof(buffer
));
2054 ret
= RegQueryValueExA(subkey
, "stringtest", NULL
, NULL
, buffer
, &outsize
);
2055 ok(ret
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", ret
);
2056 ok(outsize
== insize
, "wrong size: %u != %u\n", outsize
, insize
);
2057 ok(memcmp(buffer
, string
, outsize
) == 0, "bad string: %s/%u != %s\n",
2058 debugstr_an((char*)buffer
, outsize
), outsize
, string
);
2059 ok(buffer
[insize
] == 0xbd, "buffer overflow at %u %02x\n", insize
, buffer
[insize
]);
2061 /* RegQueryValueExA adds a trailing '\0' if there is room */
2063 memset(buffer
, 0xbd, sizeof(buffer
));
2064 ret
= RegQueryValueExA(subkey
, "stringtest", NULL
, NULL
, buffer
, &outsize
);
2065 ok(ret
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", ret
);
2066 ok(outsize
== insize
, "wrong size: %u != %u\n", outsize
, insize
);
2067 ok(memcmp(buffer
, string
, outsize
) == 0, "bad string: %s/%u != %s\n",
2068 debugstr_an((char*)buffer
, outsize
), outsize
, string
);
2069 ok(buffer
[insize
] == 0, "buffer overflow at %u %02x\n", insize
, buffer
[insize
]);
2071 /* RegEnumValueA may return a string with no trailing '\0' */
2073 memset(buffer
, 0xbd, sizeof(buffer
));
2075 ret
= RegEnumValueA(subkey
, 0, name
, &nsize
, NULL
, NULL
, buffer
, &outsize
);
2076 ok(ret
== ERROR_SUCCESS
, "RegEnumValueA failed: %d\n", ret
);
2077 ok(strcmp(name
, "stringtest") == 0, "wrong name: %s\n", name
);
2078 ok(outsize
== insize
, "wrong size: %u != %u\n", outsize
, insize
);
2079 ok(memcmp(buffer
, string
, outsize
) == 0, "bad string: %s/%u != %s\n",
2080 debugstr_an((char*)buffer
, outsize
), outsize
, string
);
2081 ok(buffer
[insize
] == 0xbd, "buffer overflow at %u %02x\n", insize
, buffer
[insize
]);
2083 /* RegEnumValueA adds a trailing '\0' if there is room */
2085 memset(buffer
, 0xbd, sizeof(buffer
));
2087 ret
= RegEnumValueA(subkey
, 0, name
, &nsize
, NULL
, NULL
, buffer
, &outsize
);
2088 ok(ret
== ERROR_SUCCESS
, "RegEnumValueA failed: %d\n", ret
);
2089 ok(strcmp(name
, "stringtest") == 0, "wrong name: %s\n", name
);
2090 ok(outsize
== insize
, "wrong size: %u != %u\n", outsize
, insize
);
2091 ok(memcmp(buffer
, string
, outsize
) == 0, "bad string: %s/%u != %s\n",
2092 debugstr_an((char*)buffer
, outsize
), outsize
, string
);
2093 ok(buffer
[insize
] == 0, "buffer overflow at %u %02x\n", insize
, buffer
[insize
]);
2095 RegDeleteKeyA(subkey
, "");
2096 RegCloseKey(subkey
);
2099 static void test_reg_copy_tree(void)
2101 HKEY src
, dst
, subkey
;
2102 CHAR buffer
[MAX_PATH
];
2108 win_skip("Skipping RegCopyTreeA tests, function not present\n");
2112 ret
= RegCreateKeyA(hkey_main
, "src", &src
);
2113 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2114 ret
= RegCreateKeyA(hkey_main
, "dst", &dst
);
2115 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2117 /* Copy nonexistent subkey */
2118 ret
= pRegCopyTreeA(src
, "nonexistent_subkey", dst
);
2119 ok(ret
== ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", ret
);
2121 /* Create test keys and values */
2122 ret
= RegSetValueA(src
, NULL
, REG_SZ
, "data", 4);
2123 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2124 ret
= RegSetValueExA(src
, "value", 0, REG_SZ
, (const BYTE
*)"data2", 5);
2125 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2127 ret
= RegCreateKeyA(src
, "subkey2", &subkey
);
2128 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2129 ret
= RegSetValueA(subkey
, NULL
, REG_SZ
, "data3", 5);
2130 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2131 ret
= RegSetValueExA(subkey
, "value", 0, REG_SZ
, (const BYTE
*)"data4", 5);
2132 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2133 ret
= RegCloseKey(subkey
);
2134 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2136 ret
= RegCreateKeyA(src
, "subkey3", &subkey
);
2137 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2138 ret
= RegCloseKey(subkey
);
2139 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2142 ret
= pRegCopyTreeA(src
, "subkey2", dst
);
2143 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2146 ret
= RegQueryValueA(dst
, NULL
, buffer
, &size
);
2147 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2148 ok(!strcmp(buffer
, "data3"), "Expected 'data3', got '%s'\n", buffer
);
2151 ret
= RegQueryValueExA(dst
, "value", NULL
, &type
, (BYTE
*)buffer
, &dwsize
);
2152 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2153 ok(type
== REG_SZ
, "Expected REG_SZ, got %u\n", type
);
2154 ok(!strcmp(buffer
, "data4"), "Expected 'data4', got '%s'\n", buffer
);
2156 /* Copy full tree */
2157 ret
= pRegCopyTreeA(src
, NULL
, dst
);
2158 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2161 ret
= RegQueryValueA(dst
, NULL
, buffer
, &size
);
2162 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2163 ok(!strcmp(buffer
, "data"), "Expected 'data', got '%s'\n", buffer
);
2166 ret
= RegQueryValueExA(dst
, "value", NULL
, &type
, (BYTE
*)buffer
, &dwsize
);
2167 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2168 ok(type
== REG_SZ
, "Expected REG_SZ, got %u\n", type
);
2169 ok(!strcmp(buffer
, "data2"), "Expected 'data2', got '%s'\n", buffer
);
2171 ret
= RegOpenKeyA(dst
, "subkey2", &subkey
);
2172 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2174 ret
= RegQueryValueA(subkey
, NULL
, buffer
, &size
);
2175 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2176 ok(!strcmp(buffer
, "data3"), "Expected 'data3', got '%s'\n", buffer
);
2178 ret
= RegQueryValueExA(subkey
, "value", NULL
, &type
, (BYTE
*)buffer
, &dwsize
);
2179 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2180 ok(type
== REG_SZ
, "Expected REG_SZ, got %u\n", type
);
2181 ok(!strcmp(buffer
, "data4"), "Expected 'data4', got '%s'\n", buffer
);
2182 ret
= RegCloseKey(subkey
);
2183 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2185 ret
= RegOpenKeyA(dst
, "subkey3", &subkey
);
2186 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2187 ret
= RegCloseKey(subkey
);
2188 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2194 static void test_reg_delete_tree(void)
2196 CHAR buffer
[MAX_PATH
];
2197 HKEY subkey
, subkey2
;
2201 if(!pRegDeleteTreeA
) {
2202 win_skip("Skipping RegDeleteTreeA tests, function not present\n");
2206 ret
= RegCreateKeyA(hkey_main
, "subkey", &subkey
);
2207 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2208 ret
= RegCreateKeyA(subkey
, "subkey2", &subkey2
);
2209 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2210 ret
= RegSetValueA(subkey
, NULL
, REG_SZ
, "data", 4);
2211 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2212 ret
= RegSetValueA(subkey2
, NULL
, REG_SZ
, "data2", 5);
2213 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2214 ret
= RegCloseKey(subkey2
);
2215 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2217 ret
= pRegDeleteTreeA(subkey
, "subkey2");
2218 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2219 ok(RegOpenKeyA(subkey
, "subkey2", &subkey2
),
2220 "subkey2 was not deleted\n");
2222 ok(!RegQueryValueA(subkey
, NULL
, buffer
, &size
),
2223 "Default value of subkey no longer present\n");
2225 ret
= RegCreateKeyA(subkey
, "subkey2", &subkey2
);
2226 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2227 ret
= RegCloseKey(subkey2
);
2228 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2229 ret
= pRegDeleteTreeA(hkey_main
, "subkey\\subkey2");
2230 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2231 ok(RegOpenKeyA(subkey
, "subkey2", &subkey2
),
2232 "subkey2 was not deleted\n");
2233 ok(!RegQueryValueA(subkey
, NULL
, buffer
, &size
),
2234 "Default value of subkey no longer present\n");
2236 ret
= RegCreateKeyA(subkey
, "subkey2", &subkey2
);
2237 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2238 ret
= RegCloseKey(subkey2
);
2239 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2240 ret
= RegCreateKeyA(subkey
, "subkey3", &subkey2
);
2241 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2242 ret
= RegCloseKey(subkey2
);
2243 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2244 ret
= RegSetValueA(subkey
, NULL
, REG_SZ
, "data", 4);
2245 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2246 ret
= RegSetValueExA(subkey
, "value", 0, REG_SZ
, (const BYTE
*)"data2", 5);
2247 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2248 ret
= pRegDeleteTreeA(subkey
, NULL
);
2249 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2250 ok(!RegOpenKeyA(hkey_main
, "subkey", &subkey
),
2251 "subkey was deleted\n");
2252 ok(RegOpenKeyA(subkey
, "subkey2", &subkey2
),
2253 "subkey2 was not deleted\n");
2254 ok(RegOpenKeyA(subkey
, "subkey3", &subkey2
),
2255 "subkey3 was not deleted\n");
2257 ret
= RegQueryValueA(subkey
, NULL
, buffer
, &size
);
2258 ok(ret
== ERROR_SUCCESS
,
2259 "Default value of subkey is not present\n");
2260 ok(!buffer
[0], "Expected length 0 got length %u(%s)\n", lstrlenA(buffer
), buffer
);
2262 ok(RegQueryValueExA(subkey
, "value", NULL
, &type
, (BYTE
*)buffer
, &dwsize
),
2263 "Value is still present\n");
2264 ret
= RegCloseKey(subkey
);
2265 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2267 ret
= RegOpenKeyA(hkey_main
, "subkey", &subkey
);
2268 ok(ret
== ERROR_SUCCESS
, "subkey was deleted\n");
2269 ret
= pRegDeleteTreeA(subkey
, "");
2270 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2271 ret
= RegCloseKey(subkey
);
2272 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2274 ret
= RegOpenKeyA(hkey_main
, "subkey", &subkey
);
2275 ok(ret
== ERROR_SUCCESS
, "subkey was deleted\n");
2276 ret
= RegCloseKey(subkey
);
2277 ok(ret
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", ret
);
2279 ret
= pRegDeleteTreeA(hkey_main
, "not-here");
2280 ok(ret
== ERROR_FILE_NOT_FOUND
,
2281 "Expected ERROR_FILE_NOT_FOUND, got %d\n", ret
);
2284 static void test_rw_order(void)
2288 static const char keyname
[] = "test_rw_order";
2290 DWORD values
, value_len
, value_name_max_len
;
2293 RegDeleteKeyA(HKEY_CURRENT_USER
, keyname
);
2294 ret
= RegCreateKeyA(HKEY_CURRENT_USER
, keyname
, &hKey
);
2295 if(ret
!= ERROR_SUCCESS
) {
2296 skip("Couldn't create key. Skipping.\n");
2300 ok(!RegSetValueExA(hKey
, "A", 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
)),
2301 "RegSetValueExA for value \"A\" failed\n");
2302 ok(!RegSetValueExA(hKey
, "C", 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
)),
2303 "RegSetValueExA for value \"C\" failed\n");
2304 ok(!RegSetValueExA(hKey
, "D", 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
)),
2305 "RegSetValueExA for value \"D\" failed\n");
2306 ok(!RegSetValueExA(hKey
, "B", 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
)),
2307 "RegSetValueExA for value \"B\" failed\n");
2309 ok(!RegQueryInfoKeyA(hKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &values
,
2310 &value_name_max_len
, NULL
, NULL
, NULL
), "RegQueryInfoKeyA failed\n");
2311 ok(values
== 4, "Expected 4 values, got %u\n", values
);
2313 /* Value enumeration preserves RegSetValueEx call order */
2315 ok(!RegEnumValueA(hKey
, 0, value_buf
, &value_len
, NULL
, NULL
, NULL
, NULL
), "RegEnumValueA failed\n");
2316 ok(strcmp(value_buf
, "A") == 0, "Expected name \"A\", got %s\n", value_buf
);
2318 ok(!RegEnumValueA(hKey
, 1, value_buf
, &value_len
, NULL
, NULL
, NULL
, NULL
), "RegEnumValueA failed\n");
2319 todo_wine
ok(strcmp(value_buf
, "C") == 0, "Expected name \"C\", got %s\n", value_buf
);
2321 ok(!RegEnumValueA(hKey
, 2, value_buf
, &value_len
, NULL
, NULL
, NULL
, NULL
), "RegEnumValueA failed\n");
2322 todo_wine
ok(strcmp(value_buf
, "D") == 0, "Expected name \"D\", got %s\n", value_buf
);
2324 ok(!RegEnumValueA(hKey
, 3, value_buf
, &value_len
, NULL
, NULL
, NULL
, NULL
), "RegEnumValueA failed\n");
2325 todo_wine
ok(strcmp(value_buf
, "B") == 0, "Expected name \"B\", got %s\n", value_buf
);
2327 ok(!RegDeleteKeyA(HKEY_CURRENT_USER
, keyname
), "Failed to delete key\n");
2330 static void test_symlinks(void)
2332 static const WCHAR targetW
[] = L
"\\Software\\Wine\\Test\\target";
2334 UNICODE_STRING target_str
;
2338 DWORD target_len
, type
, len
, dw
, err
;
2340 if (!pRtlFormatCurrentUserKeyPath
|| !pNtDeleteKey
)
2342 win_skip( "Can't perform symlink tests\n" );
2346 pRtlFormatCurrentUserKeyPath( &target_str
);
2348 target_len
= target_str
.Length
+ sizeof(targetW
);
2349 target
= HeapAlloc( GetProcessHeap(), 0, target_len
);
2350 memcpy( target
, target_str
.Buffer
, target_str
.Length
);
2351 memcpy( target
+ target_str
.Length
/sizeof(WCHAR
), targetW
, sizeof(targetW
) );
2353 err
= RegCreateKeyExA( hkey_main
, "link", 0, NULL
, REG_OPTION_CREATE_LINK
,
2354 KEY_ALL_ACCESS
, NULL
, &link
, NULL
);
2355 ok( err
== ERROR_SUCCESS
, "RegCreateKeyEx failed: %u\n", err
);
2357 /* REG_SZ is not allowed */
2358 err
= RegSetValueExA( link
, "SymbolicLinkValue", 0, REG_SZ
, (BYTE
*)"foobar", sizeof("foobar") );
2359 ok( err
== ERROR_ACCESS_DENIED
, "RegSetValueEx wrong error %u\n", err
);
2360 err
= RegSetValueExA( link
, "SymbolicLinkValue", 0, REG_LINK
,
2361 (BYTE
*)target
, target_len
- sizeof(WCHAR
) );
2362 ok( err
== ERROR_SUCCESS
, "RegSetValueEx failed error %u\n", err
);
2363 /* other values are not allowed */
2364 err
= RegSetValueExA( link
, "link", 0, REG_LINK
, (BYTE
*)target
, target_len
- sizeof(WCHAR
) );
2365 ok( err
== ERROR_ACCESS_DENIED
, "RegSetValueEx wrong error %u\n", err
);
2367 /* try opening the target through the link */
2369 err
= RegOpenKeyA( hkey_main
, "link", &key
);
2370 ok( err
== ERROR_FILE_NOT_FOUND
, "RegOpenKey wrong error %u\n", err
);
2372 err
= RegCreateKeyExA( hkey_main
, "target", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2373 ok( err
== ERROR_SUCCESS
, "RegCreateKeyEx failed error %u\n", err
);
2376 err
= RegSetValueExA( key
, "value", 0, REG_DWORD
, (BYTE
*)&dw
, sizeof(dw
) );
2377 ok( err
== ERROR_SUCCESS
, "RegSetValueEx failed error %u\n", err
);
2380 err
= RegOpenKeyA( hkey_main
, "link", &key
);
2381 ok( err
== ERROR_SUCCESS
, "RegOpenKey failed error %u\n", err
);
2383 len
= sizeof(buffer
);
2384 err
= RegQueryValueExA( key
, "value", NULL
, &type
, buffer
, &len
);
2385 ok( err
== ERROR_SUCCESS
, "RegOpenKey failed error %u\n", err
);
2386 ok( len
== sizeof(DWORD
), "wrong len %u\n", len
);
2388 len
= sizeof(buffer
);
2389 err
= RegQueryValueExA( key
, "SymbolicLinkValue", NULL
, &type
, buffer
, &len
);
2390 ok( err
== ERROR_FILE_NOT_FOUND
, "RegQueryValueEx wrong error %u\n", err
);
2392 /* REG_LINK can be created in non-link keys */
2393 err
= RegSetValueExA( key
, "SymbolicLinkValue", 0, REG_LINK
,
2394 (BYTE
*)target
, target_len
- sizeof(WCHAR
) );
2395 ok( err
== ERROR_SUCCESS
, "RegSetValueEx failed error %u\n", err
);
2396 len
= sizeof(buffer
);
2397 err
= RegQueryValueExA( key
, "SymbolicLinkValue", NULL
, &type
, buffer
, &len
);
2398 ok( err
== ERROR_SUCCESS
, "RegQueryValueEx failed error %u\n", err
);
2399 ok( len
== target_len
- sizeof(WCHAR
), "wrong len %u\n", len
);
2400 err
= RegDeleteValueA( key
, "SymbolicLinkValue" );
2401 ok( err
== ERROR_SUCCESS
, "RegDeleteValue failed error %u\n", err
);
2405 err
= RegCreateKeyExA( hkey_main
, "link", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2406 ok( err
== ERROR_SUCCESS
, "RegCreateKeyEx failed error %u\n", err
);
2408 len
= sizeof(buffer
);
2409 err
= RegQueryValueExA( key
, "value", NULL
, &type
, buffer
, &len
);
2410 ok( err
== ERROR_SUCCESS
, "RegQueryValueEx failed error %u\n", err
);
2411 ok( len
== sizeof(DWORD
), "wrong len %u\n", len
);
2413 err
= RegQueryValueExA( key
, "SymbolicLinkValue", NULL
, &type
, buffer
, &len
);
2414 ok( err
== ERROR_FILE_NOT_FOUND
, "RegQueryValueEx wrong error %u\n", err
);
2417 /* now open the symlink itself */
2419 err
= RegOpenKeyExA( hkey_main
, "link", REG_OPTION_OPEN_LINK
, KEY_ALL_ACCESS
, &key
);
2420 ok( err
== ERROR_SUCCESS
, "RegOpenKeyEx failed error %u\n", err
);
2421 len
= sizeof(buffer
);
2422 err
= RegQueryValueExA( key
, "SymbolicLinkValue", NULL
, &type
, buffer
, &len
);
2423 ok( err
== ERROR_SUCCESS
, "RegQueryValueEx failed error %u\n", err
);
2424 ok( len
== target_len
- sizeof(WCHAR
), "wrong len %u\n", len
);
2427 err
= RegCreateKeyExA( hkey_main
, "link", 0, NULL
, REG_OPTION_OPEN_LINK
,
2428 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2429 ok( err
== ERROR_SUCCESS
, "RegCreateKeyEx failed error %u\n", err
);
2430 len
= sizeof(buffer
);
2431 err
= RegQueryValueExA( key
, "SymbolicLinkValue", NULL
, &type
, buffer
, &len
);
2432 ok( err
== ERROR_SUCCESS
, "RegQueryValueEx failed error %u\n", err
);
2433 ok( len
== target_len
- sizeof(WCHAR
), "wrong len %u\n", len
);
2436 err
= RegCreateKeyExA( hkey_main
, "link", 0, NULL
, REG_OPTION_CREATE_LINK
,
2437 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2438 ok( err
== ERROR_ALREADY_EXISTS
, "RegCreateKeyEx wrong error %u\n", err
);
2440 err
= RegCreateKeyExA( hkey_main
, "link", 0, NULL
, REG_OPTION_CREATE_LINK
| REG_OPTION_OPEN_LINK
,
2441 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2442 ok( err
== ERROR_ALREADY_EXISTS
, "RegCreateKeyEx wrong error %u\n", err
);
2444 err
= RegDeleteKeyA( hkey_main
, "target" );
2445 ok( err
== ERROR_SUCCESS
, "RegDeleteKey failed error %u\n", err
);
2447 err
= RegDeleteKeyA( hkey_main
, "link" );
2448 ok( err
== ERROR_FILE_NOT_FOUND
, "RegDeleteKey wrong error %u\n", err
);
2450 status
= pNtDeleteKey( link
);
2451 ok( !status
, "NtDeleteKey failed: 0x%08x\n", status
);
2452 RegCloseKey( link
);
2454 HeapFree( GetProcessHeap(), 0, target
);
2455 pRtlFreeUnicodeString( &target_str
);
2458 static DWORD
get_key_value( HKEY root
, const char *name
, DWORD flags
)
2461 DWORD err
, type
, dw
, len
= sizeof(dw
);
2463 err
= RegCreateKeyExA( root
, name
, 0, NULL
, 0, flags
| KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2464 if (err
== ERROR_FILE_NOT_FOUND
) return 0;
2465 ok( err
== ERROR_SUCCESS
, "%08x: RegCreateKeyEx failed: %u\n", flags
, err
);
2467 err
= RegQueryValueExA( key
, "value", NULL
, &type
, (BYTE
*)&dw
, &len
);
2468 if (err
== ERROR_FILE_NOT_FOUND
)
2471 ok( err
== ERROR_SUCCESS
, "%08x: RegQueryValueEx failed: %u\n", flags
, err
);
2476 static void _check_key_value( int line
, HANDLE root
, const char *name
, DWORD flags
, DWORD expect
)
2478 DWORD dw
= get_key_value( root
, name
, flags
);
2479 ok_(__FILE__
,line
)( dw
== expect
, "%08x: wrong value %u/%u\n", flags
, dw
, expect
);
2481 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
2483 static void test_redirection(void)
2485 DWORD err
, type
, dw
, len
;
2486 HKEY key
, root32
, root64
, key32
, key64
, native
, op_key
;
2487 BOOL is_vista
= FALSE
;
2488 REGSAM opposite
= (sizeof(void*) == 8 ? KEY_WOW64_32KEY
: KEY_WOW64_64KEY
);
2493 if (!pIsWow64Process
|| !pIsWow64Process( GetCurrentProcess(), &is_wow64
) || !is_wow64
)
2495 skip( "Not on Wow64, no redirection\n" );
2502 skip("not enough privileges to modify HKLM\n");
2506 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine", 0, NULL
, 0,
2507 KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, NULL
, &root64
, NULL
);
2508 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2510 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine", 0, NULL
, 0,
2511 KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, NULL
, &root32
, NULL
);
2512 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2514 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Winetest", 0, NULL
, 0,
2515 KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, NULL
, &key64
, NULL
);
2516 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2518 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Winetest", 0, NULL
, 0,
2519 KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, NULL
, &key32
, NULL
);
2520 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2523 err
= RegSetValueExA( key64
, "value", 0, REG_DWORD
, (BYTE
*)&dw
, sizeof(dw
) );
2524 ok( err
== ERROR_SUCCESS
, "RegSetValueExA failed: %u\n", err
);
2527 err
= RegSetValueExA( key32
, "value", 0, REG_DWORD
, (BYTE
*)&dw
, sizeof(dw
) );
2528 ok( err
== ERROR_SUCCESS
, "RegSetValueExA failed: %u\n", err
);
2532 err
= RegQueryValueExA( key32
, "value", NULL
, &type
, (BYTE
*)&dw
, &len
);
2533 ok( err
== ERROR_SUCCESS
, "RegQueryValueExA failed: %u\n", err
);
2534 ok( dw
== 32, "wrong value %u\n", dw
);
2538 err
= RegQueryValueExA( key64
, "value", NULL
, &type
, (BYTE
*)&dw
, &len
);
2539 ok( err
== ERROR_SUCCESS
, "RegQueryValueExA failed: %u\n", err
);
2540 ok( dw
== 64, "wrong value %u\n", dw
);
2542 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software", 0, NULL
, 0,
2543 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2544 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2548 /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
2549 /* the new (and simpler) Win7 mechanism doesn't */
2550 if (get_key_value( key
, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
2552 trace( "using Vista-style Wow6432Node handling\n" );
2555 check_key_value( key
, "Wine\\Winetest", 0, 32 );
2556 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
2557 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
2558 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", 0, is_vista
? 32 : 0 );
2559 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 0 );
2560 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY
, is_vista
? 32 : 0 );
2564 if (get_key_value( HKEY_LOCAL_MACHINE
, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY
) == 64)
2566 trace( "using Vista-style Wow6432Node handling\n" );
2569 check_key_value( key
, "Wine\\Winetest", 0, 64 );
2570 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", 0, 32 );
2576 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software", 0, NULL
, 0,
2577 KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2578 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2579 dw
= get_key_value( key
, "Wine\\Winetest", 0 );
2580 ok( dw
== 64 || broken(dw
== 32) /* xp64 */, "wrong value %u\n", dw
);
2581 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
, 64 );
2582 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
2583 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", 0, 32 );
2584 dw
= get_key_value( key
, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY
);
2585 ok( dw
== 32 || broken(dw
== 64) /* xp64 */, "wrong value %u\n", dw
);
2586 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
2589 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software", 0, NULL
, 0,
2590 KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2591 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2592 check_key_value( key
, "Wine\\Winetest", 0, 32 );
2593 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
2594 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
2595 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", 0, is_vista
? 32 : 0 );
2596 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 0 );
2597 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY
, is_vista
? 32 : 0 );
2602 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software", 0, NULL
, 0,
2603 KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2604 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2605 check_key_value( key
, "Wine\\Winetest", 0, 64 );
2606 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
, 64 );
2607 dw
= get_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
);
2608 todo_wine
ok( dw
== 32, "wrong value %u\n", dw
);
2609 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", 0, 32 );
2612 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software", 0, NULL
, 0,
2613 KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2614 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2615 check_key_value( key
, "Wine\\Winetest", 0, 32 );
2616 dw
= get_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
);
2617 ok( dw
== 32 || broken(dw
== 64) /* vista */, "wrong value %u\n", dw
);
2618 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
2622 check_key_value( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Winetest", 0, ptr_size
);
2623 check_key_value( HKEY_LOCAL_MACHINE
, "Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
2626 /* KEY_WOW64 flags have no effect on 64-bit */
2627 check_key_value( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Winetest", KEY_WOW64_64KEY
, 64 );
2628 check_key_value( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
2629 check_key_value( HKEY_LOCAL_MACHINE
, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
2630 check_key_value( HKEY_LOCAL_MACHINE
, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
2634 check_key_value( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Winetest", KEY_WOW64_64KEY
, 64 );
2635 check_key_value( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
2636 check_key_value( HKEY_LOCAL_MACHINE
, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
2637 check_key_value( HKEY_LOCAL_MACHINE
, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
2640 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wow6432Node", 0, NULL
, 0,
2641 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2642 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2643 check_key_value( key
, "Wine\\Winetest", 0, 32 );
2644 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
2645 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
2650 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wow6432Node", 0, NULL
, 0,
2651 KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2652 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2653 dw
= get_key_value( key
, "Wine\\Winetest", 0 );
2654 ok( dw
== (is_vista
? 64 : 32) || broken(dw
== 32) /* xp64 */, "wrong value %u\n", dw
);
2655 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
2656 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
2659 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wow6432Node", 0, NULL
, 0,
2660 KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2661 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2662 check_key_value( key
, "Wine\\Winetest", 0, 32 );
2663 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
2664 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
2668 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wow6432Node\\Wine", 0, NULL
, 0,
2669 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2670 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2671 check_key_value( key
, "Winetest", 0, 32 );
2672 check_key_value( key
, "Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
2673 check_key_value( key
, "Winetest", KEY_WOW64_32KEY
, 32 );
2678 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wow6432Node\\Wine", 0, NULL
, 0,
2679 KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2680 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2681 dw
= get_key_value( key
, "Winetest", 0 );
2682 ok( dw
== 32 || (is_vista
&& dw
== 64), "wrong value %u\n", dw
);
2683 check_key_value( key
, "Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
2684 check_key_value( key
, "Winetest", KEY_WOW64_32KEY
, 32 );
2687 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wow6432Node\\Wine", 0, NULL
, 0,
2688 KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2689 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2690 check_key_value( key
, "Winetest", 0, 32 );
2691 check_key_value( key
, "Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
2692 check_key_value( key
, "Winetest", KEY_WOW64_32KEY
, 32 );
2696 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine", 0, NULL
, 0,
2697 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2698 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2699 check_key_value( key
, "Winetest", 0, ptr_size
);
2700 check_key_value( key
, "Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : ptr_size
);
2701 dw
= get_key_value( key
, "Winetest", KEY_WOW64_32KEY
);
2702 todo_wine_if (ptr_size
!= 32)
2703 ok( dw
== 32, "wrong value %u\n", dw
);
2708 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine", 0, NULL
, 0,
2709 KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2710 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2711 dw
= get_key_value( key
, "Winetest", 0 );
2712 ok( dw
== 64 || broken(dw
== 32) /* xp64 */, "wrong value %u\n", dw
);
2713 check_key_value( key
, "Winetest", KEY_WOW64_64KEY
, 64 );
2714 dw
= get_key_value( key
, "Winetest", KEY_WOW64_32KEY
);
2715 todo_wine
ok( dw
== 32, "wrong value %u\n", dw
);
2718 err
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine", 0, NULL
, 0,
2719 KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
2720 ok( err
== ERROR_SUCCESS
, "RegCreateKeyExA failed: %u\n", err
);
2721 check_key_value( key
, "Winetest", 0, 32 );
2722 check_key_value( key
, "Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
2723 check_key_value( key
, "Winetest", KEY_WOW64_32KEY
, 32 );
2727 if (pRegDeleteKeyExA
)
2729 err
= pRegDeleteKeyExA( key32
, "", KEY_WOW64_32KEY
, 0 );
2730 ok( err
== ERROR_SUCCESS
, "RegDeleteKey failed: %u\n", err
);
2731 err
= pRegDeleteKeyExA( key64
, "", KEY_WOW64_64KEY
, 0 );
2732 ok( err
== ERROR_SUCCESS
, "RegDeleteKey failed: %u\n", err
);
2733 pRegDeleteKeyExA( key64
, "", KEY_WOW64_64KEY
, 0 );
2734 pRegDeleteKeyExA( root64
, "", KEY_WOW64_64KEY
, 0 );
2738 err
= RegDeleteKeyA( key32
, "" );
2739 ok( err
== ERROR_SUCCESS
, "RegDeleteKey failed: %u\n", err
);
2740 err
= RegDeleteKeyA( key64
, "" );
2741 ok( err
== ERROR_SUCCESS
, "RegDeleteKey failed: %u\n", err
);
2742 RegDeleteKeyA( key64
, "" );
2743 RegDeleteKeyA( root64
, "" );
2745 RegCloseKey( key32
);
2746 RegCloseKey( key64
);
2747 RegCloseKey( root32
);
2748 RegCloseKey( root64
);
2750 /* open key in native bit mode */
2751 err
= RegOpenKeyExA(HKEY_CLASSES_ROOT
, "Interface", 0, KEY_ALL_ACCESS
, &native
);
2752 ok(err
== ERROR_SUCCESS
, "got %i\n", err
);
2754 pRegDeleteKeyExA(native
, "AWineTest", 0, 0);
2756 /* write subkey in opposite bit mode */
2757 err
= RegOpenKeyExA(HKEY_CLASSES_ROOT
, "Interface", 0, KEY_ALL_ACCESS
| opposite
, &op_key
);
2758 ok(err
== ERROR_SUCCESS
, "got %i\n", err
);
2760 err
= RegCreateKeyExA(op_key
, "AWineTest", 0, NULL
, 0, KEY_ALL_ACCESS
| opposite
,
2762 ok(err
== ERROR_SUCCESS
|| err
== ERROR_ACCESS_DENIED
, "got %i\n", err
);
2763 if(err
!= ERROR_SUCCESS
){
2764 win_skip("Can't write to registry\n");
2765 RegCloseKey(op_key
);
2766 RegCloseKey(native
);
2771 /* verify subkey is not present in native mode */
2772 err
= RegOpenKeyExA(native
, "AWineTest", 0, KEY_ALL_ACCESS
, &key
);
2773 ok(err
== ERROR_FILE_NOT_FOUND
||
2774 broken(err
== ERROR_SUCCESS
), /* before Win7, HKCR is reflected instead of redirected */
2777 err
= pRegDeleteKeyExA(op_key
, "AWineTest", opposite
, 0);
2778 ok(err
== ERROR_SUCCESS
, "got %i\n", err
);
2780 RegCloseKey(op_key
);
2781 RegCloseKey(native
);
2784 static void test_classesroot(void)
2786 HKEY hkey
, hklm
, hkcr
, hkeysub1
, hklmsub1
, hkcrsub1
, hklmsub2
, hkcrsub2
;
2788 DWORD type
= REG_SZ
;
2789 static CHAR buffer
[8];
2792 /* create a key in the user's classes */
2793 if (!RegOpenKeyA( HKEY_CURRENT_USER
, "Software\\Classes\\WineTestCls", &hkey
))
2796 RegCloseKey( hkey
);
2798 res
= RegCreateKeyExA( HKEY_CURRENT_USER
, "Software\\Classes\\WineTestCls", 0, NULL
, 0,
2799 KEY_QUERY_VALUE
|KEY_SET_VALUE
, NULL
, &hkey
, NULL
);
2800 if (res
== ERROR_ACCESS_DENIED
)
2802 skip("not enough privileges to add a user class\n");
2805 ok(!IS_HKCR(hkey
), "hkcr mask set in %p\n", hkey
);
2807 /* try to open that key in hkcr */
2808 res
= RegOpenKeyExA( HKEY_CLASSES_ROOT
, "WineTestCls", 0,
2809 KEY_QUERY_VALUE
|KEY_SET_VALUE
, &hkcr
);
2810 todo_wine
ok(res
== ERROR_SUCCESS
||
2811 broken(res
== ERROR_FILE_NOT_FOUND
/* WinNT */),
2812 "test key not found in hkcr: %d\n", res
);
2815 skip("HKCR key merging not supported\n");
2817 RegCloseKey( hkey
);
2821 todo_wine
ok(IS_HKCR(hkcr
), "hkcr mask not set in %p\n", hkcr
);
2823 /* set a value in user's classes */
2824 res
= RegSetValueExA(hkey
, "val1", 0, REG_SZ
, (const BYTE
*)"user", sizeof("user"));
2825 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2827 /* try to find the value in hkcr */
2828 res
= RegQueryValueExA(hkcr
, "val1", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2829 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", res
);
2830 ok(!strcmp( buffer
, "user" ), "value set to '%s'\n", buffer
);
2832 /* modify the value in hkcr */
2833 res
= RegSetValueExA(hkcr
, "val1", 0, REG_SZ
, (const BYTE
*)"hkcr", sizeof("hkcr"));
2834 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2836 /* check if the value is also modified in user's classes */
2837 res
= RegQueryValueExA(hkey
, "val1", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2838 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2839 ok(!strcmp( buffer
, "hkcr" ), "value set to '%s'\n", buffer
);
2841 /* set a value in hkcr */
2842 res
= RegSetValueExA(hkcr
, "val0", 0, REG_SZ
, (const BYTE
*)"hkcr", sizeof("hkcr"));
2843 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2845 /* try to find the value in user's classes */
2846 res
= RegQueryValueExA(hkey
, "val0", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2847 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", res
);
2848 ok(!strcmp( buffer
, "hkcr" ), "value set to '%s'\n", buffer
);
2850 /* modify the value in user's classes */
2851 res
= RegSetValueExA(hkey
, "val0", 0, REG_SZ
, (const BYTE
*)"user", sizeof("user"));
2852 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2854 /* check if the value is also modified in hkcr */
2855 res
= RegQueryValueExA(hkcr
, "val0", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2856 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2857 ok(!strcmp( buffer
, "user" ), "value set to '%s'\n", buffer
);
2862 RegCloseKey( hkey
);
2863 RegCloseKey( hkcr
);
2865 /* create a key in the hklm classes */
2866 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Classes\\WineTestCls", &hklm
))
2869 RegCloseKey( hklm
);
2871 res
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Classes\\WineTestCls", 0, NULL
, REG_OPTION_NON_VOLATILE
,
2872 KEY_ALL_ACCESS
, NULL
, &hklm
, NULL
);
2873 if (res
== ERROR_ACCESS_DENIED
)
2875 skip("not enough privileges to add a system class\n");
2878 ok(!IS_HKCR(hklm
), "hkcr mask set in %p\n", hklm
);
2880 /* try to open that key in hkcr */
2881 res
= RegOpenKeyExA( HKEY_CLASSES_ROOT
, "WineTestCls", 0,
2882 KEY_QUERY_VALUE
|KEY_SET_VALUE
, &hkcr
);
2883 ok(res
== ERROR_SUCCESS
,
2884 "test key not found in hkcr: %d\n", res
);
2885 ok(IS_HKCR(hkcr
), "hkcr mask not set in %p\n", hkcr
);
2889 RegCloseKey( hklm
);
2893 /* set a value in hklm classes */
2894 res
= RegSetValueExA(hklm
, "val2", 0, REG_SZ
, (const BYTE
*)"hklm", sizeof("hklm"));
2895 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2897 /* try to find the value in hkcr */
2898 res
= RegQueryValueExA(hkcr
, "val2", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2899 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", res
);
2900 ok(!strcmp( buffer
, "hklm" ), "value set to '%s'\n", buffer
);
2902 /* modify the value in hkcr */
2903 res
= RegSetValueExA(hkcr
, "val2", 0, REG_SZ
, (const BYTE
*)"hkcr", sizeof("hkcr"));
2904 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2906 /* check that the value is modified in hklm classes */
2907 res
= RegQueryValueExA(hklm
, "val2", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2908 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2909 ok(!strcmp( buffer
, "hkcr" ), "value set to '%s'\n", buffer
);
2911 if (RegCreateKeyExA( HKEY_CURRENT_USER
, "Software\\Classes\\WineTestCls", 0, NULL
, 0,
2912 KEY_QUERY_VALUE
|KEY_SET_VALUE
, NULL
, &hkey
, NULL
)) return;
2913 ok(!IS_HKCR(hkey
), "hkcr mask set in %p\n", hkey
);
2915 /* try to open that key in hkcr */
2916 res
= RegOpenKeyExA( HKEY_CLASSES_ROOT
, "WineTestCls", 0,
2917 KEY_QUERY_VALUE
|KEY_SET_VALUE
, &hkcr
);
2918 ok(res
== ERROR_SUCCESS
,
2919 "test key not found in hkcr: %d\n", res
);
2920 ok(IS_HKCR(hkcr
), "hkcr mask not set in %p\n", hkcr
);
2922 /* set a value in user's classes */
2923 res
= RegSetValueExA(hkey
, "val2", 0, REG_SZ
, (const BYTE
*)"user", sizeof("user"));
2924 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2926 /* try to find the value in hkcr */
2927 res
= RegQueryValueExA(hkcr
, "val2", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2928 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", res
);
2929 ok(!strcmp( buffer
, "user" ), "value set to '%s'\n", buffer
);
2931 /* modify the value in hklm */
2932 res
= RegSetValueExA(hklm
, "val2", 0, REG_SZ
, (const BYTE
*)"hklm", sizeof("hklm"));
2933 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2935 /* check that the value is not overwritten in hkcr or user's classes */
2936 res
= RegQueryValueExA(hkcr
, "val2", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2937 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", res
);
2938 ok(!strcmp( buffer
, "user" ), "value set to '%s'\n", buffer
);
2939 res
= RegQueryValueExA(hkey
, "val2", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2940 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2941 ok(!strcmp( buffer
, "user" ), "value set to '%s'\n", buffer
);
2943 /* modify the value in hkcr */
2944 res
= RegSetValueExA(hkcr
, "val2", 0, REG_SZ
, (const BYTE
*)"hkcr", sizeof("hkcr"));
2945 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2947 /* check that the value is overwritten in hklm and user's classes */
2948 res
= RegQueryValueExA(hkcr
, "val2", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2949 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", res
);
2950 ok(!strcmp( buffer
, "hkcr" ), "value set to '%s'\n", buffer
);
2951 res
= RegQueryValueExA(hkey
, "val2", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2952 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2953 ok(!strcmp( buffer
, "hkcr" ), "value set to '%s'\n", buffer
);
2955 /* create a subkey in hklm */
2956 if (RegCreateKeyExA( hklm
, "subkey1", 0, NULL
, 0,
2957 KEY_QUERY_VALUE
|KEY_SET_VALUE
, NULL
, &hklmsub1
, NULL
)) return;
2958 ok(!IS_HKCR(hklmsub1
), "hkcr mask set in %p\n", hklmsub1
);
2959 /* try to open that subkey in hkcr */
2960 res
= RegOpenKeyExA( hkcr
, "subkey1", 0, KEY_QUERY_VALUE
|KEY_SET_VALUE
, &hkcrsub1
);
2961 ok(res
== ERROR_SUCCESS
, "test key not found in hkcr: %d\n", res
);
2962 ok(IS_HKCR(hkcrsub1
), "hkcr mask not set in %p\n", hkcrsub1
);
2964 /* set a value in hklm classes */
2965 res
= RegSetValueExA(hklmsub1
, "subval1", 0, REG_SZ
, (const BYTE
*)"hklm", sizeof("hklm"));
2966 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2968 /* try to find the value in hkcr */
2969 res
= RegQueryValueExA(hkcrsub1
, "subval1", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2970 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", res
);
2971 ok(!strcmp( buffer
, "hklm" ), "value set to '%s'\n", buffer
);
2973 /* modify the value in hkcr */
2974 res
= RegSetValueExA(hkcrsub1
, "subval1", 0, REG_SZ
, (const BYTE
*)"hkcr", sizeof("hkcr"));
2975 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2977 /* check that the value is modified in hklm classes */
2978 res
= RegQueryValueExA(hklmsub1
, "subval1", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2979 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2980 ok(!strcmp( buffer
, "hkcr" ), "value set to '%s'\n", buffer
);
2982 /* create a subkey in user's classes */
2983 if (RegCreateKeyExA( hkey
, "subkey1", 0, NULL
, 0,
2984 KEY_QUERY_VALUE
|KEY_SET_VALUE
, NULL
, &hkeysub1
, NULL
)) return;
2985 ok(!IS_HKCR(hkeysub1
), "hkcr mask set in %p\n", hkeysub1
);
2987 /* set a value in user's classes */
2988 res
= RegSetValueExA(hkeysub1
, "subval1", 0, REG_SZ
, (const BYTE
*)"user", sizeof("user"));
2989 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
2991 /* try to find the value in hkcr */
2992 res
= RegQueryValueExA(hkcrsub1
, "subval1", NULL
, &type
, (LPBYTE
)buffer
, &size
);
2993 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", res
);
2994 ok(!strcmp( buffer
, "user" ), "value set to '%s'\n", buffer
);
2996 /* modify the value in hklm */
2997 res
= RegSetValueExA(hklmsub1
, "subval1", 0, REG_SZ
, (const BYTE
*)"hklm", sizeof("hklm"));
2998 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
3000 /* check that the value is not overwritten in hkcr or user's classes */
3001 res
= RegQueryValueExA(hkcrsub1
, "subval1", NULL
, &type
, (LPBYTE
)buffer
, &size
);
3002 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", res
);
3003 ok(!strcmp( buffer
, "user" ), "value set to '%s'\n", buffer
);
3004 res
= RegQueryValueExA(hkeysub1
, "subval1", NULL
, &type
, (LPBYTE
)buffer
, &size
);
3005 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d, GLE=%x\n", res
, GetLastError());
3006 ok(!strcmp( buffer
, "user" ), "value set to '%s'\n", buffer
);
3008 /* modify the value in hkcr */
3009 res
= RegSetValueExA(hkcrsub1
, "subval1", 0, REG_SZ
, (const BYTE
*)"hkcr", sizeof("hkcr"));
3010 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
3012 /* check that the value is not overwritten in hklm, but in user's classes */
3013 res
= RegQueryValueExA(hklmsub1
, "subval1", NULL
, &type
, (LPBYTE
)buffer
, &size
);
3014 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", res
);
3015 ok(!strcmp( buffer
, "hklm" ), "value set to '%s'\n", buffer
);
3016 res
= RegQueryValueExA(hkeysub1
, "subval1", NULL
, &type
, (LPBYTE
)buffer
, &size
);
3017 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d, GLE=%x\n", res
, GetLastError());
3018 ok(!strcmp( buffer
, "hkcr" ), "value set to '%s'\n", buffer
);
3020 /* new subkey in hkcr */
3021 if (RegCreateKeyExA( hkcr
, "subkey2", 0, NULL
, 0,
3022 KEY_QUERY_VALUE
|KEY_SET_VALUE
, NULL
, &hkcrsub2
, NULL
)) return;
3023 ok(IS_HKCR(hkcrsub2
), "hkcr mask not set in %p\n", hkcrsub2
);
3024 res
= RegSetValueExA(hkcrsub2
, "subval1", 0, REG_SZ
, (const BYTE
*)"hkcr", sizeof("hkcr"));
3025 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d, GLE=%x\n", res
, GetLastError());
3027 /* try to open that new subkey in user's classes and hklm */
3028 res
= RegOpenKeyExA( hkey
, "subkey2", 0, KEY_QUERY_VALUE
|KEY_SET_VALUE
, &hklmsub2
);
3029 ok(res
!= ERROR_SUCCESS
, "test key found in user's classes: %d\n", res
);
3031 res
= RegOpenKeyExA( hklm
, "subkey2", 0, KEY_QUERY_VALUE
|KEY_SET_VALUE
, &hklmsub2
);
3032 ok(res
== ERROR_SUCCESS
, "test key not found in hklm: %d\n", res
);
3033 ok(!IS_HKCR(hklmsub2
), "hkcr mask set in %p\n", hklmsub2
);
3035 /* check that the value is present in hklm */
3036 res
= RegQueryValueExA(hklmsub2
, "subval1", NULL
, &type
, (LPBYTE
)buffer
, &size
);
3037 ok(res
== ERROR_SUCCESS
, "RegQueryValueExA failed: %d\n", res
);
3038 ok(!strcmp( buffer
, "hkcr" ), "value set to '%s'\n", buffer
);
3041 RegCloseKey( hkeysub1
);
3042 RegCloseKey( hklmsub1
);
3044 /* delete subkey1 from hkcr (should point at user's classes) */
3045 res
= RegDeleteKeyA(hkcr
, "subkey1");
3046 ok(res
== ERROR_SUCCESS
, "RegDeleteKey failed: %d\n", res
);
3048 /* confirm key was removed in hkey but not hklm */
3049 res
= RegOpenKeyExA(hkey
, "subkey1", 0, KEY_READ
, &hkeysub1
);
3050 ok(res
== ERROR_FILE_NOT_FOUND
, "test key found in user's classes: %d\n", res
);
3051 res
= RegOpenKeyExA(hklm
, "subkey1", 0, KEY_READ
, &hklmsub1
);
3052 ok(res
== ERROR_SUCCESS
, "test key not found in hklm: %d\n", res
);
3053 ok(!IS_HKCR(hklmsub1
), "hkcr mask set in %p\n", hklmsub1
);
3055 /* delete subkey1 from hkcr again (which should now point at hklm) */
3056 res
= RegDeleteKeyA(hkcr
, "subkey1");
3057 ok(res
== ERROR_SUCCESS
, "RegDeleteKey failed: %d\n", res
);
3059 /* confirm hkey was removed in hklm */
3060 RegCloseKey( hklmsub1
);
3061 res
= RegOpenKeyExA(hklm
, "subkey1", 0, KEY_READ
, &hklmsub1
);
3062 ok(res
== ERROR_FILE_NOT_FOUND
, "test key found in hklm: %d\n", res
);
3068 delete_key( hkeysub1
);
3069 delete_key( hklmsub1
);
3070 delete_key( hkcrsub1
);
3071 delete_key( hklmsub2
);
3072 delete_key( hkcrsub2
);
3073 RegCloseKey( hkey
);
3074 RegCloseKey( hklm
);
3075 RegCloseKey( hkcr
);
3076 RegCloseKey( hkeysub1
);
3077 RegCloseKey( hklmsub1
);
3078 RegCloseKey( hkcrsub1
);
3079 RegCloseKey( hklmsub2
);
3080 RegCloseKey( hkcrsub2
);
3083 static void test_classesroot_enum(void)
3085 HKEY hkcu
=0, hklm
=0, hkcr
=0, hkcusub
[2]={0}, hklmsub
[2]={0};
3087 static CHAR buffer
[2];
3090 /* prepare initial testing env in HKCU */
3091 if (!RegOpenKeyA( HKEY_CURRENT_USER
, "Software\\Classes\\WineTestCls", &hkcu
))
3094 RegCloseKey( hkcu
);
3096 res
= RegCreateKeyExA( HKEY_CURRENT_USER
, "Software\\Classes\\WineTestCls", 0, NULL
, 0,
3097 KEY_SET_VALUE
|KEY_ENUMERATE_SUB_KEYS
, NULL
, &hkcu
, NULL
);
3099 if (res
!= ERROR_SUCCESS
)
3101 skip("failed to add a user class\n");
3105 res
= RegOpenKeyA( HKEY_CLASSES_ROOT
, "WineTestCls", &hkcr
);
3106 todo_wine
ok(res
== ERROR_SUCCESS
||
3107 broken(res
== ERROR_FILE_NOT_FOUND
/* WinNT */),
3108 "test key not found in hkcr: %d\n", res
);
3111 skip("HKCR key merging not supported\n");
3113 RegCloseKey( hkcu
);
3117 res
= RegSetValueExA( hkcu
, "X", 0, REG_SZ
, (const BYTE
*) "AA", 3 );
3118 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d\n", res
);
3119 res
= RegSetValueExA( hkcu
, "Y", 0, REG_SZ
, (const BYTE
*) "B", 2 );
3120 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d\n", res
);
3121 res
= RegCreateKeyA( hkcu
, "A", &hkcusub
[0] );
3122 ok(res
== ERROR_SUCCESS
, "RegCreateKeyA failed: %d\n", res
);
3123 res
= RegCreateKeyA( hkcu
, "B", &hkcusub
[1] );
3124 ok(res
== ERROR_SUCCESS
, "RegCreateKeyA failed: %d\n", res
);
3126 /* test on values in HKCU */
3127 size
= sizeof(buffer
);
3128 res
= RegEnumValueA( hkcr
, 0, buffer
, &size
, NULL
, NULL
, NULL
, NULL
);
3129 ok(res
== ERROR_SUCCESS
, "RegEnumValueA failed: %d\n", res
);
3130 ok(!strcmp( buffer
, "X" ), "expected 'X', got '%s'\n", buffer
);
3131 size
= sizeof(buffer
);
3132 res
= RegEnumValueA( hkcr
, 1, buffer
, &size
, NULL
, NULL
, NULL
, NULL
);
3133 ok(res
== ERROR_SUCCESS
, "RegEnumValueA failed: %d\n", res
);
3134 ok(!strcmp( buffer
, "Y" ), "expected 'Y', got '%s'\n", buffer
);
3135 size
= sizeof(buffer
);
3136 res
= RegEnumValueA( hkcr
, 2, buffer
, &size
, NULL
, NULL
, NULL
, NULL
);
3137 ok(res
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %d\n", res
);
3139 res
= RegEnumKeyA( hkcr
, 0, buffer
, size
);
3140 ok(res
== ERROR_SUCCESS
, "RegEnumKey failed: %d\n", res
);
3141 ok(!strcmp( buffer
, "A" ), "expected 'A', got '%s'\n", buffer
);
3142 res
= RegEnumKeyA( hkcr
, 1, buffer
, size
);
3143 ok(res
== ERROR_SUCCESS
, "RegEnumKey failed: %d\n", res
);
3144 ok(!strcmp( buffer
, "B" ), "expected 'B', got '%s'\n", buffer
);
3145 res
= RegEnumKeyA( hkcr
, 2, buffer
, size
);
3146 ok(res
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %d\n", res
);
3148 /* prepare test env in HKLM */
3149 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Classes\\WineTestCls", &hklm
))
3152 RegCloseKey( hklm
);
3155 res
= RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Classes\\WineTestCls", 0, NULL
, 0,
3156 KEY_SET_VALUE
|KEY_ENUMERATE_SUB_KEYS
, NULL
, &hklm
, NULL
);
3158 if (res
== ERROR_ACCESS_DENIED
)
3160 RegCloseKey( hkcusub
[0] );
3161 RegCloseKey( hkcusub
[1] );
3163 RegCloseKey( hkcu
);
3164 RegCloseKey( hkcr
);
3165 skip("not enough privileges to add a system class\n");
3169 res
= RegSetValueExA( hklm
, "X", 0, REG_SZ
, (const BYTE
*) "AB", 3 );
3170 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d\n", res
);
3171 res
= RegSetValueExA( hklm
, "Z", 0, REG_SZ
, (const BYTE
*) "C", 2 );
3172 ok(res
== ERROR_SUCCESS
, "RegSetValueExA failed: %d\n", res
);
3173 res
= RegCreateKeyA( hklm
, "A", &hklmsub
[0] );
3174 ok(res
== ERROR_SUCCESS
, "RegCreateKeyA failed: %d\n", res
);
3175 res
= RegCreateKeyA( hklm
, "C", &hklmsub
[1] );
3176 ok(res
== ERROR_SUCCESS
, "RegCreateKeyA failed: %d\n", res
);
3178 /* test on values/keys in both HKCU and HKLM */
3179 size
= sizeof(buffer
);
3180 res
= RegEnumValueA( hkcr
, 0, buffer
, &size
, NULL
, NULL
, NULL
, NULL
);
3181 ok(res
== ERROR_SUCCESS
, "RegEnumValueA failed: %d\n", res
);
3182 ok(!strcmp( buffer
, "X" ), "expected 'X', got '%s'\n", buffer
);
3183 size
= sizeof(buffer
);
3184 res
= RegEnumValueA( hkcr
, 1, buffer
, &size
, NULL
, NULL
, NULL
, NULL
);
3185 ok(res
== ERROR_SUCCESS
, "RegEnumValueA failed: %d\n", res
);
3186 ok(!strcmp( buffer
, "Y" ), "expected 'Y', got '%s'\n", buffer
);
3187 size
= sizeof(buffer
);
3188 res
= RegEnumValueA( hkcr
, 2, buffer
, &size
, NULL
, NULL
, NULL
, NULL
);
3189 ok(res
== ERROR_SUCCESS
, "RegEnumValueA failed: %d\n", res
);
3190 ok(!strcmp( buffer
, "Z" ), "expected 'Z', got '%s'\n", buffer
);
3191 size
= sizeof(buffer
);
3192 res
= RegEnumValueA( hkcr
, 3, buffer
, &size
, NULL
, NULL
, NULL
, NULL
);
3193 ok(res
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %d\n", res
);
3195 res
= RegEnumKeyA( hkcr
, 0, buffer
, size
);
3196 ok(res
== ERROR_SUCCESS
, "RegEnumKey failed: %d\n", res
);
3197 ok(!strcmp( buffer
, "A" ), "expected 'A', got '%s'\n", buffer
);
3198 res
= RegEnumKeyA( hkcr
, 1, buffer
, size
);
3199 ok(res
== ERROR_SUCCESS
, "RegEnumKey failed: %d\n", res
);
3200 ok(!strcmp( buffer
, "B" ), "expected 'B', got '%s'\n", buffer
);
3201 res
= RegEnumKeyA( hkcr
, 2, buffer
, size
);
3202 ok(res
== ERROR_SUCCESS
, "RegEnumKey failed: %d\n", res
);
3203 ok(!strcmp( buffer
, "C" ), "expected 'C', got '%s'\n", buffer
);
3204 res
= RegEnumKeyA( hkcr
, 3, buffer
, size
);
3205 ok(res
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %d\n", res
);
3207 /* delete values/keys from HKCU to test only on HKLM */
3208 RegCloseKey( hkcusub
[0] );
3209 RegCloseKey( hkcusub
[1] );
3211 RegCloseKey( hkcu
);
3213 size
= sizeof(buffer
);
3214 res
= RegEnumValueA( hkcr
, 0, buffer
, &size
, NULL
, NULL
, NULL
, NULL
);
3215 ok(res
== ERROR_KEY_DELETED
||
3216 res
== ERROR_NO_SYSTEM_RESOURCES
, /* Windows XP */
3217 "expected ERROR_KEY_DELETED, got %d\n", res
);
3218 size
= sizeof(buffer
);
3219 res
= RegEnumKeyA( hkcr
, 0, buffer
, size
);
3220 ok(res
== ERROR_KEY_DELETED
||
3221 res
== ERROR_NO_SYSTEM_RESOURCES
, /* Windows XP */
3222 "expected ERROR_KEY_DELETED, got %d\n", res
);
3224 /* reopen HKCR handle */
3225 RegCloseKey( hkcr
);
3226 res
= RegOpenKeyA( HKEY_CLASSES_ROOT
, "WineTestCls", &hkcr
);
3227 ok(res
== ERROR_SUCCESS
, "test key not found in hkcr: %d\n", res
);
3228 if (res
) goto cleanup
;
3230 /* test on values/keys in HKLM */
3231 size
= sizeof(buffer
);
3232 res
= RegEnumValueA( hkcr
, 0, buffer
, &size
, NULL
, NULL
, NULL
, NULL
);
3233 ok(res
== ERROR_SUCCESS
, "RegEnumValueA failed: %d\n", res
);
3234 ok(!strcmp( buffer
, "X" ), "expected 'X', got '%s'\n", buffer
);
3235 size
= sizeof(buffer
);
3236 res
= RegEnumValueA( hkcr
, 1, buffer
, &size
, NULL
, NULL
, NULL
, NULL
);
3237 ok(res
== ERROR_SUCCESS
, "RegEnumValueA failed: %d\n", res
);
3238 ok(!strcmp( buffer
, "Z" ), "expected 'Z', got '%s'\n", buffer
);
3239 size
= sizeof(buffer
);
3240 res
= RegEnumValueA( hkcr
, 2, buffer
, &size
, NULL
, NULL
, NULL
, NULL
);
3241 ok(res
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %d\n", res
);
3243 res
= RegEnumKeyA( hkcr
, 0, buffer
, size
);
3244 ok(res
== ERROR_SUCCESS
, "RegEnumKey failed: %d\n", res
);
3245 ok(!strcmp( buffer
, "A" ), "expected 'A', got '%s'\n", buffer
);
3246 res
= RegEnumKeyA( hkcr
, 1, buffer
, size
);
3247 ok(res
== ERROR_SUCCESS
, "RegEnumKey failed: %d\n", res
);
3248 ok(!strcmp( buffer
, "C" ), "expected 'C', got '%s'\n", buffer
);
3249 res
= RegEnumKeyA( hkcr
, 2, buffer
, size
);
3250 ok(res
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %d\n", res
);
3253 RegCloseKey( hklmsub
[0] );
3254 RegCloseKey( hklmsub
[1] );
3256 RegCloseKey( hklm
);
3257 RegCloseKey( hkcr
);
3260 static void test_classesroot_mask(void)
3265 res
= RegOpenKeyA( HKEY_CLASSES_ROOT
, "CLSID", &hkey
);
3266 ok(res
== ERROR_SUCCESS
, "RegOpenKeyA failed: %d\n", res
);
3267 todo_wine
ok(IS_HKCR(hkey
) || broken(!IS_HKCR(hkey
)) /* WinNT */,
3268 "hkcr mask not set in %p\n", hkey
);
3269 RegCloseKey( hkey
);
3271 res
= RegOpenKeyA( HKEY_CURRENT_USER
, "Software", &hkey
);
3272 ok(res
== ERROR_SUCCESS
, "RegOpenKeyA failed: %d\n", res
);
3273 ok(!IS_HKCR(hkey
), "hkcr mask set in %p\n", hkey
);
3274 RegCloseKey( hkey
);
3276 res
= RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software", &hkey
);
3277 ok(res
== ERROR_SUCCESS
, "RegOpenKeyA failed: %d\n", res
);
3278 ok(!IS_HKCR(hkey
), "hkcr mask set in %p\n", hkey
);
3279 RegCloseKey( hkey
);
3281 res
= RegOpenKeyA( HKEY_USERS
, ".Default", &hkey
);
3282 ok(res
== ERROR_SUCCESS
, "RegOpenKeyA failed: %d\n", res
);
3283 ok(!IS_HKCR(hkey
), "hkcr mask set in %p\n", hkey
);
3284 RegCloseKey( hkey
);
3286 res
= RegOpenKeyA( HKEY_CURRENT_CONFIG
, "Software", &hkey
);
3287 ok(res
== ERROR_SUCCESS
, "RegOpenKeyA failed: %d\n", res
);
3288 ok(!IS_HKCR(hkey
), "hkcr mask set in %p\n", hkey
);
3289 RegCloseKey( hkey
);
3292 static void test_deleted_key(void)
3296 DWORD val_count
, type
;
3299 /* Open the test key, then delete it while it's open */
3300 RegOpenKeyA( HKEY_CURRENT_USER
, "Software\\Wine\\Test", &hkey
);
3302 delete_key( hkey_main
);
3304 val_count
= sizeof(value
);
3306 res
= RegEnumValueA( hkey
, 0, value
, &val_count
, NULL
, &type
, 0, 0 );
3307 ok(res
== ERROR_KEY_DELETED
, "expect ERROR_KEY_DELETED, got %i\n", res
);
3309 res
= RegEnumKeyA( hkey
, 0, value
, sizeof(value
) );
3310 ok(res
== ERROR_KEY_DELETED
, "expect ERROR_KEY_DELETED, got %i\n", res
);
3312 val_count
= sizeof(value
);
3314 res
= RegQueryValueExA( hkey
, "test", NULL
, &type
, (BYTE
*)value
, &val_count
);
3315 ok(res
== ERROR_KEY_DELETED
, "expect ERROR_KEY_DELETED, got %i\n", res
);
3317 res
= RegSetValueExA( hkey
, "test", 0, REG_SZ
, (const BYTE
*)"value", 6);
3318 ok(res
== ERROR_KEY_DELETED
, "expect ERROR_KEY_DELETED, got %i\n", res
);
3320 res
= RegOpenKeyA( hkey
, "test", &hkey2
);
3321 ok(res
== ERROR_KEY_DELETED
, "expect ERROR_KEY_DELETED, got %i\n", res
);
3323 RegCloseKey( hkey2
);
3325 res
= RegCreateKeyA( hkey
, "test", &hkey2
);
3326 ok(res
== ERROR_KEY_DELETED
, "expect ERROR_KEY_DELETED, got %i\n", res
);
3328 RegCloseKey( hkey2
);
3330 res
= RegFlushKey( hkey
);
3331 ok(res
== ERROR_KEY_DELETED
, "expect ERROR_KEY_DELETED, got %i\n", res
);
3333 RegCloseKey( hkey
);
3338 static void test_delete_value(void)
3343 res
= RegSetValueExA( hkey_main
, "test", 0, REG_SZ
, (const BYTE
*)"value", 6 );
3344 ok(res
== ERROR_SUCCESS
, "expect ERROR_SUCCESS, got %i\n", res
);
3346 res
= RegQueryValueExA( hkey_main
, "test", NULL
, NULL
, NULL
, NULL
);
3347 ok(res
== ERROR_SUCCESS
, "expect ERROR_SUCCESS, got %i\n", res
);
3349 res
= RegDeleteValueA( hkey_main
, "test" );
3350 ok(res
== ERROR_SUCCESS
, "expect ERROR_SUCCESS, got %i\n", res
);
3352 res
= RegQueryValueExA( hkey_main
, "test", NULL
, NULL
, NULL
, NULL
);
3353 ok(res
== ERROR_FILE_NOT_FOUND
, "expect ERROR_FILE_NOT_FOUND, got %i\n", res
);
3355 res
= RegDeleteValueA( hkey_main
, "test" );
3356 ok(res
== ERROR_FILE_NOT_FOUND
, "expect ERROR_FILE_NOT_FOUND, got %i\n", res
);
3358 memset(longname
, 'a', 400);
3360 res
= RegDeleteValueA( hkey_main
, longname
);
3361 ok(res
== ERROR_FILE_NOT_FOUND
|| broken(res
== ERROR_MORE_DATA
), /* nt4, win2k */
3362 "expect ERROR_FILE_NOT_FOUND, got %i\n", res
);
3364 /* Default registry value */
3365 res
= RegSetValueExA(hkey_main
, "", 0, REG_SZ
, (const BYTE
*)"value", 6);
3366 ok(res
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", res
);
3368 res
= RegQueryValueExA(hkey_main
, "", NULL
, NULL
, NULL
, NULL
);
3369 ok(res
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", res
);
3371 res
= RegDeleteValueA(hkey_main
, "" );
3372 ok(res
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", res
);
3374 res
= RegQueryValueExA(hkey_main
, "", NULL
, NULL
, NULL
, NULL
);
3375 ok(res
== ERROR_FILE_NOT_FOUND
, "expected ERROR_FILE_NOT_FOUND, got %d\n", res
);
3378 static void test_delete_key_value(void)
3383 if (!pRegDeleteKeyValueA
)
3385 win_skip("RegDeleteKeyValue is not available.\n");
3389 ret
= pRegDeleteKeyValueA(NULL
, NULL
, NULL
);
3390 ok(ret
== ERROR_INVALID_HANDLE
, "got %d\n", ret
);
3392 ret
= pRegDeleteKeyValueA(hkey_main
, NULL
, NULL
);
3393 ok(ret
== ERROR_FILE_NOT_FOUND
, "got %d\n", ret
);
3395 ret
= RegSetValueExA(hkey_main
, "test", 0, REG_SZ
, (const BYTE
*)"value", 6);
3396 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
3398 ret
= RegQueryValueExA(hkey_main
, "test", NULL
, NULL
, NULL
, NULL
);
3399 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
3401 /* NULL subkey name means delete from open key */
3402 ret
= pRegDeleteKeyValueA(hkey_main
, NULL
, "test");
3403 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
3405 ret
= RegQueryValueExA(hkey_main
, "test", NULL
, NULL
, NULL
, NULL
);
3406 ok(ret
== ERROR_FILE_NOT_FOUND
, "got %d\n", ret
);
3408 /* now with real subkey */
3409 ret
= RegCreateKeyExA(hkey_main
, "Subkey1", 0, NULL
, 0, KEY_WRITE
|KEY_READ
, NULL
, &subkey
, NULL
);
3410 ok(!ret
, "failed with error %d\n", ret
);
3412 ret
= RegSetValueExA(subkey
, "test", 0, REG_SZ
, (const BYTE
*)"value", 6);
3413 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
3415 ret
= RegQueryValueExA(subkey
, "test", NULL
, NULL
, NULL
, NULL
);
3416 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
3418 ret
= pRegDeleteKeyValueA(hkey_main
, "Subkey1", "test");
3419 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
3421 ret
= RegQueryValueExA(subkey
, "test", NULL
, NULL
, NULL
, NULL
);
3422 ok(ret
== ERROR_FILE_NOT_FOUND
, "got %d\n", ret
);
3424 /* Default registry value */
3425 ret
= RegSetValueExA(subkey
, "", 0, REG_SZ
, (const BYTE
*)"value", 6);
3426 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3428 ret
= RegQueryValueExA(subkey
, "", NULL
, NULL
, NULL
, NULL
);
3429 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3431 ret
= pRegDeleteKeyValueA(hkey_main
, "Subkey1", "" );
3432 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3434 ret
= RegQueryValueExA(subkey
, "", NULL
, NULL
, NULL
, NULL
);
3435 ok(ret
== ERROR_FILE_NOT_FOUND
, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret
);
3437 RegDeleteKeyA(subkey
, "");
3438 RegCloseKey(subkey
);
3441 static void test_RegOpenCurrentUser(void)
3446 key
= HKEY_CURRENT_USER
;
3447 ret
= RegOpenCurrentUser(KEY_READ
, &key
);
3448 ok(!ret
, "got %d, error %d\n", ret
, GetLastError());
3449 ok(key
!= HKEY_CURRENT_USER
, "got %p\n", key
);
3453 struct notify_data
{
3459 static DWORD WINAPI
notify_change_thread(void *arg
)
3461 struct notify_data
*data
= arg
;
3464 ret
= RegNotifyChangeKeyValue(data
->key
, TRUE
,
3465 REG_NOTIFY_CHANGE_NAME
|data
->flags
, data
->event
, TRUE
);
3466 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3470 static void test_RegNotifyChangeKeyValue(void)
3472 struct notify_data data
;
3473 HKEY key
, subkey
, subsubkey
;
3479 event
= CreateEventW(NULL
, FALSE
, TRUE
, NULL
);
3480 ok(event
!= NULL
, "CreateEvent failed, error %u\n", GetLastError());
3481 ret
= RegCreateKeyA(hkey_main
, "TestKey", &key
);
3482 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3484 ret
= RegNotifyChangeKeyValue(key
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, event
, TRUE
);
3485 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3486 dwret
= WaitForSingleObject(event
, 0);
3487 ok(dwret
== WAIT_TIMEOUT
, "expected WAIT_TIMEOUT, got %u\n", dwret
);
3489 ret
= RegCreateKeyA(key
, "SubKey", &subkey
);
3490 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3491 dwret
= WaitForSingleObject(event
, 0);
3492 ok(dwret
== WAIT_OBJECT_0
, "expected WAIT_OBJECT_0, got %u\n", dwret
);
3494 /* watching deeper keys */
3495 ret
= RegNotifyChangeKeyValue(key
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, event
, TRUE
);
3496 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3497 dwret
= WaitForSingleObject(event
, 0);
3498 ok(dwret
== WAIT_TIMEOUT
, "expected WAIT_TIMEOUT, got %u\n", dwret
);
3500 ret
= RegCreateKeyA(subkey
, "SubKey", &subsubkey
);
3501 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3502 dwret
= WaitForSingleObject(event
, 0);
3503 ok(dwret
== WAIT_OBJECT_0
, "expected WAIT_OBJECT_0, got %u\n", dwret
);
3505 /* watching deeper values */
3506 ret
= RegNotifyChangeKeyValue(key
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, event
, TRUE
);
3507 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3508 dwret
= WaitForSingleObject(event
, 0);
3509 ok(dwret
== WAIT_TIMEOUT
, "expected WAIT_TIMEOUT, got %u\n", dwret
);
3511 ret
= RegSetValueA(subsubkey
, NULL
, REG_SZ
, "SubSubKeyValue", 0);
3512 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3513 dwret
= WaitForSingleObject(event
, 0);
3514 ok(dwret
== WAIT_OBJECT_0
, "expected WAIT_OBJECT_0, got %u\n", dwret
);
3516 /* don't watch deeper values */
3518 ret
= RegOpenKeyA(hkey_main
, "TestKey", &key
);
3519 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3521 ret
= RegNotifyChangeKeyValue(key
, FALSE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, event
, TRUE
);
3522 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3523 dwret
= WaitForSingleObject(event
, 0);
3524 ok(dwret
== WAIT_TIMEOUT
, "expected WAIT_TIMEOUT, got %u\n", dwret
);
3526 ret
= RegSetValueA(subsubkey
, NULL
, REG_SZ
, "SubSubKeyValueNEW", 0);
3527 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3528 dwret
= WaitForSingleObject(event
, 0);
3529 ok(dwret
== WAIT_TIMEOUT
, "expected WAIT_TIMEOUT, got %u\n", dwret
);
3531 RegDeleteKeyA(subkey
, "SubKey");
3532 RegDeleteKeyA(key
, "SubKey");
3533 RegCloseKey(subsubkey
);
3534 RegCloseKey(subkey
);
3537 /* test same thread with REG_NOTIFY_THREAD_AGNOSTIC */
3538 ret
= RegOpenKeyA(hkey_main
, "TestKey", &key
);
3539 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3540 ret
= RegNotifyChangeKeyValue(key
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_THREAD_AGNOSTIC
,
3542 if (ret
== ERROR_INVALID_PARAMETER
)
3544 win_skip("REG_NOTIFY_THREAD_AGNOSTIC is not supported\n");
3550 ret
= RegCreateKeyA(key
, "SubKey", &subkey
);
3551 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3552 dwret
= WaitForSingleObject(event
, 0);
3553 ok(dwret
== WAIT_OBJECT_0
, "expected WAIT_OBJECT_0, got %u\n", dwret
);
3555 RegDeleteKeyA(key
, "SubKey");
3556 RegCloseKey(subkey
);
3559 /* test different thread without REG_NOTIFY_THREAD_AGNOSTIC */
3560 ret
= RegOpenKeyA(hkey_main
, "TestKey", &key
);
3561 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3566 thread
= CreateThread(NULL
, 0, notify_change_thread
, &data
, 0, NULL
);
3567 WaitForSingleObject(thread
, INFINITE
);
3568 CloseHandle(thread
);
3570 /* the thread exiting causes event to signal on Windows
3571 this is worked around on Windows using REG_NOTIFY_THREAD_AGNOSTIC
3572 Wine already behaves as if the flag is set */
3573 dwret
= WaitForSingleObject(event
, 0);
3575 ok(dwret
== WAIT_OBJECT_0
, "expected WAIT_OBJECT_0, got %u\n", dwret
);
3578 /* test different thread with REG_NOTIFY_THREAD_AGNOSTIC */
3579 ret
= RegOpenKeyA(hkey_main
, "TestKey", &key
);
3580 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3582 data
.flags
= REG_NOTIFY_THREAD_AGNOSTIC
;
3583 thread
= CreateThread(NULL
, 0, notify_change_thread
, &data
, 0, NULL
);
3584 WaitForSingleObject(thread
, INFINITE
);
3585 CloseHandle(thread
);
3587 dwret
= WaitForSingleObject(event
, 0);
3588 ok(dwret
== WAIT_TIMEOUT
, "expected WAIT_TIMEOUT, got %u\n", dwret
);
3590 ret
= RegCreateKeyA(key
, "SubKey", &subkey
);
3591 ok(ret
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %d\n", ret
);
3593 dwret
= WaitForSingleObject(event
, 0);
3594 ok(dwret
== WAIT_OBJECT_0
, "expected WAIT_OBJECT_0, got %u\n", dwret
);
3596 RegDeleteKeyA(key
, "SubKey");
3597 RegDeleteKeyA(key
, "");
3598 RegCloseKey(subkey
);
3603 static const char *find_counter_value(const char *text
, const char *index
)
3605 const char *p
= text
;
3609 if (!strcmp(p
, index
))
3610 return p
+ strlen(p
) + 1;
3619 static void test_counter_values(const char *text
, HKEY key
)
3621 const char *p
= text
;
3624 ok(!strcmp(p
, "1"), "got first index %s\n", debugstr_a(p
));
3626 ok(!strcmp(p
, "1847"), "got first name %s\n", debugstr_a(p
));
3631 unsigned int index
= atoi(p
);
3633 ok(index
> 0, "expected nonzero index\n");
3636 ok(*p
, "name missing for %u\n", index
);
3640 name
= find_counter_value(text
, "1846");
3641 ok(name
!= NULL
, "did not find name\n");
3642 if (key
!= HKEY_PERFORMANCE_NLSTEXT
)
3643 ok(!strcmp(name
, "End Marker"), "got name %s\n", debugstr_a(name
));
3646 static void test_help_values(const char *text
, HKEY key
)
3648 const char *p
= text
;
3653 unsigned int index
= atoi(p
);
3655 ok(index
> 0, "expected nonzero index\n");
3661 name
= find_counter_value(text
, "1847");
3662 ok(name
!= NULL
, "did not find name\n");
3663 if (key
!= HKEY_PERFORMANCE_NLSTEXT
)
3664 ok(!strcmp(name
, "End Marker"), "got name %s\n", debugstr_a(name
));
3667 static void test_performance_keys(void)
3669 static const HKEY keys
[] = {HKEY_PERFORMANCE_DATA
, HKEY_PERFORMANCE_TEXT
, HKEY_PERFORMANCE_NLSTEXT
};
3670 static const char *const names
[] = {NULL
, "", "Global", "2", "invalid counter name", "System"};
3671 DWORD size
, type
, sysname_len
, expect_size
, key_count
, value_count
;
3672 LARGE_INTEGER perftime1
, perftime2
, systime1
, systime2
, freq
;
3673 WCHAR sysname
[MAX_COMPUTERNAME_LENGTH
+ 1];
3674 unsigned int buffer_size
= 1024 * 1024;
3675 void *buffer
, *bufferW
;
3676 PERF_DATA_BLOCK
*data
;
3686 buffer
= malloc(buffer_size
);
3688 sysname_len
= ARRAY_SIZE(sysname
);
3689 GetComputerNameW(sysname
, &sysname_len
);
3691 for (i
= 0; i
< ARRAY_SIZE(keys
); ++i
)
3693 winetest_push_context("key %p", keys
[i
]);
3695 for (j
= 0; j
< ARRAY_SIZE(names
); ++j
)
3697 winetest_push_context("value %s", debugstr_a(names
[j
]));
3699 QueryPerformanceFrequency(&freq
);
3702 ret
= RegQueryValueExA(keys
[i
], names
[j
], NULL
, NULL
, NULL
, &size
);
3703 todo_wine_if (keys
[i
] != HKEY_PERFORMANCE_DATA
)
3704 ok(ret
== ERROR_MORE_DATA
, "got %u\n", ret
);
3705 ok(!size
, "got size %u\n", size
);
3708 ret
= RegQueryValueExA(keys
[i
], names
[j
], NULL
, NULL
, buffer
, &size
);
3709 todo_wine_if (keys
[i
] != HKEY_PERFORMANCE_DATA
)
3710 ok(ret
== ERROR_MORE_DATA
, "got %u\n", ret
);
3711 todo_wine_if (keys
[i
] == HKEY_PERFORMANCE_DATA
)
3712 ok(size
== 10, "got size %u\n", size
);
3715 ret
= RegQueryValueExA(keys
[i
], names
[j
], NULL
, NULL
, NULL
, &size
);
3716 todo_wine_if (keys
[i
] != HKEY_PERFORMANCE_DATA
)
3717 ok(ret
== ERROR_MORE_DATA
, "got %u\n", ret
);
3719 QueryPerformanceCounter(&perftime1
);
3720 NtQuerySystemTime(&systime1
);
3724 ret
= RegQueryValueExA(keys
[i
], names
[j
], NULL
, &type
, buffer
, &size
);
3725 todo_wine_if (keys
[i
] != HKEY_PERFORMANCE_DATA
)
3727 ok(!ret
, "got %u\n", ret
);
3728 ok(type
== REG_BINARY
, "got type %u\n", type
);
3729 ok(size
>= sizeof(PERF_DATA_BLOCK
) && size
< buffer_size
, "got size %u\n", size
);
3734 winetest_pop_context();
3738 QueryPerformanceCounter(&perftime2
);
3739 NtQuerySystemTime(&systime2
);
3742 ok(!wcsncmp(data
->Signature
, L
"PERF", 4), "got signature %s\n",
3743 debugstr_wn(data
->Signature
, 4));
3744 ok(data
->LittleEndian
== 1, "got endianness %u\n", data
->LittleEndian
);
3745 ok(data
->Version
== 1, "got version %u\n", data
->Version
);
3746 ok(data
->Revision
== 1, "got version %u\n", data
->Revision
);
3747 ok(data
->TotalByteLength
== size
, "expected size %u, got %u\n",
3748 size
, data
->TotalByteLength
);
3750 expect_size
= sizeof(PERF_DATA_BLOCK
) + data
->SystemNameLength
;
3751 expect_size
= (expect_size
+ 7) & ~7;
3753 ok(data
->HeaderLength
== expect_size
, "expected header size %u, got %u\n",
3754 expect_size
, data
->HeaderLength
);
3755 /* todo: test objects... */
3756 todo_wine
ok(data
->DefaultObject
== 238, "got default object %u\n", data
->DefaultObject
);
3758 ok(data
->PerfTime
.QuadPart
>= perftime1
.QuadPart
3759 && data
->PerfTime
.QuadPart
<= perftime2
.QuadPart
,
3760 "got times %I64u, %I64u, %I64u\n",
3761 perftime1
.QuadPart
, data
->PerfTime
.QuadPart
, perftime2
.QuadPart
);
3762 ok(data
->PerfFreq
.QuadPart
== freq
.QuadPart
, "expected frequency %I64u, got %I64u\n",
3763 freq
.QuadPart
, data
->PerfFreq
.QuadPart
);
3764 ok(data
->PerfTime100nSec
.QuadPart
>= systime1
.QuadPart
3765 && data
->PerfTime100nSec
.QuadPart
<= systime2
.QuadPart
,
3766 "got times %I64u, %I64u, %I64u\n",
3767 systime1
.QuadPart
, data
->PerfTime100nSec
.QuadPart
, systime2
.QuadPart
);
3768 SystemTimeToFileTime(&data
->SystemTime
, &file_time
.f
);
3769 /* SYSTEMTIME has a granularity of 1 ms */
3770 ok(file_time
.l
>= systime1
.QuadPart
- 10000 && file_time
.l
<= systime2
.QuadPart
,
3771 "got times %I64u, %I64u, %I64u\n", systime1
.QuadPart
, file_time
.l
, systime2
.QuadPart
);
3773 ok(data
->SystemNameLength
== (sysname_len
+ 1) * sizeof(WCHAR
),
3774 "expected name len %u, got %u\n",
3775 (sysname_len
+ 1) * sizeof(WCHAR
), data
->SystemNameLength
);
3776 ok(data
->SystemNameOffset
== sizeof(PERF_DATA_BLOCK
),
3777 "got name offset %u\n", data
->SystemNameOffset
);
3778 ok(!wcscmp(sysname
, (const WCHAR
*)(data
+ 1)), "expected name %s, got %s\n",
3779 debugstr_w(sysname
), debugstr_w((const WCHAR
*)(data
+ 1)));
3781 winetest_pop_context();
3784 /* test the "Counter" value */
3787 ret
= RegQueryValueExA(keys
[i
], "cOuNtEr", NULL
, NULL
, NULL
, &size
);
3790 ok(!ret
, "got %u\n", ret
);
3791 ok(size
> 0 && size
< 0xdeadbeef, "got size %u\n", size
);
3796 ret
= RegQueryValueExA(keys
[i
], "cOuNtEr", NULL
, &type
, buffer
, &size
);
3797 todo_wine_if (keys
[i
] != HKEY_PERFORMANCE_DATA
)
3798 ok(ret
== ERROR_MORE_DATA
, "got %u\n", ret
);
3799 todo_wine
ok(size
> 0, "got size %u\n", size
);
3803 ret
= RegQueryValueExA(keys
[i
], "cOuNtEr", NULL
, &type
, buffer
, &size
);
3804 todo_wine_if (keys
[i
] != HKEY_PERFORMANCE_DATA
)
3805 ok(!ret
, "got %u\n", ret
);
3806 todo_wine
ok(type
== REG_MULTI_SZ
, "got type %u\n", type
);
3807 if (type
== REG_MULTI_SZ
)
3808 test_counter_values(buffer
, keys
[i
]);
3812 ret
= RegQueryValueExA(keys
[i
], "cOuNtErwine", NULL
, &type
, buffer
, &size
);
3813 todo_wine_if (keys
[i
] != HKEY_PERFORMANCE_DATA
)
3814 ok(!ret
, "got %u\n", ret
);
3815 todo_wine
ok(type
== REG_MULTI_SZ
, "got type %u\n", type
);
3816 if (type
== REG_MULTI_SZ
)
3817 test_counter_values(buffer
, keys
[i
]);
3820 ret
= RegQueryValueExW(keys
[i
], L
"cOuNtEr", NULL
, NULL
, NULL
, &size
);
3823 ok(!ret
, "got %u\n", ret
);
3824 ok(size
> 0, "got size %u\n", size
);
3827 bufferW
= malloc(size
);
3830 ret
= RegQueryValueExW(keys
[i
], L
"cOuNtEr", NULL
, &type
, bufferW
, &size
);
3833 ok(!ret
, "got %u\n", ret
);
3834 ok(type
== REG_MULTI_SZ
, "got type %u\n", type
);
3836 if (type
== REG_MULTI_SZ
)
3838 WideCharToMultiByte(CP_ACP
, 0, bufferW
, size
/ sizeof(WCHAR
), buffer
, buffer_size
, NULL
, NULL
);
3839 test_counter_values(buffer
, keys
[i
]);
3842 /* test the "Help" value */
3845 ret
= RegQueryValueExA(keys
[i
], "hElP", NULL
, NULL
, NULL
, &size
);
3848 ok(!ret
, "got %u\n", ret
);
3849 ok(size
> 0 && size
< 0xdeadbeef, "got size %u\n", size
);
3854 ret
= RegQueryValueExA(keys
[i
], "hElP", NULL
, &type
, buffer
, &size
);
3855 todo_wine_if (keys
[i
] != HKEY_PERFORMANCE_DATA
)
3856 ok(ret
== ERROR_MORE_DATA
, "got %u\n", ret
);
3857 todo_wine
ok(size
> 0, "got size %u\n", size
);
3861 ret
= RegQueryValueExA(keys
[i
], "hElP", NULL
, &type
, buffer
, &size
);
3862 todo_wine_if (keys
[i
] != HKEY_PERFORMANCE_DATA
)
3863 ok(!ret
, "got %u\n", ret
);
3864 todo_wine
ok(type
== REG_MULTI_SZ
, "got type %u\n", type
);
3865 if (type
== REG_MULTI_SZ
)
3866 test_help_values(buffer
, keys
[i
]);
3870 ret
= RegQueryValueExA(keys
[i
], "hElPwine", NULL
, &type
, buffer
, &size
);
3871 todo_wine_if (keys
[i
] != HKEY_PERFORMANCE_DATA
)
3872 ok(!ret
, "got %u\n", ret
);
3873 todo_wine
ok(type
== REG_MULTI_SZ
, "got type %u\n", type
);
3874 if (type
== REG_MULTI_SZ
)
3875 test_help_values(buffer
, keys
[i
]);
3878 ret
= RegQueryValueExW(keys
[i
], L
"hElP", NULL
, NULL
, NULL
, &size
);
3881 ok(!ret
, "got %u\n", ret
);
3882 ok(size
> 0, "got size %u\n", size
);
3885 bufferW
= malloc(size
);
3888 ret
= RegQueryValueExW(keys
[i
], L
"hElP", NULL
, &type
, bufferW
, &size
);
3891 ok(!ret
, "got %u\n", ret
);
3892 ok(type
== REG_MULTI_SZ
, "got type %u\n", type
);
3894 if (type
== REG_MULTI_SZ
)
3896 WideCharToMultiByte(CP_ACP
, 0, bufferW
, size
/ sizeof(WCHAR
), buffer
, buffer_size
, NULL
, NULL
);
3897 test_help_values(buffer
, keys
[i
]);
3900 /* test other registry APIs */
3902 ret
= RegOpenKeyA(keys
[i
], NULL
, &key
);
3903 todo_wine
ok(ret
== ERROR_INVALID_HANDLE
, "got %u\n", ret
);
3905 ret
= RegOpenKeyA(keys
[i
], "Global", &key
);
3906 todo_wine_if (keys
[i
] == HKEY_PERFORMANCE_DATA
)
3907 ok(ret
== ERROR_INVALID_HANDLE
, "got %u\n", ret
);
3909 ret
= RegOpenKeyExA(keys
[i
], "Global", 0, KEY_READ
, &key
);
3910 todo_wine_if (keys
[i
] == HKEY_PERFORMANCE_DATA
)
3911 ok(ret
== ERROR_INVALID_HANDLE
, "got %u\n", ret
);
3914 ret
= RegQueryValueA(keys
[i
], "Global", NULL
, (LONG
*)&size
);
3915 todo_wine_if (keys
[i
] == HKEY_PERFORMANCE_DATA
)
3916 ok(ret
== ERROR_INVALID_HANDLE
, "got %u\n", ret
);
3918 ret
= RegSetValueA(keys
[i
], "Global", REG_SZ
, "dummy", 5);
3919 todo_wine_if (keys
[i
] == HKEY_PERFORMANCE_DATA
)
3920 ok(ret
== ERROR_INVALID_HANDLE
, "got %u\n", ret
);
3922 ret
= RegQueryInfoKeyA(keys
[i
], NULL
, NULL
, NULL
, &key_count
, NULL
,
3923 NULL
, &value_count
, NULL
, NULL
, NULL
, NULL
);
3924 todo_wine_if (keys
[i
] != HKEY_PERFORMANCE_DATA
)
3925 ok(!ret
, "got %u\n", ret
);
3926 todo_wine
ok(!key_count
, "got %u subkeys\n", key_count
);
3927 todo_wine
ok(value_count
== 2, "got %u values\n", value_count
);
3930 ret
= RegEnumValueA(keys
[i
], 0, buffer
, &size
, NULL
, NULL
, NULL
, NULL
);
3931 todo_wine
ok(ret
== ERROR_MORE_DATA
, "got %u\n", ret
);
3932 ok(size
== buffer_size
, "got size %u\n", size
);
3934 ret
= RegCloseKey(keys
[i
]);
3935 ok(!ret
, "got %u\n", ret
);
3937 ret
= RegCloseKey(keys
[i
]);
3938 ok(!ret
, "got %u\n", ret
);
3940 winetest_pop_context();
3943 ret
= RegSetValueExA(HKEY_PERFORMANCE_DATA
, "Global", 0, REG_SZ
, (const BYTE
*)"dummy", 5);
3944 todo_wine
ok(ret
== ERROR_INVALID_HANDLE
, "got %u\n", ret
);
3946 ret
= RegSetValueExA(HKEY_PERFORMANCE_TEXT
, "Global", 0, REG_SZ
, (const BYTE
*)"dummy", 5);
3947 todo_wine
ok(ret
== ERROR_BADKEY
, "got %u\n", ret
);
3949 ret
= RegSetValueExA(HKEY_PERFORMANCE_NLSTEXT
, "Global", 0, REG_SZ
, (const BYTE
*)"dummy", 5);
3950 todo_wine
ok(ret
== ERROR_BADKEY
, "got %u\n", ret
);
3952 if (pRegSetKeyValueW
)
3954 ret
= pRegSetKeyValueW(HKEY_PERFORMANCE_DATA
, NULL
, L
"Global", REG_SZ
, L
"dummy", 10);
3955 todo_wine
ok(ret
== ERROR_INVALID_HANDLE
, "got %u\n", ret
);
3957 ret
= pRegSetKeyValueW(HKEY_PERFORMANCE_TEXT
, NULL
, L
"Global", REG_SZ
, L
"dummy", 10);
3958 todo_wine
ok(ret
== ERROR_BADKEY
, "got %u\n", ret
);
3960 ret
= pRegSetKeyValueW(HKEY_PERFORMANCE_NLSTEXT
, NULL
, L
"Global", REG_SZ
, L
"dummy", 10);
3961 todo_wine
ok(ret
== ERROR_BADKEY
, "got %u\n", ret
);
3964 ret
= RegEnumKeyA(HKEY_PERFORMANCE_DATA
, 0, buffer
, buffer_size
);
3965 todo_wine
ok(ret
== ERROR_INVALID_HANDLE
, "got %u\n", ret
);
3967 ret
= RegEnumKeyA(HKEY_PERFORMANCE_TEXT
, 0, buffer
, buffer_size
);
3968 todo_wine
ok(ret
== ERROR_NO_MORE_ITEMS
, "got %u\n", ret
);
3970 ret
= RegEnumKeyA(HKEY_PERFORMANCE_NLSTEXT
, 0, buffer
, buffer_size
);
3971 todo_wine
ok(ret
== ERROR_NO_MORE_ITEMS
, "got %u\n", ret
);
3976 static void test_perflib_key(void)
3978 unsigned int primary_lang
= PRIMARYLANGID(GetUserDefaultLangID());
3979 unsigned int buffer_size
= 1024 * 1024;
3980 OBJECT_NAME_INFORMATION
*name_info
;
3981 HKEY perflib_key
, key
, key2
;
3982 OBJECT_ATTRIBUTES attr
;
3983 UNICODE_STRING string
;
3989 ret
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
,
3990 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Perflib", 0, KEY_READ
, &perflib_key
);
3991 ok(!ret
, "got %u\n", ret
);
3993 ret
= RegOpenKeyExA(perflib_key
, "009", 0, KEY_READ
, &key
);
3994 ok(!ret
, "got %u\n", ret
);
3995 /* English always returns TEXT; most other languages return NLSTEXT, but
3996 * some (e.g. Hindi) return TEXT */
3997 ok(key
== HKEY_PERFORMANCE_TEXT
|| key
== HKEY_PERFORMANCE_NLSTEXT
, "got key %p\n", key
);
3999 ret
= RegCloseKey(key
);
4000 ok(!ret
, "got %u\n", ret
);
4002 RtlInitUnicodeString(&string
, L
"009");
4003 InitializeObjectAttributes(&attr
, &string
, OBJ_CASE_INSENSITIVE
, perflib_key
, NULL
);
4004 ret
= NtOpenKey((HANDLE
*)&key
, KEY_ALL_ACCESS
, &attr
);
4005 ok(ret
== STATUS_PREDEFINED_HANDLE
|| ret
== STATUS_ACCESS_DENIED
4006 || ret
== STATUS_SUCCESS
/* Win < 7 */, "got %#x\n", ret
);
4007 if (ret
== STATUS_PREDEFINED_HANDLE
)
4008 ok(!is_special_key(key
), "expected a normal handle, got %p\n", key
);
4009 else if (ret
== STATUS_SUCCESS
)
4010 ok(key
== HKEY_PERFORMANCE_TEXT
, "got key %p\n", key
);
4013 skip("Not enough permissions to test the perflib key.\n");
4014 RegCloseKey(perflib_key
);
4018 buffer
= malloc(buffer_size
);
4020 ret
= NtQueryKey(key
, KeyFullInformation
, buffer
, buffer_size
, &size
);
4021 ok(ret
== STATUS_INVALID_HANDLE
, "got %#x\n", ret
);
4023 ret
= NtEnumerateKey(key
, 0, KeyFullInformation
, buffer
, buffer_size
, &size
);
4024 ok(ret
== STATUS_INVALID_HANDLE
, "got %#x\n", ret
);
4026 RtlInitUnicodeString(&string
, L
"counter");
4027 ret
= NtQueryValueKey(key
, &string
, KeyValuePartialInformation
, buffer
, buffer_size
, &size
);
4028 ok(ret
== STATUS_INVALID_HANDLE
, "got %#x\n", ret
);
4030 ret
= NtEnumerateValueKey(key
, 0, KeyValuePartialInformation
, buffer
, buffer_size
, &size
);
4031 ok(ret
== STATUS_INVALID_HANDLE
, "got %#x\n", ret
);
4033 ret
= NtSetValueKey(key
, &string
, 0, REG_SZ
, "test", 5);
4034 ok(ret
== STATUS_INVALID_HANDLE
, "got %#x\n", ret
);
4036 ret
= NtDeleteValueKey(key
, &string
);
4037 ok(ret
== STATUS_INVALID_HANDLE
, "got %#x\n", ret
);
4039 ret
= NtDeleteKey(key
);
4040 ok(ret
== STATUS_INVALID_HANDLE
, "got %#x\n", ret
);
4042 RtlInitUnicodeString(&string
, L
"subkey");
4043 InitializeObjectAttributes(&attr
, &string
, OBJ_CASE_INSENSITIVE
, key
, NULL
);
4044 ret
= NtOpenKey((HANDLE
*)&key2
, KEY_READ
, &attr
);
4045 if (is_special_key(key
))
4046 ok(ret
== STATUS_INVALID_HANDLE
, "got %#x\n", ret
);
4048 ok(ret
== STATUS_OBJECT_NAME_NOT_FOUND
4049 || broken(ret
== STATUS_INVALID_HANDLE
) /* WoW64 */, "got %#x\n", ret
);
4051 ret
= NtCreateKey((HANDLE
*)&key2
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
);
4052 if (is_special_key(key
))
4053 ok(ret
== STATUS_INVALID_HANDLE
, "got %#x\n", ret
);
4055 ok(!ret
|| broken(ret
== STATUS_ACCESS_DENIED
) /* w8adm */
4056 || broken(ret
== STATUS_INVALID_HANDLE
) /* WoW64 */, "got %#x\n", ret
);
4063 /* it's a real handle, though */
4064 ret
= NtQueryObject(key
, ObjectNameInformation
, buffer
, buffer_size
, &size
);
4065 if (is_special_key(key
))
4066 ok(ret
== STATUS_INVALID_HANDLE
, "got %#x\n", ret
);
4068 ok(!ret
, "got %#x\n", ret
);
4071 name_info
= (OBJECT_NAME_INFORMATION
*)buffer
;
4072 ok(!wcsicmp(name_info
->Name
.Buffer
, L
"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT"
4073 "\\CurrentVersion\\Perflib\\009"), "got name %s\n", debugstr_w(name_info
->Name
.Buffer
));
4077 if (is_special_key(key
))
4078 ok(ret
== STATUS_INVALID_HANDLE
, "got %#x\n", ret
);
4080 ok(!ret
, "got %#x\n", ret
);
4082 /* multilingual support was not really completely thought through */
4084 sprintf(lang_name
, "%03x", primary_lang
);
4085 if (primary_lang
!= LANG_ENGLISH
)
4087 ret
= RegOpenKeyExA(perflib_key
, lang_name
, 0, KEY_READ
, &key
);
4088 todo_wine
ok(!ret
, "got %u\n", ret
);
4089 ok(!is_special_key(key
), "expected a normal handle, got %p\n", key
);
4091 ret
= RegQueryValueExA(key
, "counter", NULL
, NULL
, (BYTE
*)buffer
, &size
);
4092 todo_wine
ok(ret
== ERROR_FILE_NOT_FOUND
, "got %u\n", ret
);
4094 ret
= RegCloseKey(key
);
4095 todo_wine
ok(!ret
, "got %u\n", ret
);
4098 ret
= RegCloseKey(perflib_key
);
4099 ok(!ret
, "got %u\n", ret
);
4101 RtlInitUnicodeString(&string
, L
"\\Registry\\PerfData");
4102 InitializeObjectAttributes(&attr
, &string
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
4103 ret
= NtOpenKey((HANDLE
*)&key
, KEY_READ
, &attr
);
4104 todo_wine
ok(ret
== STATUS_OBJECT_NAME_NOT_FOUND
, "got %#x\n", ret
);
4109 static void test_RegLoadMUIString(void)
4111 HMODULE hUser32
, hResDll
, hFile
;
4112 int (WINAPI
*pLoadStringW
)(HMODULE
, UINT
, WCHAR
*, int);
4115 DWORD type
, size
, text_size
;
4117 char buf
[64], *p
, sysdir
[MAX_PATH
];
4118 char with_env_var
[128], filename
[MAX_PATH
], tmp_path
[MAX_PATH
];
4119 WCHAR textW
[64], bufW
[64];
4120 WCHAR curdirW
[MAX_PATH
], sysdirW
[MAX_PATH
];
4121 const static char tz_value
[] = "MUI_Std";
4122 const static WCHAR tz_valueW
[] = L
"MUI_Std";
4131 { "", REG_SZ
, FALSE
, ERROR_INVALID_DATA
},
4132 { "not a MUI string", REG_SZ
, FALSE
, ERROR_INVALID_DATA
},
4133 { "@unknown.dll", REG_SZ
, TRUE
, ERROR_INVALID_DATA
},
4134 { "@unknown.dll,-10", REG_SZ
, TRUE
, ERROR_FILE_NOT_FOUND
},
4136 { with_env_var
, REG_SZ
, FALSE
, ERROR_SUCCESS
},
4137 { with_env_var
, REG_EXPAND_SZ
, FALSE
, ERROR_SUCCESS
},
4138 { "%WineMuiTest1%", REG_EXPAND_SZ
, TRUE
, ERROR_INVALID_DATA
},
4139 { "@%WineMuiTest2%", REG_EXPAND_SZ
, TRUE
, ERROR_SUCCESS
},
4141 { "@%WineMuiExe%,a", REG_SZ
, FALSE
, ERROR_INVALID_DATA
},
4142 { "@%WineMuiExe%,-4", REG_SZ
, FALSE
, ERROR_NOT_FOUND
, ERROR_FILE_NOT_FOUND
},
4143 { "@%WineMuiExe%,-39", REG_SZ
, FALSE
, ERROR_RESOURCE_NAME_NOT_FOUND
},
4144 { "@%WineMuiDat%,-16", REG_EXPAND_SZ
, FALSE
, ERROR_BAD_EXE_FORMAT
, ERROR_FILE_NOT_FOUND
},
4147 if (!pRegLoadMUIStringA
|| !pRegLoadMUIStringW
)
4149 win_skip("RegLoadMUIString is not available\n");
4153 hUser32
= LoadLibraryA("user32.dll");
4154 ok(hUser32
!= NULL
, "cannot load user32.dll\n");
4155 pLoadStringW
= (void *)GetProcAddress(hUser32
, "LoadStringW");
4156 ok(pLoadStringW
!= NULL
, "failed to get LoadStringW address\n");
4158 ret
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
,
4159 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\UTC", 0,
4161 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
4163 size
= ARRAY_SIZE(buf
);
4164 ret
= RegQueryValueExA(hkey
, tz_value
, NULL
, &type
, (BYTE
*)buf
, &size
);
4165 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
4166 ok(buf
[0] == '@', "got %s\n", buf
);
4168 /* setup MUI string for tests */
4169 strcpy(with_env_var
, "@%windir%\\system32\\");
4170 strcat(with_env_var
, &buf
[1]);
4171 SetEnvironmentVariableA("WineMuiTest1", buf
);
4172 SetEnvironmentVariableA("WineMuiTest2", &buf
[1]);
4174 /* load expecting text */
4175 p
= strrchr(buf
, ',');
4177 i
= atoi(p
+ 2); /* skip ',-' */
4178 hResDll
= LoadLibraryExA(&buf
[1], NULL
, LOAD_LIBRARY_AS_DATAFILE
| LOAD_LIBRARY_AS_IMAGE_RESOURCE
);
4179 memset(textW
, 0xaa, sizeof(textW
));
4180 ret
= pLoadStringW(hResDll
, i
, textW
, ARRAY_SIZE(textW
));
4181 ok(ret
> 0, "failed to load string resource\n");
4182 text_size
= (ret
+ 1) * sizeof(WCHAR
);
4183 FreeLibrary(hResDll
);
4184 FreeLibrary(hUser32
);
4186 ret
= GetSystemDirectoryW(sysdirW
, ARRAY_SIZE(sysdirW
));
4187 ok(ret
> 0, "GetSystemDirectoryW failed\n");
4188 ret
= GetSystemDirectoryA(sysdir
, ARRAY_SIZE(sysdir
));
4189 ok(ret
> 0, "GetSystemDirectoryA failed\n");
4191 /* change the current directory to system32 */
4192 GetCurrentDirectoryW(ARRAY_SIZE(curdirW
), curdirW
);
4193 SetCurrentDirectoryW(sysdirW
);
4196 ret
= pRegLoadMUIStringW(hkey
, tz_valueW
, NULL
, 0, &size
, 0, NULL
);
4197 ok(ret
== ERROR_MORE_DATA
, "got %d, expected ERROR_MORE_DATA\n", ret
);
4198 ok(size
== text_size
, "got %u, expected %u\n", size
, text_size
);
4200 memset(bufW
, 0xff, sizeof(bufW
));
4201 ret
= pRegLoadMUIStringW(hkey
, tz_valueW
, bufW
, sizeof(WCHAR
)+1, &size
, 0, NULL
);
4202 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d, expected ERROR_INVALID_PARAMETER\n", ret
);
4203 ok(bufW
[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW
[0]);
4206 memset(bufW
, 0xff, sizeof(bufW
));
4207 ret
= pRegLoadMUIStringW(hkey
, tz_valueW
, bufW
, sizeof(WCHAR
)*2, &size
, 0, NULL
);
4208 ok(ret
== ERROR_MORE_DATA
, "got %d, expected ERROR_MORE_DATA\n", ret
);
4209 ok(size
== text_size
|| broken(size
== text_size
+ sizeof(WCHAR
) /* vista */),
4210 "got %u, expected %u\n", size
, text_size
);
4211 ok(bufW
[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW
[0]);
4213 memset(bufW
, 0xff, sizeof(bufW
));
4214 ret
= pRegLoadMUIStringW(hkey
, tz_valueW
, bufW
, sizeof(WCHAR
)*2, &size
, REG_MUI_STRING_TRUNCATE
, NULL
);
4215 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d, expected ERROR_INVALID_PARAMETER\n", ret
);
4216 ok(bufW
[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW
[0]);
4218 memset(bufW
, 0xff, sizeof(bufW
));
4219 ret
= pRegLoadMUIStringW(hkey
, tz_valueW
, bufW
, sizeof(WCHAR
)*2, NULL
, 0xdeadbeef, NULL
);
4220 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d, expected ERROR_INVALID_PARAMETER\n", ret
);
4221 ok(bufW
[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW
[0]);
4223 memset(bufW
, 0xff, sizeof(bufW
));
4224 ret
= pRegLoadMUIStringW(hkey
, tz_valueW
, bufW
, sizeof(WCHAR
)*2, NULL
, REG_MUI_STRING_TRUNCATE
, NULL
);
4225 ok(ret
== ERROR_SUCCESS
, "got %d, expected ERROR_SUCCESS\n", ret
);
4226 ok(bufW
[0] == textW
[0], "got 0x%04x, expected 0x%04x\n", bufW
[0], textW
[0]);
4227 ok(bufW
[1] == 0, "got 0x%04x, expected nul\n", bufW
[1]);
4230 memset(bufW
, 0xff, sizeof(bufW
));
4231 ret
= pRegLoadMUIStringW(hkey
, tz_valueW
, bufW
, ARRAY_SIZE(bufW
), &size
, 0, NULL
);
4232 ok(ret
== ERROR_SUCCESS
, "got %d, expected ERROR_SUCCESS\n", ret
);
4233 ok(size
== text_size
, "got %u, expected %u\n", size
, text_size
);
4234 ok(!memcmp(textW
, bufW
, size
), "got %s, expected %s\n",
4235 wine_dbgstr_wn(bufW
, size
/ sizeof(WCHAR
)), wine_dbgstr_wn(textW
, text_size
/ sizeof(WCHAR
)));
4237 ret
= pRegLoadMUIStringA(hkey
, tz_value
, buf
, ARRAY_SIZE(buf
), &size
, 0, NULL
);
4238 ok(ret
== ERROR_CALL_NOT_IMPLEMENTED
, "got %d, expected ERROR_CALL_NOT_IMPLEMENTED\n", ret
);
4240 /* change the current directory to other than system32 directory */
4241 SetCurrentDirectoryA("\\");
4244 memset(bufW
, 0xff, sizeof(bufW
));
4245 ret
= pRegLoadMUIStringW(hkey
, tz_valueW
, bufW
, ARRAY_SIZE(bufW
), &size
, 0, sysdirW
);
4246 ok(ret
== ERROR_SUCCESS
, "got %d, expected ERROR_SUCCESS\n", ret
);
4247 ok(size
== text_size
, "got %u, expected %u\n", size
, text_size
);
4248 ok(!memcmp(textW
, bufW
, size
), "got %s, expected %s\n",
4249 wine_dbgstr_wn(bufW
, size
/ sizeof(WCHAR
)), wine_dbgstr_wn(textW
, text_size
/ sizeof(WCHAR
)));
4251 ret
= pRegLoadMUIStringA(hkey
, tz_value
, buf
, ARRAY_SIZE(buf
), &size
, 0, sysdir
);
4252 ok(ret
== ERROR_CALL_NOT_IMPLEMENTED
, "got %d, expected ERROR_CALL_NOT_IMPLEMENTED\n", ret
);
4254 ret
= pRegLoadMUIStringW(hkey
, tz_valueW
, bufW
, ARRAY_SIZE(bufW
), &size
, 0, NULL
);
4255 ok(ret
== ERROR_FILE_NOT_FOUND
, "got %d, expected ERROR_FILE_NOT_FOUND\n", ret
);
4257 ret
= pRegLoadMUIStringA(hkey
, tz_value
, buf
, ARRAY_SIZE(buf
), &size
, 0, NULL
);
4258 ok(ret
== ERROR_CALL_NOT_IMPLEMENTED
, "got %d, expected ERROR_CALL_NOT_IMPLEMENTED\n", ret
);
4262 GetModuleFileNameA(NULL
, filename
, ARRAY_SIZE(filename
));
4263 SetEnvironmentVariableA("WineMuiExe", filename
);
4265 GetTempPathA(ARRAY_SIZE(tmp_path
), tmp_path
);
4266 GetTempFileNameA(tmp_path
, "mui", 0, filename
);
4267 SetEnvironmentVariableA("WineMuiDat", filename
);
4269 /* write dummy data to the file, i.e. it's not a PE file. */
4270 hFile
= CreateFileA(filename
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
4271 ok(hFile
!= INVALID_HANDLE_VALUE
, "can't open %s\n", filename
);
4272 WriteFile(hFile
, filename
, strlen(filename
), &size
, NULL
);
4275 for (i
= 0; i
< ARRAY_SIZE(test_case
); i
++)
4277 size
= test_case
[i
].value
? strlen(test_case
[i
].value
) + 1 : 0;
4278 ret
= RegSetValueExA(hkey_main
, tz_value
, 0, test_case
[i
].type
,
4279 (const BYTE
*)test_case
[i
].value
, size
);
4280 ok(ret
== ERROR_SUCCESS
, "[%2u] got %d\n", i
, ret
);
4283 memset(bufW
, 0xff, sizeof(bufW
));
4284 ret
= pRegLoadMUIStringW(hkey_main
, tz_valueW
, bufW
, ARRAY_SIZE(bufW
),
4286 test_case
[i
].use_sysdir
? sysdirW
: NULL
);
4287 ok(ret
== test_case
[i
].expected
||
4288 broken(test_case
[i
].value
[0] == '%' && ret
== ERROR_SUCCESS
/* vista */) ||
4289 broken(test_case
[i
].broken_ret
&& ret
== test_case
[i
].broken_ret
/* vista */),
4290 "[%2u] expected %d, got %d\n", i
, test_case
[i
].expected
, ret
);
4291 if (ret
== ERROR_SUCCESS
&& test_case
[i
].expected
== ERROR_SUCCESS
)
4293 ok(size
== text_size
, "[%2u] got %u, expected %u\n", i
, size
, text_size
);
4294 ok(!memcmp(bufW
, textW
, size
), "[%2u] got %s, expected %s\n", i
,
4295 wine_dbgstr_wn(bufW
, size
/sizeof(WCHAR
)),
4296 wine_dbgstr_wn(textW
, text_size
/sizeof(WCHAR
)));
4300 SetCurrentDirectoryW(curdirW
);
4301 DeleteFileA(filename
);
4302 SetEnvironmentVariableA("WineMuiTest1", NULL
);
4303 SetEnvironmentVariableA("WineMuiTest2", NULL
);
4304 SetEnvironmentVariableA("WineMuiExe", NULL
);
4305 SetEnvironmentVariableA("WineMuiDat", NULL
);
4308 static void test_EnumDynamicTimeZoneInformation(void)
4314 WCHAR sysdir
[MAX_PATH
];
4315 DWORD index
, ret
, gle
, size
;
4316 DYNAMIC_TIME_ZONE_INFORMATION bogus_dtzi
, dtzi
;
4322 SYSTEMTIME std_date
;
4323 SYSTEMTIME dlt_date
;
4326 if (!pEnumDynamicTimeZoneInformation
)
4328 win_skip("EnumDynamicTimeZoneInformation is not supported.\n");
4332 if (pRegLoadMUIStringW
)
4333 GetSystemDirectoryW(sysdir
, ARRAY_SIZE(sysdir
));
4335 SetLastError(0xdeadbeef);
4336 ret
= pEnumDynamicTimeZoneInformation(0, NULL
);
4337 gle
= GetLastError();
4338 ok(gle
== 0xdeadbeef, "got 0x%x\n", gle
);
4339 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
4341 memset(&bogus_dtzi
, 0xcc, sizeof(bogus_dtzi
));
4342 memset(&dtzi
, 0xcc, sizeof(dtzi
));
4343 SetLastError(0xdeadbeef);
4344 ret
= pEnumDynamicTimeZoneInformation(-1, &dtzi
);
4345 gle
= GetLastError();
4346 ok(gle
== 0xdeadbeef, "got 0x%x\n", gle
);
4347 ok(ret
== ERROR_NO_MORE_ITEMS
, "got %d\n", ret
);
4348 ok(!memcmp(&dtzi
, &bogus_dtzi
, sizeof(dtzi
)), "mismatch\n");
4350 status
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
,
4351 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0,
4352 KEY_ENUMERATE_SUB_KEYS
|KEY_QUERY_VALUE
, &key
);
4353 ok(status
== ERROR_SUCCESS
, "got %d\n", status
);
4355 while (!(status
= RegEnumKeyW(key
, index
, keyname
, ARRAY_SIZE(keyname
))))
4357 winetest_push_context("%s" , wine_dbgstr_w(keyname
));
4359 status
= RegOpenKeyExW(key
, keyname
, 0, KEY_QUERY_VALUE
, &subkey
);
4360 ok(status
== ERROR_SUCCESS
, "got %d\n", status
);
4362 memset(&dtzi
, 0xcc, sizeof(dtzi
));
4363 SetLastError(0xdeadbeef);
4364 ret
= pEnumDynamicTimeZoneInformation(index
, &dtzi
);
4365 gle
= GetLastError();
4366 /* recently added time zones may not have MUI strings */
4367 ok(gle
== ERROR_SUCCESS
||
4368 gle
== ERROR_RESOURCE_TYPE_NOT_FOUND
/* Win10 1809 32-bit */ ||
4369 gle
== ERROR_MUI_FILE_NOT_FOUND
/* Win10 1809 64-bit */,
4371 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
4372 ok(!lstrcmpW(dtzi
.TimeZoneKeyName
, keyname
), "expected %s, got %s\n",
4373 wine_dbgstr_w(keyname
), wine_dbgstr_w(dtzi
.TimeZoneKeyName
));
4375 if (gle
== ERROR_SUCCESS
)
4377 size
= sizeof(name
);
4378 memset(name
, 0, sizeof(name
));
4379 status
= pRegGetValueW(subkey
, NULL
, L
"Std", RRF_RT_REG_SZ
, NULL
, name
, &size
);
4380 ok(status
== ERROR_SUCCESS
, "status %d Std %s\n", status
,
4381 wine_dbgstr_w(name
));
4382 ok(*name
, "Std name is empty\n");
4383 if (pRegLoadMUIStringW
)
4385 size
= sizeof(name
);
4386 memset(name
, 0, sizeof(name
));
4387 status
= pRegLoadMUIStringW(subkey
, L
"MUI_Std", name
, size
, &size
, 0, sysdir
);
4388 ok(status
== ERROR_SUCCESS
, "status %d MUI_Std %s\n",
4389 status
, wine_dbgstr_w(name
));
4390 ok(*name
, "MUI_Std name is empty\n");
4392 ok(!memcmp(&dtzi
.StandardName
, name
, size
), "expected %s, got %s\n",
4393 wine_dbgstr_w(name
), wine_dbgstr_w(dtzi
.StandardName
));
4395 size
= sizeof(name
);
4396 memset(name
, 0, sizeof(name
));
4397 status
= pRegGetValueW(subkey
, NULL
, L
"Dlt", RRF_RT_REG_SZ
, NULL
, name
, &size
);
4398 ok(status
== ERROR_SUCCESS
, "status %d %s Dlt %s\n",
4399 status
, wine_dbgstr_w(keyname
), wine_dbgstr_w(name
));
4400 ok(*name
, "Dlt name is empty\n");
4401 if (pRegLoadMUIStringW
)
4403 size
= sizeof(name
);
4404 memset(name
, 0, sizeof(name
));
4405 status
= pRegLoadMUIStringW(subkey
, L
"MUI_Dlt", name
, size
, &size
, 0, sysdir
);
4406 ok(status
== ERROR_SUCCESS
, "status %d %s MUI_Dlt %s\n",
4407 status
, wine_dbgstr_w(keyname
), wine_dbgstr_w(name
));
4408 ok(*name
, "MUI_Dlt name is empty\n");
4410 ok(!memcmp(&dtzi
.DaylightName
, name
, size
), "expected %s, got %s\n",
4411 wine_dbgstr_w(name
), wine_dbgstr_w(dtzi
.DaylightName
));
4413 size
= sizeof(name
);
4414 memset(name
, 0, sizeof(name
));
4415 status
= pRegGetValueW(subkey
, NULL
, L
"Display", RRF_RT_REG_SZ
, NULL
, name
, &size
);
4416 ok(status
== ERROR_SUCCESS
, "status %d %s Display %s\n",
4417 status
, wine_dbgstr_w(keyname
), wine_dbgstr_w(name
));
4418 ok(*name
, "Display name is empty\n");
4419 if (pRegLoadMUIStringW
)
4421 size
= sizeof(name
);
4422 memset(name
, 0, sizeof(name
));
4423 status
= pRegLoadMUIStringW(subkey
, L
"MUI_Display", name
, size
, &size
, 0, sysdir
);
4424 /* recently added time zones may not have MUI strings */
4425 todo_wine
ok((status
== ERROR_SUCCESS
&& *name
) ||
4426 broken(status
== ERROR_RESOURCE_TYPE_NOT_FOUND
) /* Win10 1809 32-bit */ ||
4427 broken(status
== ERROR_MUI_FILE_NOT_FOUND
) /* Win10 1809 64-bit */,
4428 "status %d MUI_Display %s\n", status
, wine_dbgstr_w(name
));
4433 ok(!dtzi
.StandardName
[0], "expected empty StandardName\n");
4434 ok(!dtzi
.DaylightName
[0], "expected empty DaylightName\n");
4437 ok(!dtzi
.DynamicDaylightTimeDisabled
, "got %d\n", dtzi
.DynamicDaylightTimeDisabled
);
4439 size
= sizeof(tz_data
);
4440 status
= pRegGetValueW(key
, keyname
, L
"TZI", RRF_RT_REG_BINARY
, NULL
, &tz_data
, &size
);
4441 ok(status
== ERROR_SUCCESS
, "got %d\n", status
);
4443 ok(dtzi
.Bias
== tz_data
.bias
, "expected %d, got %d\n",
4444 tz_data
.bias
, dtzi
.Bias
);
4445 ok(dtzi
.StandardBias
== tz_data
.std_bias
, "expected %d, got %d\n",
4446 tz_data
.std_bias
, dtzi
.StandardBias
);
4447 ok(dtzi
.DaylightBias
== tz_data
.dlt_bias
, "expected %d, got %d\n",
4448 tz_data
.dlt_bias
, dtzi
.DaylightBias
);
4450 ok(!memcmp(&dtzi
.StandardDate
, &tz_data
.std_date
, sizeof(dtzi
.StandardDate
)),
4451 "expected %s, got %s\n",
4452 dbgstr_SYSTEMTIME(&tz_data
.std_date
), dbgstr_SYSTEMTIME(&dtzi
.StandardDate
));
4454 ok(!memcmp(&dtzi
.DaylightDate
, &tz_data
.dlt_date
, sizeof(dtzi
.DaylightDate
)),
4455 "expected %s, got %s\n",
4456 dbgstr_SYSTEMTIME(&tz_data
.dlt_date
), dbgstr_SYSTEMTIME(&dtzi
.DaylightDate
));
4458 winetest_pop_context();
4459 RegCloseKey(subkey
);
4462 ok(status
== ERROR_NO_MORE_ITEMS
, "got %d\n", status
);
4464 memset(&dtzi
, 0xcc, sizeof(dtzi
));
4465 SetLastError(0xdeadbeef);
4466 ret
= pEnumDynamicTimeZoneInformation(index
, &dtzi
);
4467 gle
= GetLastError();
4468 ok(gle
== 0xdeadbeef, "got 0x%x\n", gle
);
4469 ok(ret
== ERROR_NO_MORE_ITEMS
, "got %d\n", ret
);
4470 ok(!memcmp(&dtzi
, &bogus_dtzi
, sizeof(dtzi
)), "mismatch\n");
4475 START_TEST(registry
)
4477 /* Load pointers for functions that are not available in all Windows versions */
4483 create_test_entries();
4485 test_query_value_ex();
4487 test_reg_open_key();
4488 test_reg_create_key();
4489 test_reg_close_key();
4490 test_reg_delete_key();
4491 test_reg_query_value();
4492 test_reg_query_info();
4493 test_string_termination();
4497 test_classesroot_enum();
4498 test_classesroot_mask();
4499 test_reg_save_key();
4500 test_reg_load_key();
4501 test_reg_unload_key();
4502 test_reg_copy_tree();
4503 test_reg_delete_tree();
4506 test_delete_value();
4507 test_delete_key_value();
4508 test_RegOpenCurrentUser();
4509 test_RegNotifyChangeKeyValue();
4510 test_performance_keys();
4511 test_RegLoadMUIString();
4512 test_EnumDynamicTimeZoneInformation();
4516 delete_key( hkey_main
);
4518 test_regconnectregistry();