makefiles: Don't use standard libs for programs that specify -nodefaultlibs.
[wine/zf.git] / dlls / advapi32 / tests / registry.c
blobc8f9adf7732b9b86f127f2aaec02360a4d074a20
1 /*
2 * Unit tests for registry functions
4 * Copyright (c) 2002 Alexandre Julliard
5 * Copyright (c) 2010 André Hentschel
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include "wine/test.h"
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winternl.h"
29 #include "winreg.h"
30 #include "winperf.h"
31 #include "winsvc.h"
32 #include "winerror.h"
33 #include "aclapi.h"
35 #define IS_HKCR(hk) ((UINT_PTR)hk > 0 && ((UINT_PTR)hk & 3) == 2)
37 static HKEY hkey_main;
38 static DWORD GLE;
40 static const char * sTestpath1 = "%LONGSYSTEMVAR%\\subdir1";
41 static const char * sTestpath2 = "%FOO%\\subdir1";
42 static const DWORD ptr_size = 8 * sizeof(void*);
44 static DWORD (WINAPI *pRegGetValueA)(HKEY,LPCSTR,LPCSTR,DWORD,LPDWORD,PVOID,LPDWORD);
45 static DWORD (WINAPI *pRegGetValueW)(HKEY,LPCWSTR,LPCWSTR,DWORD,LPDWORD,PVOID,LPDWORD);
46 static LONG (WINAPI *pRegCopyTreeA)(HKEY,const char *,HKEY);
47 static LONG (WINAPI *pRegDeleteTreeA)(HKEY,const char *);
48 static DWORD (WINAPI *pRegDeleteKeyExA)(HKEY,LPCSTR,REGSAM,DWORD);
49 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
50 static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
51 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(UNICODE_STRING*);
52 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
53 static LONG (WINAPI *pRegDeleteKeyValueA)(HKEY,LPCSTR,LPCSTR);
54 static LONG (WINAPI *pRegSetKeyValueW)(HKEY,LPCWSTR,LPCWSTR,DWORD,const void*,DWORD);
55 static LONG (WINAPI *pRegLoadMUIStringA)(HKEY,LPCSTR,LPSTR,DWORD,LPDWORD,DWORD,LPCSTR);
56 static LONG (WINAPI *pRegLoadMUIStringW)(HKEY,LPCWSTR,LPWSTR,DWORD,LPDWORD,DWORD,LPCWSTR);
57 static DWORD (WINAPI *pEnumDynamicTimeZoneInformation)(const DWORD,
58 DYNAMIC_TIME_ZONE_INFORMATION*);
60 static BOOL limited_user;
62 static const char *dbgstr_SYSTEMTIME(const SYSTEMTIME *st)
64 return wine_dbg_sprintf("%02d-%02d-%04d %02d:%02d:%02d.%03d",
65 st->wMonth, st->wDay, st->wYear,
66 st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);
69 #define ADVAPI32_GET_PROC(func) \
70 p ## func = (void*)GetProcAddress(hadvapi32, #func)
72 static void InitFunctionPtrs(void)
74 HMODULE hntdll = GetModuleHandleA("ntdll.dll");
75 HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
76 HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
78 /* This function was introduced with Windows 2003 SP1 */
79 ADVAPI32_GET_PROC(RegGetValueA);
80 ADVAPI32_GET_PROC(RegGetValueW);
81 ADVAPI32_GET_PROC(RegCopyTreeA);
82 ADVAPI32_GET_PROC(RegDeleteTreeA);
83 ADVAPI32_GET_PROC(RegDeleteKeyExA);
84 ADVAPI32_GET_PROC(RegDeleteKeyValueA);
85 ADVAPI32_GET_PROC(RegSetKeyValueW);
86 ADVAPI32_GET_PROC(RegLoadMUIStringA);
87 ADVAPI32_GET_PROC(RegLoadMUIStringW);
88 ADVAPI32_GET_PROC(EnumDynamicTimeZoneInformation);
90 pIsWow64Process = (void *)GetProcAddress( hkernel32, "IsWow64Process" );
91 pRtlFormatCurrentUserKeyPath = (void *)GetProcAddress( hntdll, "RtlFormatCurrentUserKeyPath" );
92 pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString");
93 pNtDeleteKey = (void *)GetProcAddress( hntdll, "NtDeleteKey" );
96 /* delete key and all its subkeys */
97 static DWORD delete_key( HKEY hkey )
99 char name[MAX_PATH];
100 DWORD ret;
102 if ((ret = RegOpenKeyExA( hkey, "", 0, KEY_ENUMERATE_SUB_KEYS, &hkey ))) return ret;
103 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
105 HKEY tmp;
106 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
108 ret = delete_key( tmp );
109 RegCloseKey( tmp );
111 if (ret) break;
113 if (ret != ERROR_NO_MORE_ITEMS) return ret;
114 RegDeleteKeyA( hkey, "" );
115 RegCloseKey(hkey);
116 return 0;
119 static void setup_main_key(void)
121 DWORD ret;
123 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main )) delete_key( hkey_main );
125 ret = RegCreateKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main );
126 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
129 static void check_user_privs(void)
131 DWORD ret;
132 HKEY hkey = (HKEY)0xdeadbeef;
134 ret = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WRITE, &hkey);
135 ok(ret == ERROR_SUCCESS || ret == ERROR_ACCESS_DENIED, "expected success or access denied, got %i\n", ret);
136 if (ret == ERROR_SUCCESS)
138 ok(hkey != NULL, "RegOpenKeyExA succeeded but returned NULL hkey\n");
139 RegCloseKey(hkey);
141 else
143 ok(hkey == NULL, "RegOpenKeyExA failed but returned hkey %p\n", hkey);
144 limited_user = TRUE;
145 trace("running as limited user\n");
149 #define lok ok_(__FILE__, line)
150 #define test_hkey_main_Value_A(name, string, full_byte_len) _test_hkey_main_Value_A(__LINE__, name, string, full_byte_len)
151 static void _test_hkey_main_Value_A(int line, LPCSTR name, LPCSTR string,
152 DWORD full_byte_len)
154 DWORD ret, type, cbData;
155 DWORD str_byte_len;
156 BYTE* value;
158 type=0xdeadbeef;
159 cbData=0xdeadbeef;
160 /* When successful RegQueryValueExA() leaves GLE as is,
161 * so we must reset it to detect unimplemented functions.
163 SetLastError(0xdeadbeef);
164 ret = RegQueryValueExA(hkey_main, name, NULL, &type, NULL, &cbData);
165 GLE = GetLastError();
166 lok(ret == ERROR_SUCCESS, "RegQueryValueExA/1 failed: %d, GLE=%d\n", ret, GLE);
167 /* It is wrong for the Ansi version to not be implemented */
168 ok(GLE == 0xdeadbeef, "RegQueryValueExA set GLE = %u\n", GLE);
169 if(GLE == ERROR_CALL_NOT_IMPLEMENTED) return;
171 str_byte_len = (string ? lstrlenA(string) : 0) + 1;
172 lok(type == REG_SZ, "RegQueryValueExA/1 returned type %d\n", type);
173 lok(cbData == full_byte_len, "cbData=%d instead of %d or %d\n", cbData, full_byte_len, str_byte_len);
175 value = HeapAlloc(GetProcessHeap(), 0, cbData+1);
176 memset(value, 0xbd, cbData+1);
177 type=0xdeadbeef;
178 ret = RegQueryValueExA(hkey_main, name, NULL, &type, value, &cbData);
179 GLE = GetLastError();
180 lok(ret == ERROR_SUCCESS, "RegQueryValueExA/2 failed: %d, GLE=%d\n", ret, GLE);
181 if (!string)
183 /* When cbData == 0, RegQueryValueExA() should not modify the buffer */
184 lok(*value == 0xbd, "RegQueryValueExA overflowed: cbData=%u *value=%02x\n", cbData, *value);
186 else
188 lok(memcmp(value, string, cbData) == 0, "RegQueryValueExA/2 failed: %s/%d != %s/%d\n",
189 debugstr_an((char*)value, cbData), cbData,
190 debugstr_an(string, full_byte_len), full_byte_len);
191 lok(*(value+cbData) == 0xbd, "RegQueryValueExA/2 overflowed at offset %u: %02x != bd\n", cbData, *(value+cbData));
193 HeapFree(GetProcessHeap(), 0, value);
196 #define test_hkey_main_Value_W(name, string, full_byte_len) _test_hkey_main_Value_W(__LINE__, name, string, full_byte_len)
197 static void _test_hkey_main_Value_W(int line, LPCWSTR name, LPCWSTR string,
198 DWORD full_byte_len)
200 DWORD ret, type, cbData;
201 BYTE* value;
203 type=0xdeadbeef;
204 cbData=0xdeadbeef;
205 /* When successful RegQueryValueExW() leaves GLE as is,
206 * so we must reset it to detect unimplemented functions.
208 SetLastError(0xdeadbeef);
209 ret = RegQueryValueExW(hkey_main, name, NULL, &type, NULL, &cbData);
210 GLE = GetLastError();
211 lok(ret == ERROR_SUCCESS, "RegQueryValueExW/1 failed: %d, GLE=%d\n", ret, GLE);
212 if(GLE == ERROR_CALL_NOT_IMPLEMENTED)
214 win_skip("RegQueryValueExW() is not implemented\n");
215 return;
218 lok(type == REG_SZ, "RegQueryValueExW/1 returned type %d\n", type);
219 lok(cbData == full_byte_len,
220 "cbData=%d instead of %d\n", cbData, full_byte_len);
222 /* Give enough space to overflow by one WCHAR */
223 value = HeapAlloc(GetProcessHeap(), 0, cbData+2);
224 memset(value, 0xbd, cbData+2);
225 type=0xdeadbeef;
226 ret = RegQueryValueExW(hkey_main, name, NULL, &type, value, &cbData);
227 GLE = GetLastError();
228 lok(ret == ERROR_SUCCESS, "RegQueryValueExW/2 failed: %d, GLE=%d\n", ret, GLE);
229 if (string)
231 lok(memcmp(value, string, cbData) == 0, "RegQueryValueExW failed: %s/%d != %s/%d\n",
232 wine_dbgstr_wn((WCHAR*)value, cbData / sizeof(WCHAR)), cbData,
233 wine_dbgstr_wn(string, full_byte_len / sizeof(WCHAR)), full_byte_len);
235 /* This implies that when cbData == 0, RegQueryValueExW() should not modify the buffer */
236 lok(*(value+cbData) == 0xbd, "RegQueryValueExW/2 overflowed at %u: %02x != bd\n", cbData, *(value+cbData));
237 lok(*(value+cbData+1) == 0xbd, "RegQueryValueExW/2 overflowed at %u+1: %02x != bd\n", cbData, *(value+cbData+1));
238 HeapFree(GetProcessHeap(), 0, value);
241 static void test_set_value(void)
243 DWORD ret;
245 static const WCHAR name1W[] = {'C','l','e','a','n','S','i','n','g','l','e','S','t','r','i','n','g', 0};
246 static const WCHAR name2W[] = {'S','o','m','e','I','n','t','r','a','Z','e','r','o','e','d','S','t','r','i','n','g', 0};
247 static const WCHAR emptyW[] = {0};
248 static const WCHAR string1W[] = {'T','h','i','s','N','e','v','e','r','B','r','e','a','k','s', 0};
249 static const WCHAR string2W[] = {'T','h','i','s', 0 ,'B','r','e','a','k','s', 0 , 0 ,'A', 0 , 0 , 0 , 'L','o','t', 0 , 0 , 0 , 0, 0};
250 static const WCHAR substring2W[] = {'T','h','i','s',0};
252 static const char name1A[] = "CleanSingleString";
253 static const char name2A[] = "SomeIntraZeroedString";
254 static const char emptyA[] = "";
255 static const char string1A[] = "ThisNeverBreaks";
256 static const char string2A[] = "This\0Breaks\0\0A\0\0\0Lot\0\0\0\0";
257 static const char substring2A[] = "This";
259 if (0)
261 /* Crashes on NT4, Windows 2000 and XP SP1 */
262 ret = RegSetValueA(hkey_main, NULL, REG_SZ, NULL, 0);
263 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have failed with ERROR_INVALID_PARAMETER instead of %d\n", ret);
266 ret = RegSetValueA(hkey_main, NULL, REG_SZ, string1A, sizeof(string1A));
267 ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %d, GLE=%d\n", ret, GetLastError());
268 test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
269 test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
271 /* RegSetValueA ignores the size passed in */
272 ret = RegSetValueA(hkey_main, NULL, REG_SZ, string1A, 4);
273 ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %d, GLE=%d\n", ret, GetLastError());
274 test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
275 test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
277 /* stops at first null */
278 ret = RegSetValueA(hkey_main, NULL, REG_SZ, string2A, sizeof(string2A));
279 ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %d, GLE=%d\n", ret, GetLastError());
280 test_hkey_main_Value_A(NULL, substring2A, sizeof(substring2A));
281 test_hkey_main_Value_W(NULL, substring2W, sizeof(substring2W));
283 /* only REG_SZ is supported on NT*/
284 ret = RegSetValueA(hkey_main, NULL, REG_BINARY, string2A, sizeof(string2A));
285 ok(ret == ERROR_INVALID_PARAMETER, "got %d (expected ERROR_INVALID_PARAMETER)\n", ret);
287 ret = RegSetValueA(hkey_main, NULL, REG_EXPAND_SZ, string2A, sizeof(string2A));
288 ok(ret == ERROR_INVALID_PARAMETER, "got %d (expected ERROR_INVALID_PARAMETER)\n", ret);
290 ret = RegSetValueA(hkey_main, NULL, REG_MULTI_SZ, string2A, sizeof(string2A));
291 ok(ret == ERROR_INVALID_PARAMETER, "got %d (expected ERROR_INVALID_PARAMETER)\n", ret);
293 /* Test RegSetValueExA with a 'zero-byte' string (as Office 2003 does).
294 * Surprisingly enough we're supposed to get zero bytes out of it.
296 ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)emptyA, 0);
297 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
298 test_hkey_main_Value_A(name1A, NULL, 0);
299 test_hkey_main_Value_W(name1W, NULL, 0);
301 /* test RegSetValueExA with an empty string */
302 ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)emptyA, sizeof(emptyA));
303 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
304 test_hkey_main_Value_A(name1A, emptyA, sizeof(emptyA));
305 test_hkey_main_Value_W(name1W, emptyW, sizeof(emptyW));
307 /* test RegSetValueExA with off-by-one size */
308 ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)string1A, sizeof(string1A)-sizeof(string1A[0]));
309 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
310 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
311 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
313 /* test RegSetValueExA with normal string */
314 ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)string1A, sizeof(string1A));
315 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
316 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
317 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
319 /* test RegSetValueExA with intrazeroed string */
320 ret = RegSetValueExA(hkey_main, name2A, 0, REG_SZ, (const BYTE *)string2A, sizeof(string2A));
321 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
322 test_hkey_main_Value_A(name2A, string2A, sizeof(string2A));
323 test_hkey_main_Value_W(name2W, string2W, sizeof(string2W));
325 if (0)
327 /* Crashes on NT4, Windows 2000 and XP SP1 */
328 ret = RegSetValueW(hkey_main, NULL, REG_SZ, NULL, 0);
329 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have failed with ERROR_INVALID_PARAMETER instead of %d\n", ret);
331 RegSetValueExA(hkey_main, name2A, 0, REG_SZ, (const BYTE *)1, 1);
332 RegSetValueExA(hkey_main, name2A, 0, REG_DWORD, (const BYTE *)1, 1);
335 ret = RegSetValueW(hkey_main, NULL, REG_SZ, string1W, sizeof(string1W));
336 ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %d, GLE=%d\n", ret, GetLastError());
337 test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
338 test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
340 ret = RegSetValueW(hkey_main, name1W, REG_SZ, string1W, sizeof(string1W));
341 ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %d, GLE=%d\n", ret, GetLastError());
342 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
343 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
345 /* RegSetValueW ignores the size passed in */
346 ret = RegSetValueW(hkey_main, NULL, REG_SZ, string1W, 4 * sizeof(string1W[0]));
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 /* stops at first null */
352 ret = RegSetValueW(hkey_main, NULL, REG_SZ, string2W, sizeof(string2W));
353 ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %d, GLE=%d\n", ret, GetLastError());
354 test_hkey_main_Value_A(NULL, substring2A, sizeof(substring2A));
355 test_hkey_main_Value_W(NULL, substring2W, sizeof(substring2W));
357 /* only REG_SZ is supported */
358 ret = RegSetValueW(hkey_main, NULL, REG_BINARY, string2W, sizeof(string2W));
359 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
360 ret = RegSetValueW(hkey_main, NULL, REG_EXPAND_SZ, string2W, sizeof(string2W));
361 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
362 ret = RegSetValueW(hkey_main, NULL, REG_MULTI_SZ, string2W, sizeof(string2W));
363 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
365 /* test RegSetValueExW with off-by-one size */
366 ret = RegSetValueExW(hkey_main, name1W, 0, REG_SZ, (const BYTE *)string1W, sizeof(string1W)-sizeof(string1W[0]));
367 ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %d, GLE=%d\n", ret, GetLastError());
368 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
369 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
371 /* test RegSetValueExW with normal string */
372 ret = RegSetValueExW(hkey_main, name1W, 0, REG_SZ, (const BYTE *)string1W, sizeof(string1W));
373 ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %d, GLE=%d\n", ret, GetLastError());
374 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
375 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
377 /* test RegSetValueExW with intrazeroed string */
378 ret = RegSetValueExW(hkey_main, name2W, 0, REG_SZ, (const BYTE *)string2W, sizeof(string2W));
379 ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %d, GLE=%d\n", ret, GetLastError());
380 test_hkey_main_Value_A(name2A, string2A, sizeof(string2A));
381 test_hkey_main_Value_W(name2W, string2W, sizeof(string2W));
383 /* test RegSetValueExW with data = 1 */
384 ret = RegSetValueExW(hkey_main, name2W, 0, REG_SZ, (const BYTE *)1, 1);
385 ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %d, GLE=%d\n", ret, GetLastError());
386 ret = RegSetValueExW(hkey_main, name2W, 0, REG_DWORD, (const BYTE *)1, 1);
387 ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %d, GLE=%d\n", ret, GetLastError());
389 if (pRegGetValueA) /* avoid a crash on Windows 2000 */
391 ret = RegSetValueExW(hkey_main, NULL, 0, REG_SZ, NULL, 4);
392 ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %d, GLE=%d\n", ret, GetLastError());
394 ret = RegSetValueExW(hkey_main, NULL, 0, REG_SZ, NULL, 0);
395 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
397 ret = RegSetValueExW(hkey_main, NULL, 0, REG_DWORD, NULL, 4);
398 ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %d, GLE=%d\n", ret, GetLastError());
400 ret = RegSetValueExW(hkey_main, NULL, 0, REG_DWORD, NULL, 0);
401 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
404 /* RegSetKeyValue */
405 if (!pRegSetKeyValueW)
406 win_skip("RegSetKeyValue() is not supported.\n");
407 else
409 static const WCHAR subkeyW[] = {'s','u','b','k','e','y',0};
410 DWORD len, type;
411 HKEY subkey;
413 ret = pRegSetKeyValueW(hkey_main, NULL, name1W, REG_SZ, (const BYTE*)string2W, sizeof(string2W));
414 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
415 test_hkey_main_Value_A(name1A, string2A, sizeof(string2A));
416 test_hkey_main_Value_W(name1W, string2W, sizeof(string2W));
418 ret = pRegSetKeyValueW(hkey_main, subkeyW, name1W, REG_SZ, string1W, sizeof(string1W));
419 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
421 ret = RegOpenKeyExW(hkey_main, subkeyW, 0, KEY_QUERY_VALUE, &subkey);
422 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
423 type = len = 0;
424 ret = RegQueryValueExW(subkey, name1W, 0, &type, NULL, &len);
425 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
426 ok(len == sizeof(string1W), "got %d\n", len);
427 ok(type == REG_SZ, "got type %d\n", type);
429 ret = pRegSetKeyValueW(hkey_main, subkeyW, name1W, REG_SZ, NULL, 0);
430 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
432 ret = pRegSetKeyValueW(hkey_main, subkeyW, name1W, REG_SZ, NULL, 4);
433 ok(ret == ERROR_NOACCESS, "got %d\n", ret);
435 ret = pRegSetKeyValueW(hkey_main, subkeyW, name1W, REG_DWORD, NULL, 4);
436 ok(ret == ERROR_NOACCESS, "got %d\n", ret);
438 RegCloseKey(subkey);
442 static void create_test_entries(void)
444 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
446 SetEnvironmentVariableA("LONGSYSTEMVAR", "bar");
447 SetEnvironmentVariableA("FOO", "ImARatherLongButIndeedNeededString");
449 ok(!RegSetValueExA(hkey_main,"TP1_EXP_SZ",0,REG_EXPAND_SZ, (const BYTE *)sTestpath1, strlen(sTestpath1)+1),
450 "RegSetValueExA failed\n");
451 ok(!RegSetValueExA(hkey_main,"TP1_SZ",0,REG_SZ, (const BYTE *)sTestpath1, strlen(sTestpath1)+1),
452 "RegSetValueExA failed\n");
453 ok(!RegSetValueExA(hkey_main,"TP1_ZB_SZ",0,REG_SZ, (const BYTE *)"", 0),
454 "RegSetValueExA failed\n");
455 ok(!RegSetValueExA(hkey_main,"TP2_EXP_SZ",0,REG_EXPAND_SZ, (const BYTE *)sTestpath2, strlen(sTestpath2)+1),
456 "RegSetValueExA failed\n");
457 ok(!RegSetValueExA(hkey_main,"DWORD",0,REG_DWORD, (const BYTE *)qw, 4),
458 "RegSetValueExA failed\n");
459 ok(!RegSetValueExA(hkey_main,"BIN32",0,REG_BINARY, (const BYTE *)qw, 4),
460 "RegSetValueExA failed\n");
461 ok(!RegSetValueExA(hkey_main,"BIN64",0,REG_BINARY, (const BYTE *)qw, 8),
462 "RegSetValueExA failed\n");
465 static void test_enum_value(void)
467 DWORD res;
468 HKEY test_key;
469 char value[20], data[20];
470 WCHAR valueW[20], dataW[20];
471 DWORD val_count, data_count, type;
472 static const WCHAR foobarW[] = {'f','o','o','b','a','r',0};
473 static const WCHAR testW[] = {'T','e','s','t',0};
474 static const WCHAR xxxW[] = {'x','x','x','x','x','x','x','x',0};
476 /* create the working key for new 'Test' value */
477 res = RegCreateKeyA( hkey_main, "TestKey", &test_key );
478 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res);
480 /* check NULL data with zero length */
481 res = RegSetValueExA( test_key, "Test", 0, REG_SZ, NULL, 0 );
482 if (GetVersion() & 0x80000000)
483 ok( res == ERROR_INVALID_PARAMETER, "RegSetValueExA returned %d\n", res );
484 else
485 ok( !res, "RegSetValueExA returned %d\n", res );
486 res = RegSetValueExA( test_key, "Test", 0, REG_EXPAND_SZ, NULL, 0 );
487 ok( ERROR_SUCCESS == res || ERROR_INVALID_PARAMETER == res, "RegSetValueExA returned %d\n", res );
488 res = RegSetValueExA( test_key, "Test", 0, REG_BINARY, NULL, 0 );
489 ok( ERROR_SUCCESS == res || ERROR_INVALID_PARAMETER == res, "RegSetValueExA returned %d\n", res );
491 /* test reading the value and data without setting them */
492 val_count = 20;
493 data_count = 20;
494 type = 1234;
495 strcpy( value, "xxxxxxxxxx" );
496 strcpy( data, "xxxxxxxxxx" );
497 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
498 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res );
499 ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
500 ok( data_count == 0, "data_count set to %d instead of 0\n", data_count );
501 ok( type == REG_BINARY, "type %d is not REG_BINARY\n", type );
502 ok( !strcmp( value, "Test" ), "value is '%s' instead of Test\n", value );
503 ok( !strcmp( data, "xxxxxxxxxx" ), "data is '%s' instead of xxxxxxxxxx\n", data );
505 val_count = 20;
506 data_count = 20;
507 type = 1234;
508 memcpy( valueW, xxxW, sizeof(xxxW) );
509 memcpy( dataW, xxxW, sizeof(xxxW) );
510 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
511 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res );
512 ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
513 ok( data_count == 0, "data_count set to %d instead of 0\n", data_count );
514 ok( type == REG_BINARY, "type %d is not REG_BINARY\n", type );
515 ok( !memcmp( valueW, testW, sizeof(testW) ), "value is not 'Test'\n" );
516 ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data is not 'xxxxxxxxxx'\n" );
518 res = RegSetValueExA( test_key, "Test", 0, REG_SZ, (const BYTE *)"foobar", 7 );
519 ok( res == 0, "RegSetValueExA failed error %d\n", res );
521 /* overflow both name and data */
522 val_count = 2;
523 data_count = 2;
524 type = 1234;
525 strcpy( value, "xxxxxxxxxx" );
526 strcpy( data, "xxxxxxxxxx" );
527 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
528 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
529 ok( val_count == 2, "val_count set to %d\n", val_count );
530 ok( data_count == 7 || broken( data_count == 8 ), "data_count set to %d instead of 7\n", data_count );
531 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
532 ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
533 ok( !strcmp( data, "xxxxxxxxxx" ), "data set to '%s'\n", data );
535 /* overflow name */
536 val_count = 3;
537 data_count = 20;
538 type = 1234;
539 strcpy( value, "xxxxxxxxxx" );
540 strcpy( data, "xxxxxxxxxx" );
541 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
542 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
543 ok( val_count == 3, "val_count set to %d\n", val_count );
544 ok( data_count == 7 || broken( data_count == 8 ), "data_count set to %d instead of 7\n", data_count );
545 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
546 /* v5.1.2600.0 (XP Home and Professional) does not touch value or data in this case */
547 ok( !strcmp( value, "Te" ) || !strcmp( value, "xxxxxxxxxx" ),
548 "value set to '%s' instead of 'Te' or 'xxxxxxxxxx'\n", value );
549 ok( !strcmp( data, "foobar" ) || !strcmp( data, "xxxxxxx" ) || broken( !strcmp( data, "xxxxxxxx" ) && data_count == 8 ),
550 "data set to '%s' instead of 'foobar' or 'xxxxxxx'\n", data );
552 /* overflow empty name */
553 val_count = 0;
554 data_count = 20;
555 type = 1234;
556 strcpy( value, "xxxxxxxxxx" );
557 strcpy( data, "xxxxxxxxxx" );
558 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
559 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
560 ok( val_count == 0, "val_count set to %d\n", val_count );
561 ok( data_count == 7 || broken( data_count == 8 ), "data_count set to %d instead of 7\n", data_count );
562 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
563 ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
564 /* v5.1.2600.0 (XP Home and Professional) does not touch data in this case */
565 ok( !strcmp( data, "foobar" ) || !strcmp( data, "xxxxxxx" ) || broken( !strcmp( data, "xxxxxxxx" ) && data_count == 8 ),
566 "data set to '%s' instead of 'foobar' or 'xxxxxxx'\n", data );
568 /* overflow data */
569 val_count = 20;
570 data_count = 2;
571 type = 1234;
572 strcpy( value, "xxxxxxxxxx" );
573 strcpy( data, "xxxxxxxxxx" );
574 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
575 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
576 ok( val_count == 20, "val_count set to %d\n", val_count );
577 ok( data_count == 7, "data_count set to %d instead of 7\n", data_count );
578 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
579 ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
580 ok( !strcmp( data, "xxxxxxxxxx" ), "data set to '%s'\n", data );
582 /* no overflow */
583 val_count = 20;
584 data_count = 20;
585 type = 1234;
586 strcpy( value, "xxxxxxxxxx" );
587 strcpy( data, "xxxxxxxxxx" );
588 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
589 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res );
590 ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
591 ok( data_count == 7, "data_count set to %d instead of 7\n", data_count );
592 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
593 ok( !strcmp( value, "Test" ), "value is '%s' instead of Test\n", value );
594 ok( !strcmp( data, "foobar" ), "data is '%s' instead of foobar\n", data );
596 if (pRegGetValueA) /* avoid a crash on Windows 2000 */
598 /* no value and no val_count parameter */
599 data_count = 20;
600 type = 1234;
601 strcpy( data, "xxxxxxxxxx" );
602 res = RegEnumValueA( test_key, 0, NULL, NULL, NULL, &type, (BYTE*)data, &data_count );
603 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
605 /* no value parameter */
606 val_count = 20;
607 data_count = 20;
608 type = 1234;
609 strcpy( data, "xxxxxxxxxx" );
610 res = RegEnumValueA( test_key, 0, NULL, &val_count, NULL, &type, (BYTE*)data, &data_count );
611 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
613 /* no val_count parameter */
614 data_count = 20;
615 type = 1234;
616 strcpy( value, "xxxxxxxxxx" );
617 strcpy( data, "xxxxxxxxxx" );
618 res = RegEnumValueA( test_key, 0, value, NULL, NULL, &type, (BYTE*)data, &data_count );
619 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
622 /* Unicode tests */
624 SetLastError(0xdeadbeef);
625 res = RegSetValueExW( test_key, testW, 0, REG_SZ, (const BYTE *)foobarW, 7*sizeof(WCHAR) );
626 if (res==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
628 win_skip("RegSetValueExW is not implemented\n");
629 goto cleanup;
631 ok( res == 0, "RegSetValueExW failed error %d\n", res );
633 /* overflow both name and data */
634 val_count = 2;
635 data_count = 2;
636 type = 1234;
637 memcpy( valueW, xxxW, sizeof(xxxW) );
638 memcpy( dataW, xxxW, sizeof(xxxW) );
639 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
640 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
641 ok( val_count == 2, "val_count set to %d\n", val_count );
642 ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
643 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
644 ok( !memcmp( valueW, xxxW, sizeof(xxxW) ), "value modified\n" );
645 ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data modified\n" );
647 /* overflow name */
648 val_count = 3;
649 data_count = 20;
650 type = 1234;
651 memcpy( valueW, xxxW, sizeof(xxxW) );
652 memcpy( dataW, xxxW, sizeof(xxxW) );
653 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
654 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
655 ok( val_count == 3, "val_count set to %d\n", val_count );
656 ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
657 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
658 ok( !memcmp( valueW, xxxW, sizeof(xxxW) ), "value modified\n" );
659 ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data modified\n" );
661 /* overflow data */
662 val_count = 20;
663 data_count = 2;
664 type = 1234;
665 memcpy( valueW, xxxW, sizeof(xxxW) );
666 memcpy( dataW, xxxW, sizeof(xxxW) );
667 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
668 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
669 ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
670 ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
671 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
672 ok( !memcmp( valueW, testW, sizeof(testW) ), "value is not 'Test'\n" );
673 ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data modified\n" );
675 /* no overflow */
676 val_count = 20;
677 data_count = 20;
678 type = 1234;
679 memcpy( valueW, xxxW, sizeof(xxxW) );
680 memcpy( dataW, xxxW, sizeof(xxxW) );
681 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
682 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res );
683 ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
684 ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
685 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
686 ok( !memcmp( valueW, testW, sizeof(testW) ), "value is not 'Test'\n" );
687 ok( !memcmp( dataW, foobarW, sizeof(foobarW) ), "data is not 'foobar'\n" );
689 if (pRegGetValueA) /* avoid a crash on Windows 2000 */
691 /* no valueW and no val_count parameter */
692 data_count = 20;
693 type = 1234;
694 memcpy( dataW, xxxW, sizeof(xxxW) );
695 res = RegEnumValueW( test_key, 0, NULL, NULL, NULL, &type, (BYTE*)dataW, &data_count );
696 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
698 /* no valueW parameter */
699 val_count = 20;
700 data_count = 20;
701 type = 1234;
702 memcpy( dataW, xxxW, sizeof(xxxW) );
703 res = RegEnumValueW( test_key, 0, NULL, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
704 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
706 /* no val_count parameter */
707 data_count = 20;
708 type = 1234;
709 memcpy( valueW, xxxW, sizeof(xxxW) );
710 memcpy( dataW, xxxW, sizeof(xxxW) );
711 res = RegEnumValueW( test_key, 0, valueW, NULL, NULL, &type, (BYTE*)dataW, &data_count );
712 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
715 cleanup:
716 RegDeleteKeyA(test_key, "");
717 RegCloseKey(test_key);
720 static void test_query_value_ex(void)
722 DWORD ret, size, type;
723 BYTE buffer[10];
725 size = sizeof(buffer);
726 ret = RegQueryValueExA(hkey_main, "TP1_SZ", NULL, &type, NULL, &size);
727 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
728 ok(size == strlen(sTestpath1) + 1, "(%d,%d)\n", (DWORD)strlen(sTestpath1) + 1, size);
729 ok(type == REG_SZ, "type %d is not REG_SZ\n", type);
731 type = 0xdeadbeef;
732 size = 0xdeadbeef;
733 ret = RegQueryValueExA(HKEY_CLASSES_ROOT, "Nonexistent Value", NULL, &type, NULL, &size);
734 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
735 ok(size == 0, "size should have been set to 0 instead of %d\n", size);
737 size = sizeof(buffer);
738 ret = RegQueryValueExA(HKEY_CLASSES_ROOT, "Nonexistent Value", NULL, &type, buffer, &size);
739 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
740 ok(size == sizeof(buffer), "size shouldn't have been changed to %d\n", size);
742 size = 4;
743 ret = RegQueryValueExA(hkey_main, "BIN32", NULL, &size, buffer, &size);
744 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
747 static void test_get_value(void)
749 DWORD ret;
750 DWORD size;
751 DWORD type;
752 DWORD dw, qw[2];
753 CHAR buf[80];
754 CHAR expanded[] = "bar\\subdir1";
755 CHAR expanded2[] = "ImARatherLongButIndeedNeededString\\subdir1";
757 if(!pRegGetValueA)
759 win_skip("RegGetValue not available on this platform\n");
760 return;
763 /* Invalid parameter */
764 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD, &type, &dw, NULL);
765 ok(ret == ERROR_INVALID_PARAMETER, "ret=%d\n", ret);
767 /* Query REG_DWORD using RRF_RT_REG_DWORD (ok) */
768 size = type = dw = 0xdeadbeef;
769 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD, &type, &dw, &size);
770 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
771 ok(size == 4, "size=%d\n", size);
772 ok(type == REG_DWORD, "type=%d\n", type);
773 ok(dw == 0x12345678, "dw=%d\n", dw);
775 /* Check RRF_SUBKEY_WOW64*KEY validation on a case without a subkey */
776 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY | RRF_SUBKEY_WOW6432KEY, NULL, NULL, NULL);
777 ok(ret == ERROR_INVALID_PARAMETER || broken(ret == ERROR_SUCCESS), /* Before Win10 */
778 "ret=%d\n", ret);
779 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY, NULL, NULL, NULL);
780 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
781 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6432KEY, NULL, NULL, NULL);
782 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
784 /* Query by subkey-name */
785 ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD, NULL, NULL, NULL);
786 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
788 /* Check RRF_SUBKEY_WOW64*KEY validation on a case with a subkey */
789 ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY | RRF_SUBKEY_WOW6432KEY, NULL, NULL, NULL);
790 ok(ret == ERROR_INVALID_PARAMETER || broken(ret == ERROR_SUCCESS), /* Before Win10 */
791 "ret=%d\n", ret);
792 ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY, NULL, NULL, NULL);
793 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
794 ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6432KEY, NULL, NULL, NULL);
795 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
797 /* Query REG_DWORD using RRF_RT_REG_BINARY (restricted) */
798 size = type = dw = 0xdeadbeef;
799 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_BINARY, &type, &dw, &size);
800 ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
801 /* Although the function failed all values are retrieved */
802 ok(size == 4, "size=%d\n", size);
803 ok(type == REG_DWORD, "type=%d\n", type);
804 ok(dw == 0x12345678, "dw=%d\n", dw);
806 /* Test RRF_ZEROONFAILURE */
807 type = dw = 0xdeadbeef; size = 4;
808 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_SZ|RRF_ZEROONFAILURE, &type, &dw, &size);
809 ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
810 /* Again all values are retrieved ... */
811 ok(size == 4, "size=%d\n", size);
812 ok(type == REG_DWORD, "type=%d\n", type);
813 /* ... except the buffer, which is zeroed out */
814 ok(dw == 0, "dw=%d\n", dw);
816 /* Test RRF_ZEROONFAILURE with a NULL buffer... */
817 type = size = 0xbadbeef;
818 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_SZ|RRF_ZEROONFAILURE, &type, NULL, &size);
819 ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
820 ok(size == 4, "size=%d\n", size);
821 ok(type == REG_DWORD, "type=%d\n", type);
823 /* Query REG_DWORD using RRF_RT_DWORD (ok) */
824 size = type = dw = 0xdeadbeef;
825 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_DWORD, &type, &dw, &size);
826 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
827 ok(size == 4, "size=%d\n", size);
828 ok(type == REG_DWORD, "type=%d\n", type);
829 ok(dw == 0x12345678, "dw=%d\n", dw);
831 /* Query 32-bit REG_BINARY using RRF_RT_DWORD (ok) */
832 size = type = dw = 0xdeadbeef;
833 ret = pRegGetValueA(hkey_main, NULL, "BIN32", RRF_RT_DWORD, &type, &dw, &size);
834 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
835 ok(size == 4, "size=%d\n", size);
836 ok(type == REG_BINARY, "type=%d\n", type);
837 ok(dw == 0x12345678, "dw=%d\n", dw);
839 /* Query 64-bit REG_BINARY using RRF_RT_DWORD (type mismatch) */
840 qw[0] = qw[1] = size = type = 0xdeadbeef;
841 ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_DWORD, &type, qw, &size);
842 ok(ret == ERROR_DATATYPE_MISMATCH, "ret=%d\n", ret);
843 ok(size == 8, "size=%d\n", size);
844 ok(type == REG_BINARY, "type=%d\n", type);
845 ok(qw[0] == 0x12345678 &&
846 qw[1] == 0x87654321, "qw={%d,%d}\n", qw[0], qw[1]);
848 /* Query 64-bit REG_BINARY using 32-bit buffer (buffer too small) */
849 type = dw = 0xdeadbeef; size = 4;
850 ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_REG_BINARY, &type, &dw, &size);
851 ok(ret == ERROR_MORE_DATA, "ret=%d\n", ret);
852 ok(dw == 0xdeadbeef, "dw=%d\n", dw);
853 ok(size == 8, "size=%d\n", size);
855 /* Query 64-bit REG_BINARY using RRF_RT_QWORD (ok) */
856 qw[0] = qw[1] = size = type = 0xdeadbeef;
857 ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_QWORD, &type, qw, &size);
858 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
859 ok(size == 8, "size=%d\n", size);
860 ok(type == REG_BINARY, "type=%d\n", type);
861 ok(qw[0] == 0x12345678 &&
862 qw[1] == 0x87654321, "qw={%d,%d}\n", qw[0], qw[1]);
864 /* Query REG_SZ using RRF_RT_REG_SZ (ok) */
865 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
866 ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ, &type, buf, &size);
867 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
868 ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
869 ok(type == REG_SZ, "type=%d\n", type);
870 ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
872 /* Query REG_SZ using RRF_RT_REG_SZ and no buffer (ok) */
873 type = 0xdeadbeef; size = 0;
874 ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ, &type, NULL, &size);
875 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
876 /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
877 ok(size == strlen(sTestpath1)+1 || broken(size == strlen(sTestpath1)+2),
878 "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
879 ok(type == REG_SZ, "type=%d\n", type);
881 /* Query REG_SZ using RRF_RT_REG_SZ on a zero-byte value (ok) */
882 strcpy(buf, sTestpath1);
883 type = 0xdeadbeef;
884 size = sizeof(buf);
885 ret = pRegGetValueA(hkey_main, NULL, "TP1_ZB_SZ", RRF_RT_REG_SZ, &type, buf, &size);
886 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
887 /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
888 ok(size == 0 ||
889 size == 1, /* win2k3 */
890 "size=%d\n", size);
891 ok(type == REG_SZ, "type=%d\n", type);
892 ok(!strcmp(sTestpath1, buf) ||
893 !strcmp(buf, ""),
894 "Expected \"%s\" or \"\", got \"%s\"\n", sTestpath1, buf);
896 /* Query REG_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (ok) */
897 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
898 ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ|RRF_NOEXPAND, &type, buf, &size);
899 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
900 ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
901 ok(type == REG_SZ, "type=%d\n", type);
902 ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
904 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ and no buffer (ok, expands) */
905 size = 0;
906 ret = pRegGetValueA(hkey_main, NULL, "TP2_EXP_SZ", RRF_RT_REG_SZ, NULL, NULL, &size);
907 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
908 ok((size == strlen(expanded2)+1) || /* win2k3 SP1 */
909 (size == strlen(expanded2)+2) || /* win2k3 SP2 */
910 (size == strlen(sTestpath2)+1),
911 "strlen(expanded2)=%d, strlen(sTestpath2)=%d, size=%d\n", lstrlenA(expanded2), lstrlenA(sTestpath2), size);
913 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ (ok, expands) */
914 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
915 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_SZ, &type, buf, &size);
916 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
917 /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath1 length + 1 here. */
918 ok(size == strlen(expanded)+1 || broken(size == strlen(sTestpath1)+1),
919 "strlen(expanded)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded), lstrlenA(sTestpath1), size);
920 ok(type == REG_SZ, "type=%d\n", type);
921 ok(!strcmp(expanded, buf), "expanded=\"%s\" buf=\"%s\"\n", expanded, buf);
923 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ (ok, expands a lot) */
924 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
925 ret = pRegGetValueA(hkey_main, NULL, "TP2_EXP_SZ", RRF_RT_REG_SZ, &type, buf, &size);
926 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
927 /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath2 length + 1 here. */
928 ok(size == strlen(expanded2)+1 || broken(size == strlen(sTestpath2)+1),
929 "strlen(expanded2)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded2), lstrlenA(sTestpath2), size);
930 ok(type == REG_SZ, "type=%d\n", type);
931 ok(!strcmp(expanded2, buf), "expanded2=\"%s\" buf=\"%s\"\n", expanded2, buf);
933 /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND (ok, doesn't expand) */
934 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
935 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND, &type, buf, &size);
936 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
937 ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
938 ok(type == REG_EXPAND_SZ, "type=%d\n", type);
939 ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
941 /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND and no buffer (ok, doesn't expand) */
942 size = 0xbadbeef;
943 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND, NULL, NULL, &size);
944 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
945 /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
946 ok(size == strlen(sTestpath1)+1 || broken(size == strlen(sTestpath1)+2),
947 "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
949 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (type mismatch) */
950 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_SZ|RRF_NOEXPAND, NULL, NULL, NULL);
951 ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
953 /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ (not allowed without RRF_NOEXPAND) */
954 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ, NULL, NULL, NULL);
955 /* before win8: ERROR_INVALID_PARAMETER, win8: ERROR_UNSUPPORTED_TYPE */
956 ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
958 /* Query REG_EXPAND_SZ using RRF_RT_ANY */
959 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
960 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_ANY, &type, buf, &size);
961 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
962 /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath1 length + 1 here. */
963 ok(size == strlen(expanded)+1 || broken(size == strlen(sTestpath1)+1),
964 "strlen(expanded)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded), lstrlenA(sTestpath1), size);
965 ok(type == REG_SZ, "type=%d\n", type);
966 ok(!strcmp(expanded, buf), "expanded=\"%s\" buf=\"%s\"\n", expanded, buf);
969 static void test_reg_open_key(void)
971 DWORD ret = 0;
972 HKEY hkResult = NULL;
973 HKEY hkPreserve = NULL;
974 HKEY hkRoot64 = NULL;
975 HKEY hkRoot32 = NULL;
976 BOOL bRet;
977 SID_IDENTIFIER_AUTHORITY sid_authority = {SECURITY_WORLD_SID_AUTHORITY};
978 PSID world_sid;
979 EXPLICIT_ACCESSA access;
980 PACL key_acl;
981 SECURITY_DESCRIPTOR *sd;
983 /* successful open */
984 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
985 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
986 ok(hkResult != NULL, "expected hkResult != NULL\n");
987 hkPreserve = hkResult;
989 /* open same key twice */
990 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
991 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
992 ok(hkResult != hkPreserve, "expected hkResult != hkPreserve\n");
993 ok(hkResult != NULL, "hkResult != NULL\n");
994 RegCloseKey(hkResult);
996 /* trailing slashes */
997 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test\\\\", &hkResult);
998 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
999 RegCloseKey(hkResult);
1001 /* open nonexistent key
1002 * check that hkResult is set to NULL
1004 hkResult = hkPreserve;
1005 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Nonexistent", &hkResult);
1006 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
1007 ok(hkResult == NULL, "expected hkResult == NULL\n");
1009 /* open the same nonexistent key again to make sure the key wasn't created */
1010 hkResult = hkPreserve;
1011 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Nonexistent", &hkResult);
1012 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
1013 ok(hkResult == NULL, "expected hkResult == NULL\n");
1015 /* send in NULL lpSubKey
1016 * check that hkResult receives the value of hKey
1018 hkResult = hkPreserve;
1019 ret = RegOpenKeyA(HKEY_CURRENT_USER, NULL, &hkResult);
1020 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1021 ok(hkResult == HKEY_CURRENT_USER, "expected hkResult == HKEY_CURRENT_USER\n");
1023 /* send empty-string in lpSubKey */
1024 hkResult = hkPreserve;
1025 ret = RegOpenKeyA(HKEY_CURRENT_USER, "", &hkResult);
1026 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1027 ok(hkResult == HKEY_CURRENT_USER, "expected hkResult == HKEY_CURRENT_USER\n");
1029 /* send in NULL lpSubKey and NULL hKey
1030 * hkResult is set to NULL
1032 hkResult = hkPreserve;
1033 ret = RegOpenKeyA(NULL, NULL, &hkResult);
1034 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1035 ok(hkResult == NULL, "expected hkResult == NULL\n");
1037 /* only send NULL hKey
1038 * the value of hkResult remains unchanged
1040 hkResult = hkPreserve;
1041 ret = RegOpenKeyA(NULL, "Software\\Wine\\Test", &hkResult);
1042 ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 95 returns BADKEY */
1043 "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
1044 ok(hkResult == hkPreserve, "expected hkResult == hkPreserve\n");
1046 /* send in NULL hkResult */
1047 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", NULL);
1048 ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", ret);
1050 ret = RegOpenKeyA(HKEY_CURRENT_USER, NULL, NULL);
1051 ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", ret);
1053 ret = RegOpenKeyA(NULL, NULL, NULL);
1054 ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", ret);
1056 /* beginning backslash character */
1057 ret = RegOpenKeyA(HKEY_CURRENT_USER, "\\Software\\Wine\\Test", &hkResult);
1058 ok(ret == ERROR_BAD_PATHNAME || /* NT/2k/XP */
1059 broken(ret == ERROR_SUCCESS), /* wow64 */
1060 "expected ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret);
1061 if (!ret) RegCloseKey(hkResult);
1063 hkResult = NULL;
1064 ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "\\clsid", 0, KEY_QUERY_VALUE, &hkResult);
1065 ok(ret == ERROR_SUCCESS || /* 2k/XP */
1066 ret == ERROR_BAD_PATHNAME, /* NT */
1067 "expected ERROR_SUCCESS, ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret);
1068 RegCloseKey(hkResult);
1070 /* NULL or empty subkey of special root */
1071 hkResult = NULL;
1072 ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, NULL, 0, KEY_QUERY_VALUE, &hkResult);
1073 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1074 ok(hkResult == HKEY_CLASSES_ROOT, "expected hkResult == HKEY_CLASSES_ROOT\n");
1076 hkResult = NULL;
1077 ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "", 0, KEY_QUERY_VALUE, &hkResult);
1078 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1079 ok(hkResult == HKEY_CLASSES_ROOT, "expected hkResult == HKEY_CLASSES_ROOT\n");
1081 hkResult = NULL;
1082 ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "\\", 0, KEY_QUERY_VALUE, &hkResult);
1083 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1084 ok(hkResult != HKEY_CLASSES_ROOT, "expected hkResult to be a new key\n");
1085 ok(!RegCloseKey(hkResult), "got invalid hkey\n");
1087 /* empty subkey of existing handle */
1088 hkResult = hkPreserve;
1089 ret = RegOpenKeyExA(hkPreserve, "", 0, KEY_QUERY_VALUE, &hkResult);
1090 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1091 ok(hkResult != hkPreserve, "expected hkResult != hkPreserve\n");
1092 ok(!RegCloseKey(hkResult), "got invalid hkey\n");
1094 /* NULL subkey of existing handle */
1095 hkResult = hkPreserve;
1096 ret = RegOpenKeyExA(hkPreserve, NULL, 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 /* empty subkey of NULL */
1102 hkResult = hkPreserve;
1103 ret = RegOpenKeyExW(NULL, L"", 0, KEY_QUERY_VALUE, &hkResult);
1104 ok(ret == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", ret);
1105 ok(hkResult == NULL || broken(hkResult == hkPreserve /* Windows XP */), "expected hkResult == NULL\n");
1107 hkResult = hkPreserve;
1108 ret = RegOpenKeyExA(NULL, "", 0, KEY_QUERY_VALUE, &hkResult);
1109 ok(ret == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", ret);
1110 ok(hkResult == hkPreserve, "expected hkResult == hkPreserve\n");
1112 RegCloseKey(hkPreserve);
1114 /* WOW64 flags */
1115 hkResult = NULL;
1116 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WOW64_32KEY, &hkResult);
1117 ok((ret == ERROR_SUCCESS && hkResult != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */),
1118 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
1119 RegCloseKey(hkResult);
1121 hkResult = NULL;
1122 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WOW64_64KEY, &hkResult);
1123 ok((ret == ERROR_SUCCESS && hkResult != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */),
1124 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
1125 RegCloseKey(hkResult);
1127 /* check special HKEYs on 64bit
1128 * only the lower 4 bytes of the supplied key are used
1130 if (ptr_size == 64)
1132 /* HKEY_CURRENT_USER */
1133 ret = RegOpenKeyA(UlongToHandle(HandleToUlong(HKEY_CURRENT_USER)), "Software", &hkResult);
1134 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1135 ok(hkResult != NULL, "expected hkResult != NULL\n");
1136 RegCloseKey(hkResult);
1138 ret = RegOpenKeyA((HKEY)(HandleToUlong(HKEY_CURRENT_USER) | (ULONG64)1 << 32), "Software", &hkResult);
1139 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1140 ok(hkResult != NULL, "expected hkResult != NULL\n");
1141 RegCloseKey(hkResult);
1143 ret = RegOpenKeyA((HKEY)(HandleToUlong(HKEY_CURRENT_USER) | (ULONG64)0xdeadbeef << 32), "Software", &hkResult);
1144 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1145 ok(hkResult != NULL, "expected hkResult != NULL\n");
1146 RegCloseKey(hkResult);
1148 ret = RegOpenKeyA((HKEY)(HandleToUlong(HKEY_CURRENT_USER) | (ULONG64)0xffffffff << 32), "Software", &hkResult);
1149 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1150 ok(hkResult != NULL, "expected hkResult != NULL\n");
1151 RegCloseKey(hkResult);
1153 /* HKEY_LOCAL_MACHINE */
1154 ret = RegOpenKeyA((HKEY)(HandleToUlong(HKEY_LOCAL_MACHINE) | (ULONG64)0xdeadbeef << 32), "Software", &hkResult);
1155 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1156 ok(hkResult != NULL, "expected hkResult != NULL\n");
1157 RegCloseKey(hkResult);
1160 /* Try using WOW64 flags when opening a key with a DACL set to verify that
1161 * the registry access check is performed correctly. Redirection isn't
1162 * being tested, so the tests don't care about whether the process is
1163 * running under WOW64. */
1164 if (!pIsWow64Process)
1166 win_skip("WOW64 flags are not recognized\n");
1167 return;
1170 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1171 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &hkRoot32, NULL);
1172 if (limited_user)
1173 ok(ret == ERROR_ACCESS_DENIED && hkRoot32 == NULL,
1174 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
1175 else
1176 ok(ret == ERROR_SUCCESS && hkRoot32 != NULL,
1177 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
1179 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1180 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &hkRoot64, NULL);
1181 if (limited_user)
1182 ok(ret == ERROR_ACCESS_DENIED && hkRoot64 == NULL,
1183 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
1184 else
1185 ok(ret == ERROR_SUCCESS && hkRoot64 != NULL,
1186 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
1188 bRet = AllocateAndInitializeSid(&sid_authority, 1, SECURITY_WORLD_RID,
1189 0, 0, 0, 0, 0, 0, 0, &world_sid);
1190 ok(bRet == TRUE,
1191 "Expected AllocateAndInitializeSid to return TRUE, got %d, last error %u\n", bRet, GetLastError());
1193 access.grfAccessPermissions = GENERIC_ALL | STANDARD_RIGHTS_ALL;
1194 access.grfAccessMode = SET_ACCESS;
1195 access.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
1196 access.Trustee.pMultipleTrustee = NULL;
1197 access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1198 access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
1199 access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
1200 access.Trustee.ptstrName = (char *)world_sid;
1202 ret = SetEntriesInAclA(1, &access, NULL, &key_acl);
1203 ok(ret == ERROR_SUCCESS,
1204 "Expected SetEntriesInAclA to return ERROR_SUCCESS, got %u, last error %u\n", ret, GetLastError());
1206 sd = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
1207 bRet = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
1208 ok(bRet == TRUE,
1209 "Expected InitializeSecurityDescriptor to return TRUE, got %d, last error %u\n", bRet, GetLastError());
1211 bRet = SetSecurityDescriptorDacl(sd, TRUE, key_acl, FALSE);
1212 ok(bRet == TRUE,
1213 "Expected SetSecurityDescriptorDacl to return TRUE, got %d, last error %u\n", bRet, GetLastError());
1215 if (limited_user)
1217 skip("not enough privileges to modify HKLM\n");
1219 else
1221 LONG error;
1223 error = RegSetKeySecurity(hkRoot64, DACL_SECURITY_INFORMATION, sd);
1224 ok(error == ERROR_SUCCESS,
1225 "Expected RegSetKeySecurity to return success, got error %u\n", error);
1227 error = RegSetKeySecurity(hkRoot32, DACL_SECURITY_INFORMATION, sd);
1228 ok(error == ERROR_SUCCESS,
1229 "Expected RegSetKeySecurity to return success, got error %u\n", error);
1231 hkResult = NULL;
1232 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_WOW64_64KEY | KEY_READ, &hkResult);
1233 ok(ret == ERROR_SUCCESS && hkResult != NULL,
1234 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
1235 RegCloseKey(hkResult);
1237 hkResult = NULL;
1238 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_WOW64_32KEY | KEY_READ, &hkResult);
1239 ok(ret == ERROR_SUCCESS && hkResult != NULL,
1240 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
1241 RegCloseKey(hkResult);
1244 HeapFree(GetProcessHeap(), 0, sd);
1245 LocalFree(key_acl);
1246 FreeSid(world_sid);
1247 RegDeleteKeyA(hkRoot64, "");
1248 RegCloseKey(hkRoot64);
1249 RegDeleteKeyA(hkRoot32, "");
1250 RegCloseKey(hkRoot32);
1253 static void test_reg_create_key(void)
1255 LONG ret;
1256 HKEY hkey1, hkey2;
1257 HKEY hkRoot64 = NULL;
1258 HKEY hkRoot32 = NULL;
1259 DWORD dwRet;
1260 BOOL bRet;
1261 SID_IDENTIFIER_AUTHORITY sid_authority = {SECURITY_WORLD_SID_AUTHORITY};
1262 PSID world_sid;
1263 EXPLICIT_ACCESSA access;
1264 PACL key_acl;
1265 SECURITY_DESCRIPTOR *sd;
1267 ret = RegCreateKeyExA(hkey_main, "Subkey1", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
1268 ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
1269 /* should succeed: all versions of Windows ignore the access rights
1270 * to the parent handle */
1271 ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey2, NULL);
1272 ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
1274 /* clean up */
1275 RegDeleteKeyA(hkey2, "");
1276 RegDeleteKeyA(hkey1, "");
1277 RegCloseKey(hkey2);
1278 RegCloseKey(hkey1);
1280 /* test creation of volatile keys */
1281 ret = RegCreateKeyExA(hkey_main, "Volatile", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey1, NULL);
1282 ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
1283 ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey2, NULL);
1284 ok(ret == ERROR_CHILD_MUST_BE_VOLATILE, "RegCreateKeyExA failed with error %d\n", ret);
1285 if (!ret) RegCloseKey( hkey2 );
1286 ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey2, NULL);
1287 ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
1288 RegCloseKey(hkey2);
1289 /* should succeed if the key already exists */
1290 ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey2, NULL);
1291 ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
1293 /* clean up */
1294 RegDeleteKeyA(hkey2, "");
1295 RegDeleteKeyA(hkey1, "");
1296 RegCloseKey(hkey2);
1297 RegCloseKey(hkey1);
1299 /* beginning backslash character */
1300 ret = RegCreateKeyExA(hkey_main, "\\Subkey3", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
1301 if (!(GetVersion() & 0x80000000))
1302 ok(ret == ERROR_BAD_PATHNAME, "expected ERROR_BAD_PATHNAME, got %d\n", ret);
1303 else {
1304 ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
1305 RegDeleteKeyA(hkey1, "");
1306 RegCloseKey(hkey1);
1309 /* trailing backslash characters */
1310 ret = RegCreateKeyExA(hkey_main, "Subkey4\\\\", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
1311 ok(ret == ERROR_SUCCESS, "RegCreateKeyExA failed with error %d\n", ret);
1312 RegDeleteKeyA(hkey1, "");
1313 RegCloseKey(hkey1);
1315 /* WOW64 flags - open an existing key */
1316 hkey1 = NULL;
1317 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0, KEY_READ|KEY_WOW64_32KEY, NULL, &hkey1, NULL);
1318 ok((ret == ERROR_SUCCESS && hkey1 != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */),
1319 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
1320 RegCloseKey(hkey1);
1322 hkey1 = NULL;
1323 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0, KEY_READ|KEY_WOW64_64KEY, NULL, &hkey1, NULL);
1324 ok((ret == ERROR_SUCCESS && hkey1 != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */),
1325 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
1326 RegCloseKey(hkey1);
1328 /* Try using WOW64 flags when opening a key with a DACL set to verify that
1329 * the registry access check is performed correctly. Redirection isn't
1330 * being tested, so the tests don't care about whether the process is
1331 * running under WOW64. */
1332 if (!pIsWow64Process)
1334 win_skip("WOW64 flags are not recognized\n");
1335 return;
1338 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1339 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &hkRoot32, NULL);
1340 if (limited_user)
1341 ok(ret == ERROR_ACCESS_DENIED && hkRoot32 == NULL,
1342 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%d)\n", ret);
1343 else
1344 ok(ret == ERROR_SUCCESS && hkRoot32 != NULL,
1345 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%d)\n", ret);
1347 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1348 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &hkRoot64, NULL);
1349 if (limited_user)
1350 ok(ret == ERROR_ACCESS_DENIED && hkRoot64 == NULL,
1351 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%d)\n", ret);
1352 else
1353 ok(ret == ERROR_SUCCESS && hkRoot64 != NULL,
1354 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%d)\n", ret);
1356 bRet = AllocateAndInitializeSid(&sid_authority, 1, SECURITY_WORLD_RID,
1357 0, 0, 0, 0, 0, 0, 0, &world_sid);
1358 ok(bRet == TRUE,
1359 "Expected AllocateAndInitializeSid to return TRUE, got %d, last error %u\n", bRet, GetLastError());
1361 access.grfAccessPermissions = GENERIC_ALL | STANDARD_RIGHTS_ALL;
1362 access.grfAccessMode = SET_ACCESS;
1363 access.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
1364 access.Trustee.pMultipleTrustee = NULL;
1365 access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1366 access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
1367 access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
1368 access.Trustee.ptstrName = (char *)world_sid;
1370 dwRet = SetEntriesInAclA(1, &access, NULL, &key_acl);
1371 ok(dwRet == ERROR_SUCCESS,
1372 "Expected SetEntriesInAclA to return ERROR_SUCCESS, got %u, last error %u\n", dwRet, GetLastError());
1374 sd = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
1375 bRet = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
1376 ok(bRet == TRUE,
1377 "Expected InitializeSecurityDescriptor to return TRUE, got %d, last error %u\n", bRet, GetLastError());
1379 bRet = SetSecurityDescriptorDacl(sd, TRUE, key_acl, FALSE);
1380 ok(bRet == TRUE,
1381 "Expected SetSecurityDescriptorDacl to return TRUE, got %d, last error %u\n", bRet, GetLastError());
1383 if (limited_user)
1385 skip("not enough privileges to modify HKLM\n");
1387 else
1389 ret = RegSetKeySecurity(hkRoot64, DACL_SECURITY_INFORMATION, sd);
1390 ok(ret == ERROR_SUCCESS,
1391 "Expected RegSetKeySecurity to return success, got error %u\n", ret);
1393 ret = RegSetKeySecurity(hkRoot32, DACL_SECURITY_INFORMATION, sd);
1394 ok(ret == ERROR_SUCCESS,
1395 "Expected RegSetKeySecurity to return success, got error %u\n", ret);
1397 hkey1 = NULL;
1398 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1399 KEY_WOW64_64KEY | KEY_READ, NULL, &hkey1, NULL);
1400 ok(ret == ERROR_SUCCESS && hkey1 != NULL,
1401 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
1402 RegCloseKey(hkey1);
1404 hkey1 = NULL;
1405 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1406 KEY_WOW64_32KEY | KEY_READ, NULL, &hkey1, NULL);
1407 ok(ret == ERROR_SUCCESS && hkey1 != NULL,
1408 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
1409 RegCloseKey(hkey1);
1412 HeapFree(GetProcessHeap(), 0, sd);
1413 LocalFree(key_acl);
1414 FreeSid(world_sid);
1415 RegDeleteKeyA(hkRoot64, "");
1416 RegCloseKey(hkRoot64);
1417 RegDeleteKeyA(hkRoot32, "");
1418 RegCloseKey(hkRoot32);
1421 static void test_reg_close_key(void)
1423 DWORD ret = 0;
1424 HKEY hkHandle;
1426 /* successfully close key
1427 * hkHandle remains changed after call to RegCloseKey
1429 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkHandle);
1430 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1431 ret = RegCloseKey(hkHandle);
1432 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1434 /* try to close the key twice */
1435 ret = RegCloseKey(hkHandle); /* Windows 95 doesn't mind. */
1436 ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_SUCCESS,
1437 "expected ERROR_INVALID_HANDLE or ERROR_SUCCESS, got %d\n", ret);
1439 /* try to close a NULL handle */
1440 ret = RegCloseKey(NULL);
1441 ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 95 returns BADKEY */
1442 "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
1444 /* Check to see if we didn't potentially close our main handle, which could happen on win98 as
1445 * win98 doesn't give a new handle when the same key is opened.
1446 * Not re-opening will make some next tests fail.
1448 if (hkey_main == hkHandle)
1450 trace("The main handle is most likely closed, so re-opening\n");
1451 RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main );
1455 static void test_reg_delete_key(void)
1457 DWORD ret;
1458 HKEY key;
1460 ret = RegDeleteKeyA(hkey_main, NULL);
1462 /* There is a bug in NT4 and W2K that doesn't check if the subkey is NULL. If
1463 * there are also no subkeys available it will delete the key pointed to by hkey_main.
1464 * Not re-creating will make some next tests fail.
1466 if (ret == ERROR_SUCCESS)
1468 trace("We are probably running on NT4 or W2K as the main key is deleted,"
1469 " re-creating the main key\n");
1470 setup_main_key();
1472 else
1473 ok(ret == ERROR_INVALID_PARAMETER ||
1474 ret == ERROR_ACCESS_DENIED ||
1475 ret == ERROR_BADKEY, /* Win95 */
1476 "ret=%d\n", ret);
1478 ret = RegCreateKeyA(hkey_main, "deleteme", &key);
1479 ok(ret == ERROR_SUCCESS, "Could not create key, got %d\n", ret);
1480 ret = RegDeleteKeyA(key, "");
1481 ok(ret == ERROR_SUCCESS, "RegDeleteKeyA failed, got %d\n", ret);
1482 RegCloseKey(key);
1483 ret = RegOpenKeyA(hkey_main, "deleteme", &key);
1484 ok(ret == ERROR_FILE_NOT_FOUND, "Key was not deleted, got %d\n", ret);
1485 RegCloseKey(key);
1488 static BOOL set_privileges(LPCSTR privilege, BOOL set)
1490 TOKEN_PRIVILEGES tp;
1491 HANDLE hToken;
1492 LUID luid;
1494 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
1495 return FALSE;
1497 if(!LookupPrivilegeValueA(NULL, privilege, &luid))
1499 CloseHandle(hToken);
1500 return FALSE;
1503 tp.PrivilegeCount = 1;
1504 tp.Privileges[0].Luid = luid;
1506 if (set)
1507 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1508 else
1509 tp.Privileges[0].Attributes = 0;
1511 AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
1512 if (GetLastError() != ERROR_SUCCESS)
1514 CloseHandle(hToken);
1515 return FALSE;
1518 CloseHandle(hToken);
1519 return TRUE;
1522 static void test_reg_save_key(void)
1524 DWORD ret;
1526 if (!set_privileges(SE_BACKUP_NAME, TRUE) ||
1527 !set_privileges(SE_RESTORE_NAME, FALSE))
1529 win_skip("Failed to set SE_BACKUP_NAME privileges, skipping tests\n");
1530 return;
1533 ret = RegSaveKeyA(hkey_main, "saved_key", NULL);
1534 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1536 set_privileges(SE_BACKUP_NAME, FALSE);
1539 static void test_reg_load_key(void)
1541 DWORD ret;
1542 HKEY hkHandle;
1544 if (!set_privileges(SE_RESTORE_NAME, TRUE) ||
1545 !set_privileges(SE_BACKUP_NAME, FALSE))
1547 win_skip("Failed to set SE_RESTORE_NAME privileges, skipping tests\n");
1548 return;
1551 ret = RegLoadKeyA(HKEY_LOCAL_MACHINE, "Test", "saved_key");
1552 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1554 set_privileges(SE_RESTORE_NAME, FALSE);
1556 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, "Test", &hkHandle);
1557 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1559 RegCloseKey(hkHandle);
1562 static void test_reg_unload_key(void)
1564 DWORD ret;
1566 if (!set_privileges(SE_RESTORE_NAME, TRUE) ||
1567 !set_privileges(SE_BACKUP_NAME, FALSE))
1569 win_skip("Failed to set SE_RESTORE_NAME privileges, skipping tests\n");
1570 return;
1573 ret = RegUnLoadKeyA(HKEY_LOCAL_MACHINE, "Test");
1574 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1576 set_privileges(SE_RESTORE_NAME, FALSE);
1578 DeleteFileA("saved_key");
1579 DeleteFileA("saved_key.LOG");
1582 /* tests that show that RegConnectRegistry and
1583 OpenSCManager accept computer names without the
1584 \\ prefix (what MSDN says). */
1585 static void test_regconnectregistry( void)
1587 CHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
1588 CHAR netwName[MAX_COMPUTERNAME_LENGTH + 3]; /* 2 chars for double backslash */
1589 DWORD len = sizeof(compName) ;
1590 BOOL ret;
1591 LONG retl;
1592 HKEY hkey;
1593 SC_HANDLE schnd;
1595 SetLastError(0xdeadbeef);
1596 ret = GetComputerNameA(compName, &len);
1597 ok( ret, "GetComputerName failed err = %d\n", GetLastError());
1598 if( !ret) return;
1600 lstrcpyA(netwName, "\\\\");
1601 lstrcpynA(netwName+2, compName, MAX_COMPUTERNAME_LENGTH + 1);
1603 retl = RegConnectRegistryA( compName, HKEY_LOCAL_MACHINE, &hkey);
1604 ok( !retl ||
1605 retl == ERROR_DLL_INIT_FAILED ||
1606 retl == ERROR_BAD_NETPATH, /* some win2k */
1607 "RegConnectRegistryA failed err = %d\n", retl);
1608 if( !retl) RegCloseKey( hkey);
1610 retl = RegConnectRegistryA( netwName, HKEY_LOCAL_MACHINE, &hkey);
1611 ok( !retl ||
1612 retl == ERROR_DLL_INIT_FAILED ||
1613 retl == ERROR_BAD_NETPATH, /* some win2k */
1614 "RegConnectRegistryA failed err = %d\n", retl);
1615 if( !retl) RegCloseKey( hkey);
1617 SetLastError(0xdeadbeef);
1618 schnd = OpenSCManagerA( compName, NULL, GENERIC_READ);
1619 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1621 win_skip("OpenSCManagerA is not implemented\n");
1622 return;
1625 ok( schnd != NULL, "OpenSCManagerA failed err = %d\n", GetLastError());
1626 CloseServiceHandle( schnd);
1628 SetLastError(0xdeadbeef);
1629 schnd = OpenSCManagerA( netwName, NULL, GENERIC_READ);
1630 ok( schnd != NULL, "OpenSCManagerA failed err = %d\n", GetLastError());
1631 CloseServiceHandle( schnd);
1635 static void test_reg_query_value(void)
1637 HKEY subkey;
1638 CHAR val[MAX_PATH];
1639 WCHAR valW[5];
1640 LONG size, ret;
1642 static const WCHAR expected[] = {'d','a','t','a',0};
1644 ret = RegCreateKeyA(hkey_main, "subkey", &subkey);
1645 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1647 ret = RegSetValueA(subkey, NULL, REG_SZ, "data", 4);
1648 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1650 /* try an invalid hkey */
1651 SetLastError(0xdeadbeef);
1652 size = MAX_PATH;
1653 ret = RegQueryValueA((HKEY)0xcafebabe, "subkey", val, &size);
1654 ok(ret == ERROR_INVALID_HANDLE ||
1655 ret == ERROR_BADKEY || /* Windows 98 returns BADKEY */
1656 ret == ERROR_ACCESS_DENIED, /* non-admin winxp */
1657 "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
1658 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1660 /* try a NULL hkey */
1661 SetLastError(0xdeadbeef);
1662 size = MAX_PATH;
1663 ret = RegQueryValueA(NULL, "subkey", val, &size);
1664 ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 98 returns BADKEY */
1665 "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
1666 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1668 /* try a NULL value */
1669 size = MAX_PATH;
1670 ret = RegQueryValueA(hkey_main, "subkey", NULL, &size);
1671 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1672 ok(size == 5, "Expected 5, got %d\n", size);
1674 /* try a NULL size */
1675 SetLastError(0xdeadbeef);
1676 val[0] = '\0';
1677 ret = RegQueryValueA(hkey_main, "subkey", val, NULL);
1678 ok(ret == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", ret);
1679 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1680 ok(!val[0], "Expected val to be untouched, got %s\n", val);
1682 /* try a NULL value and size */
1683 ret = RegQueryValueA(hkey_main, "subkey", NULL, NULL);
1684 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1686 /* try a size too small */
1687 SetLastError(0xdeadbeef);
1688 val[0] = '\0';
1689 size = 1;
1690 ret = RegQueryValueA(hkey_main, "subkey", val, &size);
1691 ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret);
1692 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1693 ok(!val[0], "Expected val to be untouched, got %s\n", val);
1694 ok(size == 5, "Expected 5, got %d\n", size);
1696 /* successfully read the value using 'subkey' */
1697 size = MAX_PATH;
1698 ret = RegQueryValueA(hkey_main, "subkey", val, &size);
1699 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1700 ok(!lstrcmpA(val, "data"), "Expected 'data', got '%s'\n", val);
1701 ok(size == 5, "Expected 5, got %d\n", size);
1703 /* successfully read the value using the subkey key */
1704 size = MAX_PATH;
1705 ret = RegQueryValueA(subkey, NULL, val, &size);
1706 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1707 ok(!lstrcmpA(val, "data"), "Expected 'data', got '%s'\n", val);
1708 ok(size == 5, "Expected 5, got %d\n", size);
1710 /* unicode - try size too small */
1711 SetLastError(0xdeadbeef);
1712 valW[0] = '\0';
1713 size = 0;
1714 ret = RegQueryValueW(subkey, NULL, valW, &size);
1715 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1717 win_skip("RegQueryValueW is not implemented\n");
1718 goto cleanup;
1720 ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret);
1721 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1722 ok(!valW[0], "Expected valW to be untouched\n");
1723 ok(size == sizeof(expected), "Got wrong size: %d\n", size);
1725 /* unicode - try size in WCHARS */
1726 SetLastError(0xdeadbeef);
1727 size = ARRAY_SIZE(valW);
1728 ret = RegQueryValueW(subkey, NULL, valW, &size);
1729 ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret);
1730 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1731 ok(!valW[0], "Expected valW to be untouched\n");
1732 ok(size == sizeof(expected), "Got wrong size: %d\n", size);
1734 /* unicode - successfully read the value */
1735 size = sizeof(valW);
1736 ret = RegQueryValueW(subkey, NULL, valW, &size);
1737 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1738 ok(!lstrcmpW(valW, expected), "Got wrong value\n");
1739 ok(size == sizeof(expected), "Got wrong size: %d\n", size);
1741 /* unicode - set the value without a NULL terminator */
1742 ret = RegSetValueW(subkey, NULL, REG_SZ, expected, sizeof(expected)-sizeof(WCHAR));
1743 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1745 /* unicode - read the unterminated value, value is terminated for us */
1746 memset(valW, 'a', sizeof(valW));
1747 size = sizeof(valW);
1748 ret = RegQueryValueW(subkey, NULL, valW, &size);
1749 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1750 ok(!lstrcmpW(valW, expected), "Got wrong value\n");
1751 ok(size == sizeof(expected), "Got wrong size: %d\n", size);
1753 cleanup:
1754 RegDeleteKeyA(subkey, "");
1755 RegCloseKey(subkey);
1758 static void test_reg_query_info(void)
1760 HKEY subkey;
1761 HKEY subsubkey;
1762 LONG ret;
1763 char classbuffer[32];
1764 WCHAR classbufferW[32];
1765 char expectbuffer[32];
1766 WCHAR expectbufferW[32];
1767 char subkey_class[] = "subkey class";
1768 WCHAR subkey_classW[] = {'s','u','b','k','e','y',' ','c','l','a','s','s',0};
1769 char subsubkey_class[] = "subsubkey class";
1770 DWORD classlen;
1771 DWORD subkeys, maxsubkeylen, maxclasslen;
1772 DWORD values, maxvaluenamelen, maxvaluelen;
1773 DWORD sdlen;
1774 FILETIME lastwrite;
1776 ret = RegCreateKeyExA(hkey_main, "subkey", 0, subkey_class, 0, KEY_ALL_ACCESS, NULL, &subkey, NULL);
1777 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1779 /* all parameters NULL */
1780 ret = RegQueryInfoKeyA(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1781 ok(ret == ERROR_INVALID_HANDLE, "ret = %d\n", ret);
1783 ret = RegQueryInfoKeyW(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1784 ok(ret == ERROR_INVALID_HANDLE, "ret = %d\n", ret);
1786 /* not requesting any information */
1787 ret = RegQueryInfoKeyA(subkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1788 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1790 ret = RegQueryInfoKeyW(subkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1791 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1793 /* class without length is invalid */
1794 memset(classbuffer, 0x55, sizeof(classbuffer));
1795 ret = RegQueryInfoKeyA(subkey, classbuffer, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1796 ok(ret == ERROR_INVALID_PARAMETER, "ret = %d\n", ret);
1797 ok(classbuffer[0] == 0x55, "classbuffer[0] = 0x%x\n", classbuffer[0]);
1799 memset(classbufferW, 0x55, sizeof(classbufferW));
1800 ret = RegQueryInfoKeyW(subkey, classbufferW, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1801 ok(ret == ERROR_INVALID_PARAMETER, "ret = %d\n", ret);
1802 ok(classbufferW[0] == 0x5555, "classbufferW[0] = 0x%x\n", classbufferW[0]);
1804 /* empty key */
1805 sdlen = classlen =0;
1806 ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1807 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1808 ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
1809 ok(subkeys == 0, "subkeys = %u\n", subkeys);
1810 ok(maxsubkeylen == 0, "maxsubkeylen = %u\n", maxsubkeylen);
1811 ok(maxclasslen == 0, "maxclasslen = %u\n", maxclasslen);
1812 ok(values == 0, "values = %u\n", values);
1813 ok(maxvaluenamelen == 0, "maxvaluenamelen = %u\n", maxvaluenamelen);
1814 ok(maxvaluelen == 0, "maxvaluelen = %u\n", maxvaluelen);
1815 todo_wine ok(sdlen != 0, "sdlen = %u\n", sdlen);
1816 ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
1817 ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
1819 sdlen = classlen = 0;
1820 ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1821 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1822 ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
1823 ok(subkeys == 0, "subkeys = %u\n", subkeys);
1824 ok(maxsubkeylen == 0, "maxsubkeylen = %u\n", maxsubkeylen);
1825 ok(maxclasslen == 0, "maxclasslen = %u\n", maxclasslen);
1826 ok(values == 0, "values = %u\n", values);
1827 ok(maxvaluenamelen == 0, "maxvaluenamelen = %u\n", maxvaluenamelen);
1828 ok(maxvaluelen == 0, "maxvaluelen = %u\n", maxvaluelen);
1829 todo_wine ok(sdlen != 0, "sdlen = %u\n", sdlen);
1830 ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
1831 ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
1833 ret = RegCreateKeyExA(subkey, "subsubkey", 0, subsubkey_class, 0, KEY_ALL_ACCESS, NULL, &subsubkey, NULL);
1834 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1836 ret = RegSetValueExA(subkey, NULL, 0, REG_SZ, (const BYTE*)"data", 5);
1837 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1839 /* with subkey & default value */
1840 sdlen = classlen = 0;
1841 ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1842 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1843 ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
1844 ok(subkeys == 1, "subkeys = %u\n", subkeys);
1845 ok(maxsubkeylen == strlen("subsubkey"), "maxsubkeylen = %u\n", maxsubkeylen);
1846 ok(maxclasslen == strlen(subsubkey_class), "maxclasslen = %u\n", maxclasslen);
1847 ok(values == 1, "values = %u\n", values);
1848 ok(maxvaluenamelen == 0, "maxvaluenamelen = %u\n", maxvaluenamelen);
1849 ok(maxvaluelen == sizeof("data") * sizeof(WCHAR), "maxvaluelen = %u\n", maxvaluelen);
1850 todo_wine ok(sdlen != 0, "sdlen = %u\n", sdlen);
1851 ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
1852 ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
1854 sdlen = classlen = 0;
1855 ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1856 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1857 ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
1858 ok(subkeys == 1, "subkeys = %u\n", subkeys);
1859 ok(maxsubkeylen == strlen("subsubkey"), "maxsubkeylen = %u\n", maxsubkeylen);
1860 ok(maxclasslen == strlen(subsubkey_class), "maxclasslen = %u\n", maxclasslen);
1861 ok(values == 1, "values = %u\n", values);
1862 ok(maxvaluenamelen == 0, "maxvaluenamelen = %u\n", maxvaluenamelen);
1863 ok(maxvaluelen == sizeof("data") * sizeof(WCHAR), "maxvaluelen = %u\n", maxvaluelen);
1864 todo_wine ok(sdlen != 0, "sdlen = %u\n", sdlen);
1865 ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
1866 ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
1868 ret = RegSetValueExA(subkey, "value one", 0, REG_SZ, (const BYTE*)"first value data", 17);
1869 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1871 ret = RegSetValueExA(subkey, "value 2", 0, REG_SZ, (const BYTE*)"second value data", 18);
1872 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1874 /* with named value */
1875 classlen = 0;
1876 ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1877 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1878 ok(values == 3, "values = %u\n", values);
1879 ok(maxvaluenamelen == strlen("value one"), "maxvaluenamelen = %u\n", maxvaluenamelen);
1880 ok(maxvaluelen == sizeof("second value data") * sizeof(WCHAR), "maxvaluelen = %u\n", maxvaluelen);
1882 classlen = 0;
1883 ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1884 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1885 ok(values == 3, "values = %u\n", values);
1886 ok(maxvaluenamelen == strlen("value one"), "maxvaluenamelen = %u\n", maxvaluenamelen);
1887 ok(maxvaluelen == sizeof("second value data") * sizeof(WCHAR), "maxvaluelen = %u\n", maxvaluelen);
1889 /* class name with zero size buffer */
1890 memset(classbuffer, 0x55, sizeof(classbuffer));
1891 classlen = 0;
1892 ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1893 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1894 ok(classlen == strlen(subkey_class) /* win2k */ ||
1895 classlen == 0, "classlen = %u\n", classlen);
1896 memset(expectbuffer, 0x55, sizeof(expectbuffer));
1897 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)), "classbuffer was modified\n");
1899 memset(classbufferW, 0x55, sizeof(classbufferW));
1900 classlen = 0;
1901 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1902 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1903 ok(classlen == strlen(subkey_class) /* win2k */ ||
1904 classlen == 0, "classlen = %u\n", classlen);
1905 memset(expectbufferW, 0x55, sizeof(expectbufferW));
1906 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)), "classbufferW was modified\n");
1908 /* class name with one char buffer */
1909 memset(classbuffer, 0x55, sizeof(classbuffer));
1910 classlen = 1;
1911 ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1912 ok(ret == ERROR_MORE_DATA, "ret = %d\n", ret);
1913 ok(classlen == 0, "classlen = %u\n", classlen);
1914 memset(expectbuffer, 0x55, sizeof(expectbuffer));
1915 expectbuffer[0] = 0;
1916 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)), "classbuffer was modified\n");
1918 memset(classbufferW, 0x55, sizeof(classbufferW));
1919 classlen = 1;
1920 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1921 /* failure-code changed to ERROR_MORE_DATA in recent win10 */
1922 ok((ret == ERROR_INSUFFICIENT_BUFFER) || (ret == ERROR_MORE_DATA), "ret = %d\n", ret);
1923 ok(classlen == 0 /* win8 */ ||
1924 classlen == strlen(subkey_class), "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 buffer one char too small */
1929 memset(classbuffer, 0x55, sizeof(classbuffer));
1930 classlen = sizeof(subkey_class) - 1;
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 == sizeof(subkey_class) - 2, "classlen = %u\n", classlen);
1934 memset(expectbuffer, 0x55, sizeof(expectbuffer));
1935 strcpy(expectbuffer, subkey_class);
1936 expectbuffer[sizeof(subkey_class) - 2] = 0;
1937 expectbuffer[sizeof(subkey_class) - 1] = 0x55;
1938 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)),
1939 "classbuffer = %.*s, expected %s\n",
1940 (int)sizeof(classbuffer), classbuffer, expectbuffer);
1942 memset(classbufferW, 0x55, sizeof(classbufferW));
1943 classlen = sizeof(subkey_class) - 1;
1944 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1945 ok(ret == ERROR_INSUFFICIENT_BUFFER, "ret = %d\n", ret);
1946 ok(classlen == sizeof(subkey_class) - 2 /* win8 */ ||
1947 classlen == strlen(subkey_class), "classlen = %u\n", classlen);
1948 memset(expectbufferW, 0x55, sizeof(expectbufferW));
1949 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)), "classbufferW was modified\n");
1951 /* class name with large enough buffer */
1952 memset(classbuffer, 0x55, sizeof(classbuffer));
1953 classlen = sizeof(subkey_class);
1954 ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1955 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1956 ok(classlen == sizeof(subkey_class) - 1, "classlen = %u\n", classlen);
1957 memset(expectbuffer, 0x55, sizeof(expectbuffer));
1958 strcpy(expectbuffer, subkey_class);
1959 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)),
1960 "classbuffer = \"%.*s\", expected %s\n",
1961 (int)sizeof(classbuffer), classbuffer, expectbuffer);
1963 memset(classbuffer, 0x55, sizeof(classbuffer));
1964 classlen = 0xdeadbeef;
1965 ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1966 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1967 ok(classlen == sizeof(subkey_class) - 1, "classlen = %u\n", classlen);
1968 memset(expectbuffer, 0x55, sizeof(expectbuffer));
1969 strcpy(expectbuffer, subkey_class);
1970 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)),
1971 "classbuffer = \"%.*s\", expected %s\n",
1972 (int)sizeof(classbuffer), classbuffer, expectbuffer);
1974 memset(classbufferW, 0x55, sizeof(classbufferW));
1975 classlen = sizeof(subkey_class);
1976 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1977 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1978 ok(classlen == sizeof(subkey_class) - 1, "classlen = %u\n", classlen);
1979 memset(expectbufferW, 0x55, sizeof(expectbufferW));
1980 lstrcpyW(expectbufferW, subkey_classW);
1981 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)),
1982 "classbufferW = %s, expected %s\n",
1983 wine_dbgstr_wn(classbufferW, ARRAY_SIZE(classbufferW)), wine_dbgstr_w(expectbufferW));
1985 memset(classbufferW, 0x55, sizeof(classbufferW));
1986 classlen = 0xdeadbeef;
1987 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1988 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1989 ok(classlen == sizeof(subkey_class) - 1, "classlen = %u\n", classlen);
1990 memset(expectbufferW, 0x55, sizeof(expectbufferW));
1991 lstrcpyW(expectbufferW, subkey_classW);
1992 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)),
1993 "classbufferW = %s, expected %s\n",
1994 wine_dbgstr_wn(classbufferW, ARRAY_SIZE(classbufferW)), wine_dbgstr_w(expectbufferW));
1996 RegDeleteKeyA(subsubkey, "");
1997 RegCloseKey(subsubkey);
1998 RegDeleteKeyA(subkey, "");
1999 RegCloseKey(subkey);
2002 static void test_string_termination(void)
2004 HKEY subkey;
2005 LSTATUS ret;
2006 static const char string[] = "FullString";
2007 char name[11];
2008 BYTE buffer[11];
2009 DWORD insize, outsize, nsize;
2011 ret = RegCreateKeyA(hkey_main, "string_termination", &subkey);
2012 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2014 /* Off-by-one RegSetValueExA -> adds a trailing '\0'! */
2015 insize=sizeof(string)-1;
2016 ret = RegSetValueExA(subkey, "stringtest", 0, REG_SZ, (BYTE*)string, insize);
2017 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", ret);
2018 outsize=insize;
2019 ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
2020 ok(ret == ERROR_MORE_DATA, "RegQueryValueExA returned: %d\n", ret);
2022 /* Off-by-two RegSetValueExA -> no trailing '\0' */
2023 insize=sizeof(string)-2;
2024 ret = RegSetValueExA(subkey, "stringtest", 0, REG_SZ, (BYTE*)string, insize);
2025 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", ret);
2026 outsize=0;
2027 ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, NULL, &outsize);
2028 ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
2029 ok(outsize == insize, "wrong size %u != %u\n", outsize, insize);
2031 /* RegQueryValueExA may return a string with no trailing '\0' */
2032 outsize=insize;
2033 memset(buffer, 0xbd, sizeof(buffer));
2034 ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
2035 ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
2036 ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
2037 ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
2038 debugstr_an((char*)buffer, outsize), outsize, string);
2039 ok(buffer[insize] == 0xbd, "buffer overflow at %u %02x\n", insize, buffer[insize]);
2041 /* RegQueryValueExA adds a trailing '\0' if there is room */
2042 outsize=insize+1;
2043 memset(buffer, 0xbd, sizeof(buffer));
2044 ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
2045 ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
2046 ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
2047 ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
2048 debugstr_an((char*)buffer, outsize), outsize, string);
2049 ok(buffer[insize] == 0, "buffer overflow at %u %02x\n", insize, buffer[insize]);
2051 /* RegEnumValueA may return a string with no trailing '\0' */
2052 outsize=insize;
2053 memset(buffer, 0xbd, sizeof(buffer));
2054 nsize=sizeof(name);
2055 ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize);
2056 ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", ret);
2057 ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name);
2058 ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
2059 ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
2060 debugstr_an((char*)buffer, outsize), outsize, string);
2061 ok(buffer[insize] == 0xbd, "buffer overflow at %u %02x\n", insize, buffer[insize]);
2063 /* RegEnumValueA adds a trailing '\0' if there is room */
2064 outsize=insize+1;
2065 memset(buffer, 0xbd, sizeof(buffer));
2066 nsize=sizeof(name);
2067 ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize);
2068 ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", ret);
2069 ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name);
2070 ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
2071 ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
2072 debugstr_an((char*)buffer, outsize), outsize, string);
2073 ok(buffer[insize] == 0, "buffer overflow at %u %02x\n", insize, buffer[insize]);
2075 RegDeleteKeyA(subkey, "");
2076 RegCloseKey(subkey);
2079 static void test_reg_copy_tree(void)
2081 HKEY src, dst, subkey;
2082 CHAR buffer[MAX_PATH];
2083 DWORD dwsize, type;
2084 LONG size, ret;
2086 if (!pRegCopyTreeA)
2088 win_skip("Skipping RegCopyTreeA tests, function not present\n");
2089 return;
2092 ret = RegCreateKeyA(hkey_main, "src", &src);
2093 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2094 ret = RegCreateKeyA(hkey_main, "dst", &dst);
2095 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2097 /* Copy nonexistent subkey */
2098 ret = pRegCopyTreeA(src, "nonexistent_subkey", dst);
2099 ok(ret == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
2101 /* Create test keys and values */
2102 ret = RegSetValueA(src, NULL, REG_SZ, "data", 4);
2103 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2104 ret = RegSetValueExA(src, "value", 0, REG_SZ, (const BYTE *)"data2", 5);
2105 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2107 ret = RegCreateKeyA(src, "subkey2", &subkey);
2108 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2109 ret = RegSetValueA(subkey, NULL, REG_SZ, "data3", 5);
2110 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2111 ret = RegSetValueExA(subkey, "value", 0, REG_SZ, (const BYTE *)"data4", 5);
2112 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2113 ret = RegCloseKey(subkey);
2114 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2116 ret = RegCreateKeyA(src, "subkey3", &subkey);
2117 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2118 ret = RegCloseKey(subkey);
2119 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2121 /* Copy subkey */
2122 ret = pRegCopyTreeA(src, "subkey2", dst);
2123 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2125 size = MAX_PATH;
2126 ret = RegQueryValueA(dst, NULL, buffer, &size);
2127 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2128 ok(!strcmp(buffer, "data3"), "Expected 'data3', got '%s'\n", buffer);
2130 dwsize = MAX_PATH;
2131 ret = RegQueryValueExA(dst, "value", NULL, &type, (BYTE *)buffer, &dwsize);
2132 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2133 ok(type == REG_SZ, "Expected REG_SZ, got %u\n", type);
2134 ok(!strcmp(buffer, "data4"), "Expected 'data4', got '%s'\n", buffer);
2136 /* Copy full tree */
2137 ret = pRegCopyTreeA(src, NULL, dst);
2138 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2140 size = MAX_PATH;
2141 ret = RegQueryValueA(dst, NULL, buffer, &size);
2142 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2143 ok(!strcmp(buffer, "data"), "Expected 'data', got '%s'\n", buffer);
2145 dwsize = MAX_PATH;
2146 ret = RegQueryValueExA(dst, "value", NULL, &type, (BYTE *)buffer, &dwsize);
2147 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2148 ok(type == REG_SZ, "Expected REG_SZ, got %u\n", type);
2149 ok(!strcmp(buffer, "data2"), "Expected 'data2', got '%s'\n", buffer);
2151 ret = RegOpenKeyA(dst, "subkey2", &subkey);
2152 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2153 size = MAX_PATH;
2154 ret = RegQueryValueA(subkey, NULL, buffer, &size);
2155 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2156 ok(!strcmp(buffer, "data3"), "Expected 'data3', got '%s'\n", buffer);
2157 dwsize = MAX_PATH;
2158 ret = RegQueryValueExA(subkey, "value", NULL, &type, (BYTE *)buffer, &dwsize);
2159 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2160 ok(type == REG_SZ, "Expected REG_SZ, got %u\n", type);
2161 ok(!strcmp(buffer, "data4"), "Expected 'data4', got '%s'\n", buffer);
2162 ret = RegCloseKey(subkey);
2163 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2165 ret = RegOpenKeyA(dst, "subkey3", &subkey);
2166 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2167 ret = RegCloseKey(subkey);
2168 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2170 delete_key(src);
2171 delete_key(dst);
2174 static void test_reg_delete_tree(void)
2176 CHAR buffer[MAX_PATH];
2177 HKEY subkey, subkey2;
2178 DWORD dwsize, type;
2179 LONG size, ret;
2181 if(!pRegDeleteTreeA) {
2182 win_skip("Skipping RegDeleteTreeA tests, function not present\n");
2183 return;
2186 ret = RegCreateKeyA(hkey_main, "subkey", &subkey);
2187 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2188 ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
2189 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2190 ret = RegSetValueA(subkey, NULL, REG_SZ, "data", 4);
2191 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2192 ret = RegSetValueA(subkey2, NULL, REG_SZ, "data2", 5);
2193 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2194 ret = RegCloseKey(subkey2);
2195 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2197 ret = pRegDeleteTreeA(subkey, "subkey2");
2198 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2199 ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
2200 "subkey2 was not deleted\n");
2201 size = MAX_PATH;
2202 ok(!RegQueryValueA(subkey, NULL, buffer, &size),
2203 "Default value of subkey no longer present\n");
2205 ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
2206 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2207 ret = RegCloseKey(subkey2);
2208 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2209 ret = pRegDeleteTreeA(hkey_main, "subkey\\subkey2");
2210 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2211 ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
2212 "subkey2 was not deleted\n");
2213 ok(!RegQueryValueA(subkey, NULL, buffer, &size),
2214 "Default value of subkey no longer present\n");
2216 ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
2217 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2218 ret = RegCloseKey(subkey2);
2219 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2220 ret = RegCreateKeyA(subkey, "subkey3", &subkey2);
2221 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2222 ret = RegCloseKey(subkey2);
2223 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2224 ret = RegSetValueA(subkey, NULL, REG_SZ, "data", 4);
2225 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2226 ret = RegSetValueExA(subkey, "value", 0, REG_SZ, (const BYTE *)"data2", 5);
2227 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2228 ret = pRegDeleteTreeA(subkey, NULL);
2229 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2230 ok(!RegOpenKeyA(hkey_main, "subkey", &subkey),
2231 "subkey was deleted\n");
2232 ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
2233 "subkey2 was not deleted\n");
2234 ok(RegOpenKeyA(subkey, "subkey3", &subkey2),
2235 "subkey3 was not deleted\n");
2236 size = MAX_PATH;
2237 ret = RegQueryValueA(subkey, NULL, buffer, &size);
2238 ok(ret == ERROR_SUCCESS,
2239 "Default value of subkey is not present\n");
2240 ok(!buffer[0], "Expected length 0 got length %u(%s)\n", lstrlenA(buffer), buffer);
2241 dwsize = MAX_PATH;
2242 ok(RegQueryValueExA(subkey, "value", NULL, &type, (BYTE *)buffer, &dwsize),
2243 "Value is still present\n");
2244 ret = RegCloseKey(subkey);
2245 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2247 ret = RegOpenKeyA(hkey_main, "subkey", &subkey);
2248 ok(ret == ERROR_SUCCESS, "subkey was deleted\n");
2249 ret = pRegDeleteTreeA(subkey, "");
2250 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2251 ret = RegCloseKey(subkey);
2252 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2254 ret = RegOpenKeyA(hkey_main, "subkey", &subkey);
2255 ok(ret == ERROR_SUCCESS, "subkey was deleted\n");
2256 ret = RegCloseKey(subkey);
2257 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2259 ret = pRegDeleteTreeA(hkey_main, "not-here");
2260 ok(ret == ERROR_FILE_NOT_FOUND,
2261 "Expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
2264 static void test_rw_order(void)
2266 HKEY hKey;
2267 DWORD dw = 0;
2268 static const char keyname[] = "test_rw_order";
2269 char value_buf[2];
2270 DWORD values, value_len, value_name_max_len;
2271 LSTATUS ret;
2273 RegDeleteKeyA(HKEY_CURRENT_USER, keyname);
2274 ret = RegCreateKeyA(HKEY_CURRENT_USER, keyname, &hKey);
2275 if(ret != ERROR_SUCCESS) {
2276 skip("Couldn't create key. Skipping.\n");
2277 return;
2280 ok(!RegSetValueExA(hKey, "A", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)),
2281 "RegSetValueExA for value \"A\" failed\n");
2282 ok(!RegSetValueExA(hKey, "C", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)),
2283 "RegSetValueExA for value \"C\" failed\n");
2284 ok(!RegSetValueExA(hKey, "D", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)),
2285 "RegSetValueExA for value \"D\" failed\n");
2286 ok(!RegSetValueExA(hKey, "B", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)),
2287 "RegSetValueExA for value \"B\" failed\n");
2289 ok(!RegQueryInfoKeyA(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &values,
2290 &value_name_max_len, NULL, NULL, NULL), "RegQueryInfoKeyA failed\n");
2291 ok(values == 4, "Expected 4 values, got %u\n", values);
2293 /* Value enumeration preserves RegSetValueEx call order */
2294 value_len = 2;
2295 ok(!RegEnumValueA(hKey, 0, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n");
2296 ok(strcmp(value_buf, "A") == 0, "Expected name \"A\", got %s\n", value_buf);
2297 value_len = 2;
2298 ok(!RegEnumValueA(hKey, 1, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n");
2299 todo_wine ok(strcmp(value_buf, "C") == 0, "Expected name \"C\", got %s\n", value_buf);
2300 value_len = 2;
2301 ok(!RegEnumValueA(hKey, 2, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n");
2302 todo_wine ok(strcmp(value_buf, "D") == 0, "Expected name \"D\", got %s\n", value_buf);
2303 value_len = 2;
2304 ok(!RegEnumValueA(hKey, 3, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n");
2305 todo_wine ok(strcmp(value_buf, "B") == 0, "Expected name \"B\", got %s\n", value_buf);
2307 ok(!RegDeleteKeyA(HKEY_CURRENT_USER, keyname), "Failed to delete key\n");
2310 static void test_symlinks(void)
2312 static const WCHAR targetW[] = {'\\','S','o','f','t','w','a','r','e','\\','W','i','n','e',
2313 '\\','T','e','s','t','\\','t','a','r','g','e','t',0};
2314 BYTE buffer[1024];
2315 UNICODE_STRING target_str;
2316 WCHAR *target;
2317 HKEY key, link;
2318 NTSTATUS status;
2319 DWORD target_len, type, len, dw, err;
2321 if (!pRtlFormatCurrentUserKeyPath || !pNtDeleteKey)
2323 win_skip( "Can't perform symlink tests\n" );
2324 return;
2327 pRtlFormatCurrentUserKeyPath( &target_str );
2329 target_len = target_str.Length + sizeof(targetW);
2330 target = HeapAlloc( GetProcessHeap(), 0, target_len );
2331 memcpy( target, target_str.Buffer, target_str.Length );
2332 memcpy( target + target_str.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
2334 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, REG_OPTION_CREATE_LINK,
2335 KEY_ALL_ACCESS, NULL, &link, NULL );
2336 ok( err == ERROR_SUCCESS, "RegCreateKeyEx failed: %u\n", err );
2338 /* REG_SZ is not allowed */
2339 err = RegSetValueExA( link, "SymbolicLinkValue", 0, REG_SZ, (BYTE *)"foobar", sizeof("foobar") );
2340 ok( err == ERROR_ACCESS_DENIED, "RegSetValueEx wrong error %u\n", err );
2341 err = RegSetValueExA( link, "SymbolicLinkValue", 0, REG_LINK,
2342 (BYTE *)target, target_len - sizeof(WCHAR) );
2343 ok( err == ERROR_SUCCESS, "RegSetValueEx failed error %u\n", err );
2344 /* other values are not allowed */
2345 err = RegSetValueExA( link, "link", 0, REG_LINK, (BYTE *)target, target_len - sizeof(WCHAR) );
2346 ok( err == ERROR_ACCESS_DENIED, "RegSetValueEx wrong error %u\n", err );
2348 /* try opening the target through the link */
2350 err = RegOpenKeyA( hkey_main, "link", &key );
2351 ok( err == ERROR_FILE_NOT_FOUND, "RegOpenKey wrong error %u\n", err );
2353 err = RegCreateKeyExA( hkey_main, "target", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key, NULL );
2354 ok( err == ERROR_SUCCESS, "RegCreateKeyEx failed error %u\n", err );
2356 dw = 0xbeef;
2357 err = RegSetValueExA( key, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2358 ok( err == ERROR_SUCCESS, "RegSetValueEx failed error %u\n", err );
2359 RegCloseKey( key );
2361 err = RegOpenKeyA( hkey_main, "link", &key );
2362 ok( err == ERROR_SUCCESS, "RegOpenKey failed error %u\n", err );
2364 len = sizeof(buffer);
2365 err = RegQueryValueExA( key, "value", NULL, &type, buffer, &len );
2366 ok( err == ERROR_SUCCESS, "RegOpenKey failed error %u\n", err );
2367 ok( len == sizeof(DWORD), "wrong len %u\n", len );
2369 len = sizeof(buffer);
2370 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2371 ok( err == ERROR_FILE_NOT_FOUND, "RegQueryValueEx wrong error %u\n", err );
2373 /* REG_LINK can be created in non-link keys */
2374 err = RegSetValueExA( key, "SymbolicLinkValue", 0, REG_LINK,
2375 (BYTE *)target, target_len - sizeof(WCHAR) );
2376 ok( err == ERROR_SUCCESS, "RegSetValueEx failed error %u\n", err );
2377 len = sizeof(buffer);
2378 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2379 ok( err == ERROR_SUCCESS, "RegQueryValueEx failed error %u\n", err );
2380 ok( len == target_len - sizeof(WCHAR), "wrong len %u\n", len );
2381 err = RegDeleteValueA( key, "SymbolicLinkValue" );
2382 ok( err == ERROR_SUCCESS, "RegDeleteValue failed error %u\n", err );
2384 RegCloseKey( key );
2386 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key, NULL );
2387 ok( err == ERROR_SUCCESS, "RegCreateKeyEx failed error %u\n", err );
2389 len = sizeof(buffer);
2390 err = RegQueryValueExA( key, "value", NULL, &type, buffer, &len );
2391 ok( err == ERROR_SUCCESS, "RegQueryValueEx failed error %u\n", err );
2392 ok( len == sizeof(DWORD), "wrong len %u\n", len );
2394 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2395 ok( err == ERROR_FILE_NOT_FOUND, "RegQueryValueEx wrong error %u\n", err );
2396 RegCloseKey( key );
2398 /* now open the symlink itself */
2400 err = RegOpenKeyExA( hkey_main, "link", REG_OPTION_OPEN_LINK, KEY_ALL_ACCESS, &key );
2401 ok( err == ERROR_SUCCESS, "RegOpenKeyEx failed error %u\n", err );
2402 len = sizeof(buffer);
2403 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2404 ok( err == ERROR_SUCCESS, "RegQueryValueEx failed error %u\n", err );
2405 ok( len == target_len - sizeof(WCHAR), "wrong len %u\n", len );
2406 RegCloseKey( key );
2408 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, REG_OPTION_OPEN_LINK,
2409 KEY_ALL_ACCESS, NULL, &key, NULL );
2410 ok( err == ERROR_SUCCESS, "RegCreateKeyEx failed error %u\n", err );
2411 len = sizeof(buffer);
2412 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2413 ok( err == ERROR_SUCCESS, "RegQueryValueEx failed error %u\n", err );
2414 ok( len == target_len - sizeof(WCHAR), "wrong len %u\n", len );
2415 RegCloseKey( key );
2417 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, REG_OPTION_CREATE_LINK,
2418 KEY_ALL_ACCESS, NULL, &key, NULL );
2419 ok( err == ERROR_ALREADY_EXISTS, "RegCreateKeyEx wrong error %u\n", err );
2421 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, REG_OPTION_CREATE_LINK | REG_OPTION_OPEN_LINK,
2422 KEY_ALL_ACCESS, NULL, &key, NULL );
2423 ok( err == ERROR_ALREADY_EXISTS, "RegCreateKeyEx wrong error %u\n", err );
2425 err = RegDeleteKeyA( hkey_main, "target" );
2426 ok( err == ERROR_SUCCESS, "RegDeleteKey failed error %u\n", err );
2428 err = RegDeleteKeyA( hkey_main, "link" );
2429 ok( err == ERROR_FILE_NOT_FOUND, "RegDeleteKey wrong error %u\n", err );
2431 status = pNtDeleteKey( link );
2432 ok( !status, "NtDeleteKey failed: 0x%08x\n", status );
2433 RegCloseKey( link );
2435 HeapFree( GetProcessHeap(), 0, target );
2436 pRtlFreeUnicodeString( &target_str );
2439 static DWORD get_key_value( HKEY root, const char *name, DWORD flags )
2441 HKEY key;
2442 DWORD err, type, dw, len = sizeof(dw);
2444 err = RegCreateKeyExA( root, name, 0, NULL, 0, flags | KEY_ALL_ACCESS, NULL, &key, NULL );
2445 if (err == ERROR_FILE_NOT_FOUND) return 0;
2446 ok( err == ERROR_SUCCESS, "%08x: RegCreateKeyEx failed: %u\n", flags, err );
2448 err = RegQueryValueExA( key, "value", NULL, &type, (BYTE *)&dw, &len );
2449 if (err == ERROR_FILE_NOT_FOUND)
2450 dw = 0;
2451 else
2452 ok( err == ERROR_SUCCESS, "%08x: RegQueryValueEx failed: %u\n", flags, err );
2453 RegCloseKey( key );
2454 return dw;
2457 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
2459 DWORD dw = get_key_value( root, name, flags );
2460 ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect );
2462 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
2464 static void test_redirection(void)
2466 DWORD err, type, dw, len;
2467 HKEY key, root32, root64, key32, key64, native, op_key;
2468 BOOL is_vista = FALSE;
2469 REGSAM opposite = (sizeof(void*) == 8 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY);
2471 if (ptr_size != 64)
2473 BOOL is_wow64;
2474 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 ) || !is_wow64)
2476 skip( "Not on Wow64, no redirection\n" );
2477 return;
2481 if (limited_user)
2483 skip("not enough privileges to modify HKLM\n");
2484 return;
2487 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2488 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &root64, NULL );
2489 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2491 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2492 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &root32, NULL );
2493 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2495 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", 0, NULL, 0,
2496 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key64, NULL );
2497 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2499 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", 0, NULL, 0,
2500 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key32, NULL );
2501 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2503 dw = 64;
2504 err = RegSetValueExA( key64, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2505 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %u\n", err );
2507 dw = 32;
2508 err = RegSetValueExA( key32, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2509 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %u\n", err );
2511 dw = 0;
2512 len = sizeof(dw);
2513 err = RegQueryValueExA( key32, "value", NULL, &type, (BYTE *)&dw, &len );
2514 ok( err == ERROR_SUCCESS, "RegQueryValueExA failed: %u\n", err );
2515 ok( dw == 32, "wrong value %u\n", dw );
2517 dw = 0;
2518 len = sizeof(dw);
2519 err = RegQueryValueExA( key64, "value", NULL, &type, (BYTE *)&dw, &len );
2520 ok( err == ERROR_SUCCESS, "RegQueryValueExA failed: %u\n", err );
2521 ok( dw == 64, "wrong value %u\n", dw );
2523 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
2524 KEY_ALL_ACCESS, NULL, &key, NULL );
2525 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2527 if (ptr_size == 32)
2529 /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
2530 /* the new (and simpler) Win7 mechanism doesn't */
2531 if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
2533 trace( "using Vista-style Wow6432Node handling\n" );
2534 is_vista = TRUE;
2536 check_key_value( key, "Wine\\Winetest", 0, 32 );
2537 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2538 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2539 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
2540 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
2541 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
2543 else
2545 if (get_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY ) == 64)
2547 trace( "using Vista-style Wow6432Node handling\n" );
2548 is_vista = TRUE;
2550 check_key_value( key, "Wine\\Winetest", 0, 64 );
2551 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
2553 RegCloseKey( key );
2555 if (ptr_size == 32)
2557 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
2558 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2559 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2560 dw = get_key_value( key, "Wine\\Winetest", 0 );
2561 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
2562 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
2563 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2564 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
2565 dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY );
2566 ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw );
2567 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2568 RegCloseKey( key );
2570 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
2571 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2572 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2573 check_key_value( key, "Wine\\Winetest", 0, 32 );
2574 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2575 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2576 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
2577 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
2578 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
2579 RegCloseKey( key );
2581 else
2583 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
2584 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2585 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2586 check_key_value( key, "Wine\\Winetest", 0, 64 );
2587 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
2588 dw = get_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY );
2589 todo_wine ok( dw == 32, "wrong value %u\n", dw );
2590 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
2591 RegCloseKey( key );
2593 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
2594 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2595 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2596 check_key_value( key, "Wine\\Winetest", 0, 32 );
2597 dw = get_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY );
2598 ok( dw == 32 || broken(dw == 64) /* vista */, "wrong value %u\n", dw );
2599 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2600 RegCloseKey( key );
2603 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", 0, ptr_size );
2604 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
2605 if (ptr_size == 64)
2607 /* KEY_WOW64 flags have no effect on 64-bit */
2608 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
2609 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2610 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2611 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2613 else
2615 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
2616 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2617 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2618 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2621 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node", 0, NULL, 0,
2622 KEY_ALL_ACCESS, NULL, &key, NULL );
2623 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2624 check_key_value( key, "Wine\\Winetest", 0, 32 );
2625 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2626 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2627 RegCloseKey( key );
2629 if (ptr_size == 32)
2631 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node", 0, NULL, 0,
2632 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2633 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2634 dw = get_key_value( key, "Wine\\Winetest", 0 );
2635 ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
2636 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2637 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2638 RegCloseKey( key );
2640 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node", 0, NULL, 0,
2641 KEY_WOW64_32KEY | 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 );
2646 RegCloseKey( key );
2649 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine", 0, NULL, 0,
2650 KEY_ALL_ACCESS, NULL, &key, NULL );
2651 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2652 check_key_value( key, "Winetest", 0, 32 );
2653 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2654 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
2655 RegCloseKey( key );
2657 if (ptr_size == 32)
2659 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine", 0, NULL, 0,
2660 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2661 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2662 dw = get_key_value( key, "Winetest", 0 );
2663 ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw );
2664 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2665 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
2666 RegCloseKey( key );
2668 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine", 0, NULL, 0,
2669 KEY_WOW64_32KEY | 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 );
2674 RegCloseKey( key );
2677 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2678 KEY_ALL_ACCESS, NULL, &key, NULL );
2679 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2680 check_key_value( key, "Winetest", 0, ptr_size );
2681 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
2682 dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
2683 todo_wine_if (ptr_size != 32)
2684 ok( dw == 32, "wrong value %u\n", dw );
2685 RegCloseKey( key );
2687 if (ptr_size == 32)
2689 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2690 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2691 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2692 dw = get_key_value( key, "Winetest", 0 );
2693 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
2694 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
2695 dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
2696 todo_wine ok( dw == 32, "wrong value %u\n", dw );
2697 RegCloseKey( key );
2699 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2700 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2701 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2702 check_key_value( key, "Winetest", 0, 32 );
2703 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2704 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
2705 RegCloseKey( key );
2708 if (pRegDeleteKeyExA)
2710 err = pRegDeleteKeyExA( key32, "", KEY_WOW64_32KEY, 0 );
2711 ok( err == ERROR_SUCCESS, "RegDeleteKey failed: %u\n", err );
2712 err = pRegDeleteKeyExA( key64, "", KEY_WOW64_64KEY, 0 );
2713 ok( err == ERROR_SUCCESS, "RegDeleteKey failed: %u\n", err );
2714 pRegDeleteKeyExA( key64, "", KEY_WOW64_64KEY, 0 );
2715 pRegDeleteKeyExA( root64, "", KEY_WOW64_64KEY, 0 );
2717 else
2719 err = RegDeleteKeyA( key32, "" );
2720 ok( err == ERROR_SUCCESS, "RegDeleteKey failed: %u\n", err );
2721 err = RegDeleteKeyA( key64, "" );
2722 ok( err == ERROR_SUCCESS, "RegDeleteKey failed: %u\n", err );
2723 RegDeleteKeyA( key64, "" );
2724 RegDeleteKeyA( root64, "" );
2726 RegCloseKey( key32 );
2727 RegCloseKey( key64 );
2728 RegCloseKey( root32 );
2729 RegCloseKey( root64 );
2731 /* open key in native bit mode */
2732 err = RegOpenKeyExA(HKEY_CLASSES_ROOT, "Interface", 0, KEY_ALL_ACCESS, &native);
2733 ok(err == ERROR_SUCCESS, "got %i\n", err);
2735 pRegDeleteKeyExA(native, "AWineTest", 0, 0);
2737 /* write subkey in opposite bit mode */
2738 err = RegOpenKeyExA(HKEY_CLASSES_ROOT, "Interface", 0, KEY_ALL_ACCESS | opposite, &op_key);
2739 ok(err == ERROR_SUCCESS, "got %i\n", err);
2741 err = RegCreateKeyExA(op_key, "AWineTest", 0, NULL, 0, KEY_ALL_ACCESS | opposite,
2742 NULL, &key, NULL);
2743 ok(err == ERROR_SUCCESS || err == ERROR_ACCESS_DENIED, "got %i\n", err);
2744 if(err != ERROR_SUCCESS){
2745 win_skip("Can't write to registry\n");
2746 RegCloseKey(op_key);
2747 RegCloseKey(native);
2748 return;
2750 RegCloseKey(key);
2752 /* verify subkey is not present in native mode */
2753 err = RegOpenKeyExA(native, "AWineTest", 0, KEY_ALL_ACCESS, &key);
2754 ok(err == ERROR_FILE_NOT_FOUND ||
2755 broken(err == ERROR_SUCCESS), /* before Win7, HKCR is reflected instead of redirected */
2756 "got %i\n", err);
2758 err = pRegDeleteKeyExA(op_key, "AWineTest", opposite, 0);
2759 ok(err == ERROR_SUCCESS, "got %i\n", err);
2761 RegCloseKey(op_key);
2762 RegCloseKey(native);
2765 static void test_classesroot(void)
2767 HKEY hkey, hklm, hkcr, hkeysub1, hklmsub1, hkcrsub1, hklmsub2, hkcrsub2;
2768 DWORD size = 8;
2769 DWORD type = REG_SZ;
2770 static CHAR buffer[8];
2771 LONG res;
2773 /* create a key in the user's classes */
2774 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", &hkey ))
2776 delete_key( hkey );
2777 RegCloseKey( hkey );
2779 res = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", 0, NULL, 0,
2780 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkey, NULL );
2781 if (res == ERROR_ACCESS_DENIED)
2783 skip("not enough privileges to add a user class\n");
2784 return;
2786 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
2788 /* try to open that key in hkcr */
2789 res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "WineTestCls", 0,
2790 KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
2791 todo_wine ok(res == ERROR_SUCCESS ||
2792 broken(res == ERROR_FILE_NOT_FOUND /* WinNT */),
2793 "test key not found in hkcr: %d\n", res);
2794 if (res)
2796 skip("HKCR key merging not supported\n");
2797 delete_key( hkey );
2798 RegCloseKey( hkey );
2799 return;
2802 todo_wine ok(IS_HKCR(hkcr), "hkcr mask not set in %p\n", hkcr);
2804 /* set a value in user's classes */
2805 res = RegSetValueExA(hkey, "val1", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
2806 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2808 /* try to find the value in hkcr */
2809 res = RegQueryValueExA(hkcr, "val1", NULL, &type, (LPBYTE)buffer, &size);
2810 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2811 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2813 /* modify the value in hkcr */
2814 res = RegSetValueExA(hkcr, "val1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
2815 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2817 /* check if the value is also modified in user's classes */
2818 res = RegQueryValueExA(hkey, "val1", NULL, &type, (LPBYTE)buffer, &size);
2819 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2820 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
2822 /* set a value in hkcr */
2823 res = RegSetValueExA(hkcr, "val0", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
2824 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2826 /* try to find the value in user's classes */
2827 res = RegQueryValueExA(hkey, "val0", NULL, &type, (LPBYTE)buffer, &size);
2828 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2829 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
2831 /* modify the value in user's classes */
2832 res = RegSetValueExA(hkey, "val0", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
2833 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2835 /* check if the value is also modified in hkcr */
2836 res = RegQueryValueExA(hkcr, "val0", NULL, &type, (LPBYTE)buffer, &size);
2837 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2838 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2840 /* cleanup */
2841 delete_key( hkey );
2842 delete_key( hkcr );
2843 RegCloseKey( hkey );
2844 RegCloseKey( hkcr );
2846 /* create a key in the hklm classes */
2847 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", &hklm ))
2849 delete_key( hklm );
2850 RegCloseKey( hklm );
2852 res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", 0, NULL, REG_OPTION_NON_VOLATILE,
2853 KEY_ALL_ACCESS, NULL, &hklm, NULL );
2854 if (res == ERROR_ACCESS_DENIED)
2856 skip("not enough privileges to add a system class\n");
2857 return;
2859 ok(!IS_HKCR(hklm), "hkcr mask set in %p\n", hklm);
2861 /* try to open that key in hkcr */
2862 res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "WineTestCls", 0,
2863 KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
2864 ok(res == ERROR_SUCCESS,
2865 "test key not found in hkcr: %d\n", res);
2866 ok(IS_HKCR(hkcr), "hkcr mask not set in %p\n", hkcr);
2867 if (res)
2869 delete_key( hklm );
2870 RegCloseKey( hklm );
2871 return;
2874 /* set a value in hklm classes */
2875 res = RegSetValueExA(hklm, "val2", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
2876 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2878 /* try to find the value in hkcr */
2879 res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
2880 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2881 ok(!strcmp( buffer, "hklm" ), "value set to '%s'\n", buffer );
2883 /* modify the value in hkcr */
2884 res = RegSetValueExA(hkcr, "val2", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
2885 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2887 /* check that the value is modified in hklm classes */
2888 res = RegQueryValueExA(hklm, "val2", NULL, &type, (LPBYTE)buffer, &size);
2889 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2890 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
2892 if (RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", 0, NULL, 0,
2893 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkey, NULL )) return;
2894 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
2896 /* try to open that key in hkcr */
2897 res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "WineTestCls", 0,
2898 KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
2899 ok(res == ERROR_SUCCESS,
2900 "test key not found in hkcr: %d\n", res);
2901 ok(IS_HKCR(hkcr), "hkcr mask not set in %p\n", hkcr);
2903 /* set a value in user's classes */
2904 res = RegSetValueExA(hkey, "val2", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
2905 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2907 /* try to find the value in hkcr */
2908 res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
2909 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2910 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2912 /* modify the value in hklm */
2913 res = RegSetValueExA(hklm, "val2", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
2914 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2916 /* check that the value is not overwritten in hkcr or user's classes */
2917 res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
2918 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2919 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2920 res = RegQueryValueExA(hkey, "val2", NULL, &type, (LPBYTE)buffer, &size);
2921 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2922 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2924 /* modify the value in hkcr */
2925 res = RegSetValueExA(hkcr, "val2", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
2926 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2928 /* check that the value is overwritten in hklm and user's classes */
2929 res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
2930 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2931 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
2932 res = RegQueryValueExA(hkey, "val2", NULL, &type, (LPBYTE)buffer, &size);
2933 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2934 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
2936 /* create a subkey in hklm */
2937 if (RegCreateKeyExA( hklm, "subkey1", 0, NULL, 0,
2938 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hklmsub1, NULL )) return;
2939 ok(!IS_HKCR(hklmsub1), "hkcr mask set in %p\n", hklmsub1);
2940 /* try to open that subkey in hkcr */
2941 res = RegOpenKeyExA( hkcr, "subkey1", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcrsub1 );
2942 ok(res == ERROR_SUCCESS, "test key not found in hkcr: %d\n", res);
2943 ok(IS_HKCR(hkcrsub1), "hkcr mask not set in %p\n", hkcrsub1);
2945 /* set a value in hklm classes */
2946 res = RegSetValueExA(hklmsub1, "subval1", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
2947 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2949 /* try to find the value in hkcr */
2950 res = RegQueryValueExA(hkcrsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
2951 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2952 ok(!strcmp( buffer, "hklm" ), "value set to '%s'\n", buffer );
2954 /* modify the value in hkcr */
2955 res = RegSetValueExA(hkcrsub1, "subval1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
2956 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2958 /* check that the value is modified in hklm classes */
2959 res = RegQueryValueExA(hklmsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
2960 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2961 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
2963 /* create a subkey in user's classes */
2964 if (RegCreateKeyExA( hkey, "subkey1", 0, NULL, 0,
2965 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkeysub1, NULL )) return;
2966 ok(!IS_HKCR(hkeysub1), "hkcr mask set in %p\n", hkeysub1);
2968 /* set a value in user's classes */
2969 res = RegSetValueExA(hkeysub1, "subval1", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
2970 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2972 /* try to find the value in hkcr */
2973 res = RegQueryValueExA(hkcrsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
2974 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2975 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2977 /* modify the value in hklm */
2978 res = RegSetValueExA(hklmsub1, "subval1", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
2979 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2981 /* check that the value is not overwritten in hkcr or user's classes */
2982 res = RegQueryValueExA(hkcrsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
2983 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2984 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2985 res = RegQueryValueExA(hkeysub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
2986 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2987 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2989 /* modify the value in hkcr */
2990 res = RegSetValueExA(hkcrsub1, "subval1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
2991 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2993 /* check that the value is not overwritten in hklm, but in user's classes */
2994 res = RegQueryValueExA(hklmsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
2995 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2996 ok(!strcmp( buffer, "hklm" ), "value set to '%s'\n", buffer );
2997 res = RegQueryValueExA(hkeysub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
2998 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2999 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
3001 /* new subkey in hkcr */
3002 if (RegCreateKeyExA( hkcr, "subkey2", 0, NULL, 0,
3003 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkcrsub2, NULL )) return;
3004 ok(IS_HKCR(hkcrsub2), "hkcr mask not set in %p\n", hkcrsub2);
3005 res = RegSetValueExA(hkcrsub2, "subval1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
3006 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
3008 /* try to open that new subkey in user's classes and hklm */
3009 res = RegOpenKeyExA( hkey, "subkey2", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hklmsub2 );
3010 ok(res != ERROR_SUCCESS, "test key found in user's classes: %d\n", res);
3011 hklmsub2 = 0;
3012 res = RegOpenKeyExA( hklm, "subkey2", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hklmsub2 );
3013 ok(res == ERROR_SUCCESS, "test key not found in hklm: %d\n", res);
3014 ok(!IS_HKCR(hklmsub2), "hkcr mask set in %p\n", hklmsub2);
3016 /* check that the value is present in hklm */
3017 res = RegQueryValueExA(hklmsub2, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3018 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
3019 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
3021 /* cleanup */
3022 RegCloseKey( hkeysub1 );
3023 RegCloseKey( hklmsub1 );
3025 /* delete subkey1 from hkcr (should point at user's classes) */
3026 res = RegDeleteKeyA(hkcr, "subkey1");
3027 ok(res == ERROR_SUCCESS, "RegDeleteKey failed: %d\n", res);
3029 /* confirm key was removed in hkey but not hklm */
3030 res = RegOpenKeyExA(hkey, "subkey1", 0, KEY_READ, &hkeysub1);
3031 ok(res == ERROR_FILE_NOT_FOUND, "test key found in user's classes: %d\n", res);
3032 res = RegOpenKeyExA(hklm, "subkey1", 0, KEY_READ, &hklmsub1);
3033 ok(res == ERROR_SUCCESS, "test key not found in hklm: %d\n", res);
3034 ok(!IS_HKCR(hklmsub1), "hkcr mask set in %p\n", hklmsub1);
3036 /* delete subkey1 from hkcr again (which should now point at hklm) */
3037 res = RegDeleteKeyA(hkcr, "subkey1");
3038 ok(res == ERROR_SUCCESS, "RegDeleteKey failed: %d\n", res);
3040 /* confirm hkey was removed in hklm */
3041 RegCloseKey( hklmsub1 );
3042 res = RegOpenKeyExA(hklm, "subkey1", 0, KEY_READ, &hklmsub1);
3043 ok(res == ERROR_FILE_NOT_FOUND, "test key found in hklm: %d\n", res);
3045 /* final cleanup */
3046 delete_key( hkey );
3047 delete_key( hklm );
3048 delete_key( hkcr );
3049 delete_key( hkeysub1 );
3050 delete_key( hklmsub1 );
3051 delete_key( hkcrsub1 );
3052 delete_key( hklmsub2 );
3053 delete_key( hkcrsub2 );
3054 RegCloseKey( hkey );
3055 RegCloseKey( hklm );
3056 RegCloseKey( hkcr );
3057 RegCloseKey( hkeysub1 );
3058 RegCloseKey( hklmsub1 );
3059 RegCloseKey( hkcrsub1 );
3060 RegCloseKey( hklmsub2 );
3061 RegCloseKey( hkcrsub2 );
3064 static void test_classesroot_enum(void)
3066 HKEY hkcu=0, hklm=0, hkcr=0, hkcusub[2]={0}, hklmsub[2]={0};
3067 DWORD size;
3068 static CHAR buffer[2];
3069 LONG res;
3071 /* prepare initial testing env in HKCU */
3072 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", &hkcu ))
3074 delete_key( hkcu );
3075 RegCloseKey( hkcu );
3077 res = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", 0, NULL, 0,
3078 KEY_SET_VALUE|KEY_ENUMERATE_SUB_KEYS, NULL, &hkcu, NULL );
3080 if (res != ERROR_SUCCESS)
3082 skip("failed to add a user class\n");
3083 return;
3086 res = RegOpenKeyA( HKEY_CLASSES_ROOT, "WineTestCls", &hkcr );
3087 todo_wine ok(res == ERROR_SUCCESS ||
3088 broken(res == ERROR_FILE_NOT_FOUND /* WinNT */),
3089 "test key not found in hkcr: %d\n", res);
3090 if (res)
3092 skip("HKCR key merging not supported\n");
3093 delete_key( hkcu );
3094 RegCloseKey( hkcu );
3095 return;
3098 res = RegSetValueExA( hkcu, "X", 0, REG_SZ, (const BYTE *) "AA", 3 );
3099 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", res);
3100 res = RegSetValueExA( hkcu, "Y", 0, REG_SZ, (const BYTE *) "B", 2 );
3101 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", res);
3102 res = RegCreateKeyA( hkcu, "A", &hkcusub[0] );
3103 ok(res == ERROR_SUCCESS, "RegCreateKeyA failed: %d\n", res);
3104 res = RegCreateKeyA( hkcu, "B", &hkcusub[1] );
3105 ok(res == ERROR_SUCCESS, "RegCreateKeyA failed: %d\n", res);
3107 /* test on values in HKCU */
3108 size = sizeof(buffer);
3109 res = RegEnumValueA( hkcr, 0, buffer, &size, NULL, NULL, NULL, NULL );
3110 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3111 ok(!strcmp( buffer, "X" ), "expected 'X', got '%s'\n", buffer);
3112 size = sizeof(buffer);
3113 res = RegEnumValueA( hkcr, 1, buffer, &size, NULL, NULL, NULL, NULL );
3114 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3115 ok(!strcmp( buffer, "Y" ), "expected 'Y', got '%s'\n", buffer);
3116 size = sizeof(buffer);
3117 res = RegEnumValueA( hkcr, 2, buffer, &size, NULL, NULL, NULL, NULL );
3118 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
3120 res = RegEnumKeyA( hkcr, 0, buffer, size );
3121 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3122 ok(!strcmp( buffer, "A" ), "expected 'A', got '%s'\n", buffer);
3123 res = RegEnumKeyA( hkcr, 1, buffer, size );
3124 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3125 ok(!strcmp( buffer, "B" ), "expected 'B', got '%s'\n", buffer);
3126 res = RegEnumKeyA( hkcr, 2, buffer, size );
3127 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
3129 /* prepare test env in HKLM */
3130 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", &hklm ))
3132 delete_key( hklm );
3133 RegCloseKey( hklm );
3136 res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", 0, NULL, 0,
3137 KEY_SET_VALUE|KEY_ENUMERATE_SUB_KEYS, NULL, &hklm, NULL );
3139 if (res == ERROR_ACCESS_DENIED)
3141 RegCloseKey( hkcusub[0] );
3142 RegCloseKey( hkcusub[1] );
3143 delete_key( hkcu );
3144 RegCloseKey( hkcu );
3145 RegCloseKey( hkcr );
3146 skip("not enough privileges to add a system class\n");
3147 return;
3150 res = RegSetValueExA( hklm, "X", 0, REG_SZ, (const BYTE *) "AB", 3 );
3151 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", res);
3152 res = RegSetValueExA( hklm, "Z", 0, REG_SZ, (const BYTE *) "C", 2 );
3153 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", res);
3154 res = RegCreateKeyA( hklm, "A", &hklmsub[0] );
3155 ok(res == ERROR_SUCCESS, "RegCreateKeyA failed: %d\n", res);
3156 res = RegCreateKeyA( hklm, "C", &hklmsub[1] );
3157 ok(res == ERROR_SUCCESS, "RegCreateKeyA failed: %d\n", res);
3159 /* test on values/keys in both HKCU and HKLM */
3160 size = sizeof(buffer);
3161 res = RegEnumValueA( hkcr, 0, buffer, &size, NULL, NULL, NULL, NULL );
3162 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3163 ok(!strcmp( buffer, "X" ), "expected 'X', got '%s'\n", buffer);
3164 size = sizeof(buffer);
3165 res = RegEnumValueA( hkcr, 1, buffer, &size, NULL, NULL, NULL, NULL );
3166 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3167 ok(!strcmp( buffer, "Y" ), "expected 'Y', got '%s'\n", buffer);
3168 size = sizeof(buffer);
3169 res = RegEnumValueA( hkcr, 2, buffer, &size, NULL, NULL, NULL, NULL );
3170 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3171 ok(!strcmp( buffer, "Z" ), "expected 'Z', got '%s'\n", buffer);
3172 size = sizeof(buffer);
3173 res = RegEnumValueA( hkcr, 3, buffer, &size, NULL, NULL, NULL, NULL );
3174 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
3176 res = RegEnumKeyA( hkcr, 0, buffer, size );
3177 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3178 ok(!strcmp( buffer, "A" ), "expected 'A', got '%s'\n", buffer);
3179 res = RegEnumKeyA( hkcr, 1, buffer, size );
3180 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3181 ok(!strcmp( buffer, "B" ), "expected 'B', got '%s'\n", buffer);
3182 res = RegEnumKeyA( hkcr, 2, buffer, size );
3183 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3184 ok(!strcmp( buffer, "C" ), "expected 'C', got '%s'\n", buffer);
3185 res = RegEnumKeyA( hkcr, 3, buffer, size );
3186 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
3188 /* delete values/keys from HKCU to test only on HKLM */
3189 RegCloseKey( hkcusub[0] );
3190 RegCloseKey( hkcusub[1] );
3191 delete_key( hkcu );
3192 RegCloseKey( hkcu );
3194 size = sizeof(buffer);
3195 res = RegEnumValueA( hkcr, 0, buffer, &size, NULL, NULL, NULL, NULL );
3196 ok(res == ERROR_KEY_DELETED ||
3197 res == ERROR_NO_SYSTEM_RESOURCES, /* Windows XP */
3198 "expected ERROR_KEY_DELETED, got %d\n", res);
3199 size = sizeof(buffer);
3200 res = RegEnumKeyA( hkcr, 0, buffer, size );
3201 ok(res == ERROR_KEY_DELETED ||
3202 res == ERROR_NO_SYSTEM_RESOURCES, /* Windows XP */
3203 "expected ERROR_KEY_DELETED, got %d\n", res);
3205 /* reopen HKCR handle */
3206 RegCloseKey( hkcr );
3207 res = RegOpenKeyA( HKEY_CLASSES_ROOT, "WineTestCls", &hkcr );
3208 ok(res == ERROR_SUCCESS, "test key not found in hkcr: %d\n", res);
3209 if (res) goto cleanup;
3211 /* test on values/keys in HKLM */
3212 size = sizeof(buffer);
3213 res = RegEnumValueA( hkcr, 0, buffer, &size, NULL, NULL, NULL, NULL );
3214 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3215 ok(!strcmp( buffer, "X" ), "expected 'X', got '%s'\n", buffer);
3216 size = sizeof(buffer);
3217 res = RegEnumValueA( hkcr, 1, buffer, &size, NULL, NULL, NULL, NULL );
3218 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3219 ok(!strcmp( buffer, "Z" ), "expected 'Z', got '%s'\n", buffer);
3220 size = sizeof(buffer);
3221 res = RegEnumValueA( hkcr, 2, buffer, &size, NULL, NULL, NULL, NULL );
3222 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
3224 res = RegEnumKeyA( hkcr, 0, buffer, size );
3225 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3226 ok(!strcmp( buffer, "A" ), "expected 'A', got '%s'\n", buffer);
3227 res = RegEnumKeyA( hkcr, 1, buffer, size );
3228 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3229 ok(!strcmp( buffer, "C" ), "expected 'C', got '%s'\n", buffer);
3230 res = RegEnumKeyA( hkcr, 2, buffer, size );
3231 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
3233 cleanup:
3234 RegCloseKey( hklmsub[0] );
3235 RegCloseKey( hklmsub[1] );
3236 delete_key( hklm );
3237 RegCloseKey( hklm );
3238 RegCloseKey( hkcr );
3241 static void test_classesroot_mask(void)
3243 HKEY hkey;
3244 LSTATUS res;
3246 res = RegOpenKeyA( HKEY_CLASSES_ROOT, "CLSID", &hkey );
3247 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %d\n", res);
3248 todo_wine ok(IS_HKCR(hkey) || broken(!IS_HKCR(hkey)) /* WinNT */,
3249 "hkcr mask not set in %p\n", hkey);
3250 RegCloseKey( hkey );
3252 res = RegOpenKeyA( HKEY_CURRENT_USER, "Software", &hkey );
3253 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %d\n", res);
3254 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3255 RegCloseKey( hkey );
3257 res = RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software", &hkey );
3258 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %d\n", res);
3259 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3260 RegCloseKey( hkey );
3262 res = RegOpenKeyA( HKEY_USERS, ".Default", &hkey );
3263 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %d\n", res);
3264 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3265 RegCloseKey( hkey );
3267 res = RegOpenKeyA( HKEY_CURRENT_CONFIG, "Software", &hkey );
3268 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %d\n", res);
3269 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3270 RegCloseKey( hkey );
3273 static void test_deleted_key(void)
3275 HKEY hkey, hkey2;
3276 char value[20];
3277 DWORD val_count, type;
3278 LONG res;
3280 /* Open the test key, then delete it while it's open */
3281 RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey );
3283 delete_key( hkey_main );
3285 val_count = sizeof(value);
3286 type = 0;
3287 res = RegEnumValueA( hkey, 0, value, &val_count, NULL, &type, 0, 0 );
3288 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3290 res = RegEnumKeyA( hkey, 0, value, sizeof(value) );
3291 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3293 val_count = sizeof(value);
3294 type = 0;
3295 res = RegQueryValueExA( hkey, "test", NULL, &type, (BYTE *)value, &val_count );
3296 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3298 res = RegSetValueExA( hkey, "test", 0, REG_SZ, (const BYTE*)"value", 6);
3299 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3301 res = RegOpenKeyA( hkey, "test", &hkey2 );
3302 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3303 if (res == 0)
3304 RegCloseKey( hkey2 );
3306 res = RegCreateKeyA( hkey, "test", &hkey2 );
3307 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3308 if (res == 0)
3309 RegCloseKey( hkey2 );
3311 res = RegFlushKey( hkey );
3312 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3314 RegCloseKey( hkey );
3316 setup_main_key();
3319 static void test_delete_value(void)
3321 LONG res;
3322 char longname[401];
3324 res = RegSetValueExA( hkey_main, "test", 0, REG_SZ, (const BYTE*)"value", 6 );
3325 ok(res == ERROR_SUCCESS, "expect ERROR_SUCCESS, got %i\n", res);
3327 res = RegQueryValueExA( hkey_main, "test", NULL, NULL, NULL, NULL);
3328 ok(res == ERROR_SUCCESS, "expect ERROR_SUCCESS, got %i\n", res);
3330 res = RegDeleteValueA( hkey_main, "test" );
3331 ok(res == ERROR_SUCCESS, "expect ERROR_SUCCESS, got %i\n", res);
3333 res = RegQueryValueExA( hkey_main, "test", NULL, NULL, NULL, NULL);
3334 ok(res == ERROR_FILE_NOT_FOUND, "expect ERROR_FILE_NOT_FOUND, got %i\n", res);
3336 res = RegDeleteValueA( hkey_main, "test" );
3337 ok(res == ERROR_FILE_NOT_FOUND, "expect ERROR_FILE_NOT_FOUND, got %i\n", res);
3339 memset(longname, 'a', 400);
3340 longname[400] = 0;
3341 res = RegDeleteValueA( hkey_main, longname );
3342 ok(res == ERROR_FILE_NOT_FOUND || broken(res == ERROR_MORE_DATA), /* nt4, win2k */
3343 "expect ERROR_FILE_NOT_FOUND, got %i\n", res);
3345 /* Default registry value */
3346 res = RegSetValueExA(hkey_main, "", 0, REG_SZ, (const BYTE *)"value", 6);
3347 ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res);
3349 res = RegQueryValueExA(hkey_main, "", NULL, NULL, NULL, NULL);
3350 ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res);
3352 res = RegDeleteValueA(hkey_main, "" );
3353 ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res);
3355 res = RegQueryValueExA(hkey_main, "", NULL, NULL, NULL, NULL);
3356 ok(res == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", res);
3359 static void test_delete_key_value(void)
3361 HKEY subkey;
3362 LONG ret;
3364 if (!pRegDeleteKeyValueA)
3366 win_skip("RegDeleteKeyValue is not available.\n");
3367 return;
3370 ret = pRegDeleteKeyValueA(NULL, NULL, NULL);
3371 ok(ret == ERROR_INVALID_HANDLE, "got %d\n", ret);
3373 ret = pRegDeleteKeyValueA(hkey_main, NULL, NULL);
3374 ok(ret == ERROR_FILE_NOT_FOUND, "got %d\n", ret);
3376 ret = RegSetValueExA(hkey_main, "test", 0, REG_SZ, (const BYTE*)"value", 6);
3377 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3379 ret = RegQueryValueExA(hkey_main, "test", NULL, NULL, NULL, NULL);
3380 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3382 /* NULL subkey name means delete from open key */
3383 ret = pRegDeleteKeyValueA(hkey_main, NULL, "test");
3384 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3386 ret = RegQueryValueExA(hkey_main, "test", NULL, NULL, NULL, NULL);
3387 ok(ret == ERROR_FILE_NOT_FOUND, "got %d\n", ret);
3389 /* now with real subkey */
3390 ret = RegCreateKeyExA(hkey_main, "Subkey1", 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &subkey, NULL);
3391 ok(!ret, "failed with error %d\n", ret);
3393 ret = RegSetValueExA(subkey, "test", 0, REG_SZ, (const BYTE*)"value", 6);
3394 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3396 ret = RegQueryValueExA(subkey, "test", NULL, NULL, NULL, NULL);
3397 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3399 ret = pRegDeleteKeyValueA(hkey_main, "Subkey1", "test");
3400 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3402 ret = RegQueryValueExA(subkey, "test", NULL, NULL, NULL, NULL);
3403 ok(ret == ERROR_FILE_NOT_FOUND, "got %d\n", ret);
3405 /* Default registry value */
3406 ret = RegSetValueExA(subkey, "", 0, REG_SZ, (const BYTE *)"value", 6);
3407 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3409 ret = RegQueryValueExA(subkey, "", NULL, NULL, NULL, NULL);
3410 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3412 ret = pRegDeleteKeyValueA(hkey_main, "Subkey1", "" );
3413 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3415 ret = RegQueryValueExA(subkey, "", NULL, NULL, NULL, NULL);
3416 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
3418 RegDeleteKeyA(subkey, "");
3419 RegCloseKey(subkey);
3422 static void test_RegOpenCurrentUser(void)
3424 HKEY key;
3425 LONG ret;
3427 key = HKEY_CURRENT_USER;
3428 ret = RegOpenCurrentUser(KEY_READ, &key);
3429 ok(!ret, "got %d, error %d\n", ret, GetLastError());
3430 ok(key != HKEY_CURRENT_USER, "got %p\n", key);
3431 RegCloseKey(key);
3434 struct notify_data {
3435 HKEY key;
3436 DWORD flags;
3437 HANDLE event;
3440 static DWORD WINAPI notify_change_thread(void *arg)
3442 struct notify_data *data = arg;
3443 LONG ret;
3445 ret = RegNotifyChangeKeyValue(data->key, TRUE,
3446 REG_NOTIFY_CHANGE_NAME|data->flags, data->event, TRUE);
3447 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3448 return 0;
3451 static void test_RegNotifyChangeKeyValue(void)
3453 struct notify_data data;
3454 HKEY key, subkey, subsubkey;
3455 HANDLE thread;
3456 HANDLE event;
3457 DWORD dwret;
3458 LONG ret;
3460 event = CreateEventW(NULL, FALSE, TRUE, NULL);
3461 ok(event != NULL, "CreateEvent failed, error %u\n", GetLastError());
3462 ret = RegCreateKeyA(hkey_main, "TestKey", &key);
3463 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3465 ret = RegNotifyChangeKeyValue(key, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, event, TRUE);
3466 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3467 dwret = WaitForSingleObject(event, 0);
3468 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", dwret);
3470 ret = RegCreateKeyA(key, "SubKey", &subkey);
3471 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3472 dwret = WaitForSingleObject(event, 0);
3473 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
3475 /* watching deeper keys */
3476 ret = RegNotifyChangeKeyValue(key, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, event, TRUE);
3477 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3478 dwret = WaitForSingleObject(event, 0);
3479 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", dwret);
3481 ret = RegCreateKeyA(subkey, "SubKey", &subsubkey);
3482 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3483 dwret = WaitForSingleObject(event, 0);
3484 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
3486 /* watching deeper values */
3487 ret = RegNotifyChangeKeyValue(key, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, event, TRUE);
3488 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3489 dwret = WaitForSingleObject(event, 0);
3490 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", dwret);
3492 ret = RegSetValueA(subsubkey, NULL, REG_SZ, "SubSubKeyValue", 0);
3493 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3494 dwret = WaitForSingleObject(event, 0);
3495 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
3497 /* don't watch deeper values */
3498 RegCloseKey(key);
3499 ret = RegOpenKeyA(hkey_main, "TestKey", &key);
3500 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3502 ret = RegNotifyChangeKeyValue(key, FALSE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, event, TRUE);
3503 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3504 dwret = WaitForSingleObject(event, 0);
3505 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", dwret);
3507 ret = RegSetValueA(subsubkey, NULL, REG_SZ, "SubSubKeyValueNEW", 0);
3508 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3509 dwret = WaitForSingleObject(event, 0);
3510 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", dwret);
3512 RegDeleteKeyA(subkey, "SubKey");
3513 RegDeleteKeyA(key, "SubKey");
3514 RegCloseKey(subsubkey);
3515 RegCloseKey(subkey);
3516 RegCloseKey(key);
3518 /* test same thread with REG_NOTIFY_THREAD_AGNOSTIC */
3519 ret = RegOpenKeyA(hkey_main, "TestKey", &key);
3520 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3521 ret = RegNotifyChangeKeyValue(key, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_THREAD_AGNOSTIC,
3522 event, TRUE);
3523 if (ret == ERROR_INVALID_PARAMETER)
3525 win_skip("REG_NOTIFY_THREAD_AGNOSTIC is not supported\n");
3526 RegCloseKey(key);
3527 CloseHandle(event);
3528 return;
3531 ret = RegCreateKeyA(key, "SubKey", &subkey);
3532 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3533 dwret = WaitForSingleObject(event, 0);
3534 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
3536 RegDeleteKeyA(key, "SubKey");
3537 RegCloseKey(subkey);
3538 RegCloseKey(key);
3540 /* test different thread without REG_NOTIFY_THREAD_AGNOSTIC */
3541 ret = RegOpenKeyA(hkey_main, "TestKey", &key);
3542 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3544 data.key = key;
3545 data.flags = 0;
3546 data.event = event;
3547 thread = CreateThread(NULL, 0, notify_change_thread, &data, 0, NULL);
3548 WaitForSingleObject(thread, INFINITE);
3549 CloseHandle(thread);
3551 /* the thread exiting causes event to signal on Windows
3552 this is worked around on Windows using REG_NOTIFY_THREAD_AGNOSTIC
3553 Wine already behaves as if the flag is set */
3554 dwret = WaitForSingleObject(event, 0);
3555 todo_wine
3556 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
3557 RegCloseKey(key);
3559 /* test different thread with REG_NOTIFY_THREAD_AGNOSTIC */
3560 ret = RegOpenKeyA(hkey_main, "TestKey", &key);
3561 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3563 data.flags = REG_NOTIFY_THREAD_AGNOSTIC;
3564 thread = CreateThread(NULL, 0, notify_change_thread, &data, 0, NULL);
3565 WaitForSingleObject(thread, INFINITE);
3566 CloseHandle(thread);
3568 dwret = WaitForSingleObject(event, 0);
3569 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", dwret);
3571 ret = RegCreateKeyA(key, "SubKey", &subkey);
3572 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3574 dwret = WaitForSingleObject(event, 0);
3575 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
3577 RegDeleteKeyA(key, "SubKey");
3578 RegDeleteKeyA(key, "");
3579 RegCloseKey(subkey);
3580 RegCloseKey(key);
3581 CloseHandle(event);
3584 #define cmp_li(a, b, c) cmp_li_real(a, b, c, __LINE__)
3585 static void cmp_li_real(LARGE_INTEGER *l1, LARGE_INTEGER *l2, LONGLONG slack, int line)
3587 LONGLONG diff = l2->QuadPart - l1->QuadPart;
3588 if (diff < 0) diff = -diff;
3589 ok_(__FILE__, line)(diff <= slack, "values don't match: %s/%s\n",
3590 wine_dbgstr_longlong(l1->QuadPart), wine_dbgstr_longlong(l2->QuadPart));
3593 static void test_RegQueryValueExPerformanceData(void)
3595 static const WCHAR globalW[] = { 'G','l','o','b','a','l',0 };
3596 static const WCHAR dummyW[5] = { 'd','u','m','m','y' };
3597 static const char * const names[] = { NULL, "", "Global", "2", "invalid counter name" };
3598 DWORD cbData, len, i, type;
3599 BYTE *value;
3600 DWORD dwret;
3601 LONG limit = 6;
3602 PERF_DATA_BLOCK *pdb;
3603 HKEY hkey;
3604 BYTE buf[256 + sizeof(PERF_DATA_BLOCK)];
3606 /* Test with data == NULL */
3607 dwret = RegQueryValueExA( HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, NULL, &cbData );
3608 ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret );
3610 dwret = RegQueryValueExW( HKEY_PERFORMANCE_DATA, globalW, NULL, NULL, NULL, &cbData );
3611 ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret );
3613 /* Test ERROR_MORE_DATA, start with small buffer */
3614 len = 10;
3615 value = HeapAlloc(GetProcessHeap(), 0, len);
3616 cbData = len;
3617 type = 0xdeadbeef;
3618 dwret = RegQueryValueExA( HKEY_PERFORMANCE_DATA, "Global", NULL, &type, value, &cbData );
3619 ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret );
3620 ok(type == REG_BINARY, "got %u\n", type);
3621 while( dwret == ERROR_MORE_DATA && limit)
3623 len = len * 10;
3624 value = HeapReAlloc( GetProcessHeap(), 0, value, len );
3625 cbData = len;
3626 type = 0xdeadbeef;
3627 dwret = RegQueryValueExA( HKEY_PERFORMANCE_DATA, "Global", NULL, &type, value, &cbData );
3628 limit--;
3630 ok(limit > 0, "too many times ERROR_MORE_DATA returned\n");
3632 ok(dwret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", dwret);
3633 ok(type == REG_BINARY, "got %u\n", type);
3635 /* Check returned data */
3636 if (dwret == ERROR_SUCCESS)
3638 ok(len >= sizeof(PERF_DATA_BLOCK), "got size %d\n", len);
3639 if (len >= sizeof(PERF_DATA_BLOCK)) {
3640 pdb = (PERF_DATA_BLOCK*) value;
3641 ok(pdb->Signature[0] == 'P', "expected Signature[0] = 'P', got 0x%x\n", pdb->Signature[0]);
3642 ok(pdb->Signature[1] == 'E', "expected Signature[1] = 'E', got 0x%x\n", pdb->Signature[1]);
3643 ok(pdb->Signature[2] == 'R', "expected Signature[2] = 'R', got 0x%x\n", pdb->Signature[2]);
3644 ok(pdb->Signature[3] == 'F', "expected Signature[3] = 'F', got 0x%x\n", pdb->Signature[3]);
3645 /* TODO: check other field */
3649 HeapFree(GetProcessHeap(), 0, value);
3651 for (i = 0; i < ARRAY_SIZE(names); i++)
3653 cbData = 0xdeadbeef;
3654 dwret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, names[i], NULL, NULL, NULL, &cbData);
3655 ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret);
3656 ok(cbData == 0, "got %u\n", cbData);
3658 cbData = 0;
3659 dwret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, names[i], NULL, NULL, NULL, &cbData);
3660 ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret);
3661 ok(cbData == 0, "got %u\n", cbData);
3663 cbData = 0xdeadbeef;
3664 dwret = RegQueryValueExA(HKEY_PERFORMANCE_TEXT, names[i], NULL, NULL, NULL, &cbData);
3665 todo_wine
3666 ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret);
3667 ok(cbData == 0, "got %u\n", cbData);
3669 cbData = 0;
3670 dwret = RegQueryValueExA(HKEY_PERFORMANCE_TEXT, names[i], NULL, NULL, NULL, &cbData);
3671 todo_wine
3672 ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret);
3673 ok(cbData == 0, "got %u\n", cbData);
3675 cbData = 0xdeadbeef;
3676 dwret = RegQueryValueExA(HKEY_PERFORMANCE_NLSTEXT, names[i], NULL, NULL, NULL, &cbData);
3677 todo_wine
3678 ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret);
3679 ok(cbData == 0, "got %u\n", cbData);
3681 cbData = 0;
3682 dwret = RegQueryValueExA(HKEY_PERFORMANCE_NLSTEXT, names[i], NULL, NULL, NULL, &cbData);
3683 todo_wine
3684 ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret);
3685 ok(cbData == 0, "got %u\n", cbData);
3688 memset(buf, 0x77, sizeof(buf));
3689 type = 0xdeadbeef;
3690 cbData = sizeof(buf);
3691 dwret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "invalid counter name", NULL, &type, buf, &cbData);
3692 ok(dwret == ERROR_SUCCESS, "got %u\n", dwret);
3693 ok(type == REG_BINARY, "got %u\n", type);
3694 if (dwret == ERROR_SUCCESS)
3696 SYSTEMTIME st;
3697 WCHAR sysname[MAX_COMPUTERNAME_LENGTH + 1];
3698 DWORD sysname_len;
3699 LARGE_INTEGER counter, freq, ftime;
3701 GetSystemTime(&st);
3702 GetSystemTimeAsFileTime((FILETIME *)&ftime);
3703 QueryPerformanceCounter(&counter);
3704 QueryPerformanceFrequency(&freq);
3706 sysname_len = MAX_COMPUTERNAME_LENGTH + 1;
3707 GetComputerNameW(sysname, &sysname_len);
3709 pdb = (PERF_DATA_BLOCK *)buf;
3710 ok(pdb->Signature[0] == 'P', "got '%c'\n", pdb->Signature[0]);
3711 ok(pdb->Signature[1] == 'E', "got '%c'\n", pdb->Signature[1]);
3712 ok(pdb->Signature[2] == 'R', "got '%c'\n", pdb->Signature[2]);
3713 ok(pdb->Signature[3] == 'F', "got '%c'\n", pdb->Signature[3]);
3715 ok(pdb->LittleEndian == 1, "got %u\n", pdb->LittleEndian);
3716 ok(pdb->Version == 1, "got %u\n", pdb->Version);
3717 ok(pdb->Revision == 1, "got %u\n", pdb->Revision);
3718 len = (sizeof(*pdb) + pdb->SystemNameLength + 7) & ~7;
3719 ok(pdb->TotalByteLength == len, "got %u vs %u\n", pdb->TotalByteLength, len);
3720 ok(pdb->HeaderLength == pdb->TotalByteLength, "got %u\n", pdb->HeaderLength);
3721 ok(pdb->NumObjectTypes == 0, "got %u\n", pdb->NumObjectTypes);
3722 todo_wine
3723 ok(pdb->DefaultObject != 0, "got %u\n", pdb->DefaultObject);
3724 ok(pdb->SystemTime.wYear == st.wYear, "got %u\n", pdb->SystemTime.wYear);
3725 ok(pdb->SystemTime.wMonth == st.wMonth, "got %u\n", pdb->SystemTime.wMonth);
3726 ok(pdb->SystemTime.wDayOfWeek == st.wDayOfWeek, "got %u\n", pdb->SystemTime.wDayOfWeek);
3727 ok(pdb->SystemTime.wDay == st.wDay, "got %u\n", pdb->SystemTime.wDay);
3728 if (U(pdb->PerfTime).LowPart != 0x77777777) /* TestBot is broken */
3729 cmp_li(&pdb->PerfTime, &counter, freq.QuadPart);
3730 if (U(pdb->PerfFreq).LowPart != 0x77777777) /* TestBot is broken */
3731 cmp_li(&pdb->PerfFreq, &freq, 0);
3732 cmp_li(&pdb->PerfTime100nSec, &ftime, 200000); /* TestBot needs huge slack value */
3733 ok(pdb->SystemNameLength == (sysname_len + 1) * sizeof(WCHAR), "expected %u, got %u\n",
3734 (sysname_len + 1) * 2 /*sizeof(WCHAR)*/, pdb->SystemNameLength);
3735 ok(pdb->SystemNameOffset == sizeof(*pdb), "got %u\n", pdb->SystemNameOffset);
3736 ok(!lstrcmpW(sysname, (LPCWSTR)(pdb + 1)), "%s != %s\n",
3737 wine_dbgstr_w(sysname), wine_dbgstr_w((LPCWSTR)(pdb + 1)));
3739 len = pdb->TotalByteLength - (sizeof(*pdb) + pdb->SystemNameLength);
3740 if (len)
3742 BYTE remainder[8], *p;
3744 memset(remainder, 0x77, sizeof(remainder));
3745 p = buf + sizeof(*pdb) + pdb->SystemNameLength;
3746 ok(!memcmp(p, remainder, len), "remainder: %02x,%02x...\n", p[0], p[1]);
3750 dwret = RegOpenKeyA(HKEY_PERFORMANCE_DATA, NULL, &hkey);
3751 todo_wine
3752 ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret);
3754 dwret = RegOpenKeyA(HKEY_PERFORMANCE_DATA, "Global", &hkey);
3755 todo_wine
3756 ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret);
3758 dwret = RegOpenKeyExA(HKEY_PERFORMANCE_DATA, "Global", 0, KEY_READ, &hkey);
3759 todo_wine
3760 ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret);
3762 dwret = RegQueryValueA(HKEY_PERFORMANCE_DATA, "Global", NULL, (LONG *)&cbData);
3763 todo_wine
3764 ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret);
3766 dwret = RegSetValueA(HKEY_PERFORMANCE_DATA, "Global", REG_SZ, "dummy", 4);
3767 todo_wine
3768 ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret);
3770 dwret = RegSetValueExA(HKEY_PERFORMANCE_DATA, "Global", 0, REG_SZ, (const BYTE *)"dummy", 40);
3771 todo_wine
3772 ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret);
3774 cbData = sizeof(buf);
3775 dwret = RegEnumKeyA(HKEY_PERFORMANCE_DATA, 0, (LPSTR)buf, cbData);
3776 todo_wine
3777 ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret);
3779 cbData = sizeof(buf);
3780 dwret = RegEnumValueA(HKEY_PERFORMANCE_DATA, 0, (LPSTR)buf, &cbData, NULL, NULL, NULL, NULL);
3781 todo_wine
3782 ok(dwret == ERROR_MORE_DATA, "got %u\n", dwret);
3783 todo_wine
3784 ok(cbData == sizeof(buf), "got %u\n", cbData);
3786 dwret = RegEnumValueA(HKEY_PERFORMANCE_DATA, 0, NULL, &cbData, NULL, NULL, NULL, NULL);
3787 ok(dwret == ERROR_INVALID_PARAMETER, "got %u\n", dwret);
3789 if (pRegSetKeyValueW)
3791 dwret = pRegSetKeyValueW(HKEY_PERFORMANCE_DATA, NULL, globalW, REG_SZ, dummyW, sizeof(dummyW));
3792 todo_wine
3793 ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret);
3796 dwret = RegCloseKey(HKEY_PERFORMANCE_DATA);
3797 ok(dwret == ERROR_SUCCESS, "got %u\n", dwret);
3800 static void test_RegLoadMUIString(void)
3802 HMODULE hUser32, hResDll, hFile;
3803 int (WINAPI *pLoadStringW)(HMODULE, UINT, WCHAR *, int);
3804 LONG ret;
3805 HKEY hkey;
3806 DWORD type, size, text_size;
3807 UINT i;
3808 char buf[64], *p, sysdir[MAX_PATH];
3809 char with_env_var[128], filename[MAX_PATH], tmp_path[MAX_PATH];
3810 WCHAR textW[64], bufW[64];
3811 WCHAR curdirW[MAX_PATH], sysdirW[MAX_PATH];
3812 const static char tz_value[] = "MUI_Std";
3813 const static WCHAR tz_valueW[] = {'M','U','I','_','S','t','d', 0};
3814 struct {
3815 const char* value;
3816 DWORD type;
3817 BOOL use_sysdir;
3818 DWORD expected;
3819 DWORD broken_ret;
3820 } test_case[] = {
3821 /* 0 */
3822 { "", REG_SZ, FALSE, ERROR_INVALID_DATA },
3823 { "not a MUI string", REG_SZ, FALSE, ERROR_INVALID_DATA },
3824 { "@unknown.dll", REG_SZ, TRUE, ERROR_INVALID_DATA },
3825 { "@unknown.dll,-10", REG_SZ, TRUE, ERROR_FILE_NOT_FOUND },
3826 /* 4 */
3827 { with_env_var, REG_SZ, FALSE, ERROR_SUCCESS },
3828 { with_env_var, REG_EXPAND_SZ, FALSE, ERROR_SUCCESS },
3829 { "%WineMuiTest1%", REG_EXPAND_SZ, TRUE, ERROR_INVALID_DATA },
3830 { "@%WineMuiTest2%", REG_EXPAND_SZ, TRUE, ERROR_SUCCESS },
3831 /* 8 */
3832 { "@%WineMuiExe%,a", REG_SZ, FALSE, ERROR_INVALID_DATA },
3833 { "@%WineMuiExe%,-4", REG_SZ, FALSE, ERROR_NOT_FOUND, ERROR_FILE_NOT_FOUND },
3834 { "@%WineMuiExe%,-39", REG_SZ, FALSE, ERROR_RESOURCE_NAME_NOT_FOUND },
3835 { "@%WineMuiDat%,-16", REG_EXPAND_SZ, FALSE, ERROR_BAD_EXE_FORMAT, ERROR_FILE_NOT_FOUND },
3838 if (!pRegLoadMUIStringA || !pRegLoadMUIStringW)
3840 win_skip("RegLoadMUIString is not available\n");
3841 return;
3844 hUser32 = LoadLibraryA("user32.dll");
3845 ok(hUser32 != NULL, "cannot load user32.dll\n");
3846 pLoadStringW = (void *)GetProcAddress(hUser32, "LoadStringW");
3847 ok(pLoadStringW != NULL, "failed to get LoadStringW address\n");
3849 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
3850 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\UTC", 0,
3851 KEY_READ, &hkey);
3852 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3854 size = ARRAY_SIZE(buf);
3855 ret = RegQueryValueExA(hkey, tz_value, NULL, &type, (BYTE *)buf, &size);
3856 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3857 ok(buf[0] == '@', "got %s\n", buf);
3859 /* setup MUI string for tests */
3860 strcpy(with_env_var, "@%windir%\\system32\\");
3861 strcat(with_env_var, &buf[1]);
3862 SetEnvironmentVariableA("WineMuiTest1", buf);
3863 SetEnvironmentVariableA("WineMuiTest2", &buf[1]);
3865 /* load expecting text */
3866 p = strrchr(buf, ',');
3867 *p = '\0';
3868 i = atoi(p + 2); /* skip ',-' */
3869 hResDll = LoadLibraryExA(&buf[1], NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
3870 memset(textW, 0xaa, sizeof(textW));
3871 ret = pLoadStringW(hResDll, i, textW, ARRAY_SIZE(textW));
3872 ok(ret > 0, "failed to load string resource\n");
3873 text_size = (ret + 1) * sizeof(WCHAR);
3874 FreeLibrary(hResDll);
3875 FreeLibrary(hUser32);
3877 ret = GetSystemDirectoryW(sysdirW, ARRAY_SIZE(sysdirW));
3878 ok(ret > 0, "GetSystemDirectoryW failed\n");
3879 ret = GetSystemDirectoryA(sysdir, ARRAY_SIZE(sysdir));
3880 ok(ret > 0, "GetSystemDirectoryA failed\n");
3882 /* change the current directory to system32 */
3883 GetCurrentDirectoryW(ARRAY_SIZE(curdirW), curdirW);
3884 SetCurrentDirectoryW(sysdirW);
3886 size = 0xdeadbeef;
3887 ret = pRegLoadMUIStringW(hkey, tz_valueW, NULL, 0, &size, 0, NULL);
3888 ok(ret == ERROR_MORE_DATA, "got %d, expected ERROR_MORE_DATA\n", ret);
3889 ok(size == text_size, "got %u, expected %u\n", size, text_size);
3891 memset(bufW, 0xff, sizeof(bufW));
3892 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)+1, &size, 0, NULL);
3893 ok(ret == ERROR_INVALID_PARAMETER, "got %d, expected ERROR_INVALID_PARAMETER\n", ret);
3894 ok(bufW[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW[0]);
3896 size = 0xdeadbeef;
3897 memset(bufW, 0xff, sizeof(bufW));
3898 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)*2, &size, 0, NULL);
3899 ok(ret == ERROR_MORE_DATA, "got %d, expected ERROR_MORE_DATA\n", ret);
3900 ok(size == text_size || broken(size == text_size + sizeof(WCHAR) /* vista */),
3901 "got %u, expected %u\n", size, text_size);
3902 ok(bufW[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW[0]);
3904 memset(bufW, 0xff, sizeof(bufW));
3905 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)*2, &size, REG_MUI_STRING_TRUNCATE, NULL);
3906 ok(ret == ERROR_INVALID_PARAMETER, "got %d, expected ERROR_INVALID_PARAMETER\n", ret);
3907 ok(bufW[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW[0]);
3909 memset(bufW, 0xff, sizeof(bufW));
3910 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)*2, NULL, 0xdeadbeef, NULL);
3911 ok(ret == ERROR_INVALID_PARAMETER, "got %d, expected ERROR_INVALID_PARAMETER\n", ret);
3912 ok(bufW[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW[0]);
3914 memset(bufW, 0xff, sizeof(bufW));
3915 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)*2, NULL, REG_MUI_STRING_TRUNCATE, NULL);
3916 ok(ret == ERROR_SUCCESS, "got %d, expected ERROR_SUCCESS\n", ret);
3917 ok(bufW[0] == textW[0], "got 0x%04x, expected 0x%04x\n", bufW[0], textW[0]);
3918 ok(bufW[1] == 0, "got 0x%04x, expected nul\n", bufW[1]);
3920 size = 0xdeadbeef;
3921 memset(bufW, 0xff, sizeof(bufW));
3922 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, ARRAY_SIZE(bufW), &size, 0, NULL);
3923 ok(ret == ERROR_SUCCESS, "got %d, expected ERROR_SUCCESS\n", ret);
3924 ok(size == text_size, "got %u, expected %u\n", size, text_size);
3925 ok(!memcmp(textW, bufW, size), "got %s, expected %s\n",
3926 wine_dbgstr_wn(bufW, size / sizeof(WCHAR)), wine_dbgstr_wn(textW, text_size / sizeof(WCHAR)));
3928 ret = pRegLoadMUIStringA(hkey, tz_value, buf, ARRAY_SIZE(buf), &size, 0, NULL);
3929 ok(ret == ERROR_CALL_NOT_IMPLEMENTED, "got %d, expected ERROR_CALL_NOT_IMPLEMENTED\n", ret);
3931 /* change the current directory to other than system32 directory */
3932 SetCurrentDirectoryA("\\");
3934 size = 0xdeadbeef;
3935 memset(bufW, 0xff, sizeof(bufW));
3936 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, ARRAY_SIZE(bufW), &size, 0, sysdirW);
3937 ok(ret == ERROR_SUCCESS, "got %d, expected ERROR_SUCCESS\n", ret);
3938 ok(size == text_size, "got %u, expected %u\n", size, text_size);
3939 ok(!memcmp(textW, bufW, size), "got %s, expected %s\n",
3940 wine_dbgstr_wn(bufW, size / sizeof(WCHAR)), wine_dbgstr_wn(textW, text_size / sizeof(WCHAR)));
3942 ret = pRegLoadMUIStringA(hkey, tz_value, buf, ARRAY_SIZE(buf), &size, 0, sysdir);
3943 ok(ret == ERROR_CALL_NOT_IMPLEMENTED, "got %d, expected ERROR_CALL_NOT_IMPLEMENTED\n", ret);
3945 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, ARRAY_SIZE(bufW), &size, 0, NULL);
3946 ok(ret == ERROR_FILE_NOT_FOUND, "got %d, expected ERROR_FILE_NOT_FOUND\n", ret);
3948 ret = pRegLoadMUIStringA(hkey, tz_value, buf, ARRAY_SIZE(buf), &size, 0, NULL);
3949 ok(ret == ERROR_CALL_NOT_IMPLEMENTED, "got %d, expected ERROR_CALL_NOT_IMPLEMENTED\n", ret);
3951 RegCloseKey(hkey);
3953 GetModuleFileNameA(NULL, filename, ARRAY_SIZE(filename));
3954 SetEnvironmentVariableA("WineMuiExe", filename);
3956 GetTempPathA(ARRAY_SIZE(tmp_path), tmp_path);
3957 GetTempFileNameA(tmp_path, "mui", 0, filename);
3958 SetEnvironmentVariableA("WineMuiDat", filename);
3960 /* write dummy data to the file, i.e. it's not a PE file. */
3961 hFile = CreateFileA(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
3962 ok(hFile != INVALID_HANDLE_VALUE, "can't open %s\n", filename);
3963 WriteFile(hFile, filename, strlen(filename), &size, NULL);
3964 CloseHandle(hFile);
3966 for (i = 0; i < ARRAY_SIZE(test_case); i++)
3968 size = test_case[i].value ? strlen(test_case[i].value) + 1 : 0;
3969 ret = RegSetValueExA(hkey_main, tz_value, 0, test_case[i].type,
3970 (const BYTE *)test_case[i].value, size);
3971 ok(ret == ERROR_SUCCESS, "[%2u] got %d\n", i, ret);
3973 size = 0xdeadbeef;
3974 memset(bufW, 0xff, sizeof(bufW));
3975 ret = pRegLoadMUIStringW(hkey_main, tz_valueW, bufW, ARRAY_SIZE(bufW),
3976 &size, 0,
3977 test_case[i].use_sysdir ? sysdirW : NULL);
3978 ok(ret == test_case[i].expected ||
3979 broken(test_case[i].value[0] == '%' && ret == ERROR_SUCCESS /* vista */) ||
3980 broken(test_case[i].broken_ret && ret == test_case[i].broken_ret /* vista */),
3981 "[%2u] expected %d, got %d\n", i, test_case[i].expected, ret);
3982 if (ret == ERROR_SUCCESS && test_case[i].expected == ERROR_SUCCESS)
3984 ok(size == text_size, "[%2u] got %u, expected %u\n", i, size, text_size);
3985 ok(!memcmp(bufW, textW, size), "[%2u] got %s, expected %s\n", i,
3986 wine_dbgstr_wn(bufW, size/sizeof(WCHAR)),
3987 wine_dbgstr_wn(textW, text_size/sizeof(WCHAR)));
3991 SetCurrentDirectoryW(curdirW);
3992 DeleteFileA(filename);
3993 SetEnvironmentVariableA("WineMuiTest1", NULL);
3994 SetEnvironmentVariableA("WineMuiTest2", NULL);
3995 SetEnvironmentVariableA("WineMuiExe", NULL);
3996 SetEnvironmentVariableA("WineMuiDat", NULL);
3999 static void test_EnumDynamicTimeZoneInformation(void)
4001 LSTATUS status;
4002 HKEY key, subkey;
4003 WCHAR name[32];
4004 WCHAR keyname[128];
4005 WCHAR sysdir[MAX_PATH];
4006 DWORD index, ret, gle, size;
4007 DYNAMIC_TIME_ZONE_INFORMATION bogus_dtzi, dtzi;
4008 static const WCHAR stdW[] = {'S','t','d',0};
4009 static const WCHAR dltW[] = {'D','l','t',0};
4010 static const WCHAR tziW[] = {'T','Z','I',0};
4011 static const WCHAR mui_stdW[] = {'M','U','I','_','S','t','d',0};
4012 static const WCHAR mui_dltW[] = {'M','U','I','_','D','l','t',0};
4013 struct tz_reg_data
4015 LONG bias;
4016 LONG std_bias;
4017 LONG dlt_bias;
4018 SYSTEMTIME std_date;
4019 SYSTEMTIME dlt_date;
4020 } tz_data;
4022 if (!pEnumDynamicTimeZoneInformation)
4024 win_skip("EnumDynamicTimeZoneInformation is not supported.\n");
4025 return;
4028 if (pRegLoadMUIStringW)
4029 GetSystemDirectoryW(sysdir, ARRAY_SIZE(sysdir));
4031 SetLastError(0xdeadbeef);
4032 ret = pEnumDynamicTimeZoneInformation(0, NULL);
4033 gle = GetLastError();
4034 ok(gle == 0xdeadbeef, "got 0x%x\n", gle);
4035 ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret);
4037 memset(&bogus_dtzi, 0xcc, sizeof(bogus_dtzi));
4038 memset(&dtzi, 0xcc, sizeof(dtzi));
4039 SetLastError(0xdeadbeef);
4040 ret = pEnumDynamicTimeZoneInformation(-1, &dtzi);
4041 gle = GetLastError();
4042 ok(gle == 0xdeadbeef, "got 0x%x\n", gle);
4043 ok(ret == ERROR_NO_MORE_ITEMS, "got %d\n", ret);
4044 ok(!memcmp(&dtzi, &bogus_dtzi, sizeof(dtzi)), "mismatch\n");
4046 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
4047 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0,
4048 KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE, &key);
4049 ok(status == ERROR_SUCCESS, "got %d\n", status);
4050 index = 0;
4051 while (!(status = RegEnumKeyW(key, index, keyname, ARRAY_SIZE(keyname))))
4053 subkey = NULL;
4054 status = RegOpenKeyExW(key, keyname, 0, KEY_QUERY_VALUE, &subkey);
4055 ok(status == ERROR_SUCCESS, "got %d\n", status);
4057 memset(&dtzi, 0xcc, sizeof(dtzi));
4058 SetLastError(0xdeadbeef);
4059 ret = pEnumDynamicTimeZoneInformation(index, &dtzi);
4060 gle = GetLastError();
4061 /* recently added time zones may not have MUI strings */
4062 ok(gle == ERROR_SUCCESS ||
4063 gle == ERROR_RESOURCE_TYPE_NOT_FOUND /* Win10 1809 32-bit */ ||
4064 gle == ERROR_MUI_FILE_NOT_FOUND /* Win10 1809 64-bit */,
4065 "got 0x%x\n", gle);
4066 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
4067 ok(!lstrcmpW(dtzi.TimeZoneKeyName, keyname), "expected %s, got %s\n",
4068 wine_dbgstr_w(keyname), wine_dbgstr_w(dtzi.TimeZoneKeyName));
4070 if (gle == ERROR_SUCCESS)
4072 size = sizeof(name);
4073 memset(name, 0, sizeof(name));
4074 if (pRegLoadMUIStringW)
4075 status = pRegLoadMUIStringW(subkey, mui_stdW, name, size, &size, 0, sysdir);
4076 else
4077 status = pRegGetValueW(subkey, NULL, stdW, RRF_RT_REG_SZ, NULL, name, &size);
4078 ok(status == ERROR_SUCCESS, "status %d name %s\n", status, wine_dbgstr_w(name));
4079 ok(!memcmp(&dtzi.StandardName, name, size),
4080 "expected %s, got %s\n", wine_dbgstr_w(name), wine_dbgstr_w(dtzi.StandardName));
4082 size = sizeof(name);
4083 memset(name, 0, sizeof(name));
4084 if (pRegLoadMUIStringW)
4085 status = pRegLoadMUIStringW(subkey, mui_dltW, name, size, &size, 0, sysdir);
4086 else
4087 status = pRegGetValueW(subkey, NULL, dltW, RRF_RT_REG_SZ, NULL, name, &size);
4088 ok(status == ERROR_SUCCESS, "status %d name %s\n", status, wine_dbgstr_w(name));
4089 ok(!memcmp(&dtzi.DaylightName, name, size),
4090 "expected %s, got %s\n", wine_dbgstr_w(name), wine_dbgstr_w(dtzi.DaylightName));
4092 else
4094 ok(!dtzi.StandardName[0], "expected empty StandardName\n");
4095 ok(!dtzi.DaylightName[0], "expected empty DaylightName\n");
4098 ok(!dtzi.DynamicDaylightTimeDisabled, "got %d\n", dtzi.DynamicDaylightTimeDisabled);
4100 size = sizeof(tz_data);
4101 status = pRegGetValueW(key, keyname, tziW, RRF_RT_REG_BINARY, NULL, &tz_data, &size);
4102 ok(status == ERROR_SUCCESS, "got %d\n", status);
4104 ok(dtzi.Bias == tz_data.bias, "expected %d, got %d\n",
4105 tz_data.bias, dtzi.Bias);
4106 ok(dtzi.StandardBias == tz_data.std_bias, "expected %d, got %d\n",
4107 tz_data.std_bias, dtzi.StandardBias);
4108 ok(dtzi.DaylightBias == tz_data.dlt_bias, "expected %d, got %d\n",
4109 tz_data.dlt_bias, dtzi.DaylightBias);
4111 ok(!memcmp(&dtzi.StandardDate, &tz_data.std_date, sizeof(dtzi.StandardDate)),
4112 "expected %s, got %s\n",
4113 dbgstr_SYSTEMTIME(&tz_data.std_date), dbgstr_SYSTEMTIME(&dtzi.StandardDate));
4115 ok(!memcmp(&dtzi.DaylightDate, &tz_data.dlt_date, sizeof(dtzi.DaylightDate)),
4116 "expected %s, got %s\n",
4117 dbgstr_SYSTEMTIME(&tz_data.dlt_date), dbgstr_SYSTEMTIME(&dtzi.DaylightDate));
4119 RegCloseKey(subkey);
4120 index++;
4122 ok(status == ERROR_NO_MORE_ITEMS, "got %d\n", status);
4124 memset(&dtzi, 0xcc, sizeof(dtzi));
4125 SetLastError(0xdeadbeef);
4126 ret = pEnumDynamicTimeZoneInformation(index, &dtzi);
4127 gle = GetLastError();
4128 ok(gle == 0xdeadbeef, "got 0x%x\n", gle);
4129 ok(ret == ERROR_NO_MORE_ITEMS, "got %d\n", ret);
4130 ok(!memcmp(&dtzi, &bogus_dtzi, sizeof(dtzi)), "mismatch\n");
4132 RegCloseKey(key);
4135 START_TEST(registry)
4137 /* Load pointers for functions that are not available in all Windows versions */
4138 InitFunctionPtrs();
4140 setup_main_key();
4141 check_user_privs();
4142 test_set_value();
4143 create_test_entries();
4144 test_enum_value();
4145 test_query_value_ex();
4146 test_get_value();
4147 test_reg_open_key();
4148 test_reg_create_key();
4149 test_reg_close_key();
4150 test_reg_delete_key();
4151 test_reg_query_value();
4152 test_reg_query_info();
4153 test_string_termination();
4154 test_symlinks();
4155 test_redirection();
4156 test_classesroot();
4157 test_classesroot_enum();
4158 test_classesroot_mask();
4159 test_reg_save_key();
4160 test_reg_load_key();
4161 test_reg_unload_key();
4162 test_reg_copy_tree();
4163 test_reg_delete_tree();
4164 test_rw_order();
4165 test_deleted_key();
4166 test_delete_value();
4167 test_delete_key_value();
4168 test_RegOpenCurrentUser();
4169 test_RegNotifyChangeKeyValue();
4170 test_RegQueryValueExPerformanceData();
4171 test_RegLoadMUIString();
4172 test_EnumDynamicTimeZoneInformation();
4174 /* cleanup */
4175 delete_key( hkey_main );
4177 test_regconnectregistry();