advapi32/tests: Expand tests for performance keys.
[wine.git] / dlls / advapi32 / tests / registry.c
blob7e1348bf33ddf8cc1f0e946a1be43f36eb06cfa1
1 /*
2 * Unit tests for registry functions
4 * Copyright (c) 2002 Alexandre Julliard
5 * Copyright (c) 2010 André Hentschel
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include "ntstatus.h"
26 #define WIN32_NO_STATUS
27 #include "wine/test.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winternl.h"
31 #include "winreg.h"
32 #include "winperf.h"
33 #include "winsvc.h"
34 #include "winerror.h"
35 #include "aclapi.h"
37 #define IS_HKCR(hk) ((UINT_PTR)hk > 0 && ((UINT_PTR)hk & 3) == 2)
39 static HKEY hkey_main;
40 static DWORD GLE;
42 static const char * sTestpath1 = "%LONGSYSTEMVAR%\\subdir1";
43 static const char * sTestpath2 = "%FOO%\\subdir1";
44 static const DWORD ptr_size = 8 * sizeof(void*);
46 static DWORD (WINAPI *pRegGetValueA)(HKEY,LPCSTR,LPCSTR,DWORD,LPDWORD,PVOID,LPDWORD);
47 static DWORD (WINAPI *pRegGetValueW)(HKEY,LPCWSTR,LPCWSTR,DWORD,LPDWORD,PVOID,LPDWORD);
48 static LONG (WINAPI *pRegCopyTreeA)(HKEY,const char *,HKEY);
49 static LONG (WINAPI *pRegDeleteTreeA)(HKEY,const char *);
50 static DWORD (WINAPI *pRegDeleteKeyExA)(HKEY,LPCSTR,REGSAM,DWORD);
51 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
52 static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
53 static NTSTATUS (WINAPI * pNtUnloadKey)(POBJECT_ATTRIBUTES);
54 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(UNICODE_STRING*);
55 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
56 static NTSTATUS (WINAPI * pRtlInitUnicodeString)(PUNICODE_STRING,PCWSTR);
57 static LONG (WINAPI *pRegDeleteKeyValueA)(HKEY,LPCSTR,LPCSTR);
58 static LONG (WINAPI *pRegSetKeyValueW)(HKEY,LPCWSTR,LPCWSTR,DWORD,const void*,DWORD);
59 static LONG (WINAPI *pRegLoadMUIStringA)(HKEY,LPCSTR,LPSTR,DWORD,LPDWORD,DWORD,LPCSTR);
60 static LONG (WINAPI *pRegLoadMUIStringW)(HKEY,LPCWSTR,LPWSTR,DWORD,LPDWORD,DWORD,LPCWSTR);
61 static DWORD (WINAPI *pEnumDynamicTimeZoneInformation)(const DWORD,
62 DYNAMIC_TIME_ZONE_INFORMATION*);
64 static BOOL limited_user;
66 static const char *dbgstr_SYSTEMTIME(const SYSTEMTIME *st)
68 return wine_dbg_sprintf("%02d-%02d-%04d %02d:%02d:%02d.%03d",
69 st->wMonth, st->wDay, st->wYear,
70 st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);
73 #define ADVAPI32_GET_PROC(func) \
74 p ## func = (void*)GetProcAddress(hadvapi32, #func)
76 static void InitFunctionPtrs(void)
78 HMODULE hntdll = GetModuleHandleA("ntdll.dll");
79 HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
80 HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
82 /* This function was introduced with Windows 2003 SP1 */
83 ADVAPI32_GET_PROC(RegGetValueA);
84 ADVAPI32_GET_PROC(RegGetValueW);
85 ADVAPI32_GET_PROC(RegCopyTreeA);
86 ADVAPI32_GET_PROC(RegDeleteTreeA);
87 ADVAPI32_GET_PROC(RegDeleteKeyExA);
88 ADVAPI32_GET_PROC(RegDeleteKeyValueA);
89 ADVAPI32_GET_PROC(RegSetKeyValueW);
90 ADVAPI32_GET_PROC(RegLoadMUIStringA);
91 ADVAPI32_GET_PROC(RegLoadMUIStringW);
92 ADVAPI32_GET_PROC(EnumDynamicTimeZoneInformation);
94 pIsWow64Process = (void *)GetProcAddress( hkernel32, "IsWow64Process" );
95 pRtlFormatCurrentUserKeyPath = (void *)GetProcAddress( hntdll, "RtlFormatCurrentUserKeyPath" );
96 pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString");
97 pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString");
98 pNtDeleteKey = (void *)GetProcAddress( hntdll, "NtDeleteKey" );
99 pNtUnloadKey = (void *)GetProcAddress( hntdll, "NtUnloadKey" );
102 static BOOL is_special_key(HKEY key)
104 return !!((ULONG_PTR)key & 0x80000000);
107 /* delete key and all its subkeys */
108 static DWORD delete_key( HKEY hkey )
110 char name[MAX_PATH];
111 DWORD ret;
113 if ((ret = RegOpenKeyExA( hkey, "", 0, KEY_ENUMERATE_SUB_KEYS, &hkey ))) return ret;
114 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
116 HKEY tmp;
117 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
119 ret = delete_key( tmp );
120 RegCloseKey( tmp );
122 if (ret) break;
124 if (ret != ERROR_NO_MORE_ITEMS) return ret;
125 RegDeleteKeyA( hkey, "" );
126 RegCloseKey(hkey);
127 return 0;
130 static void setup_main_key(void)
132 DWORD ret;
134 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main )) delete_key( hkey_main );
136 ret = RegCreateKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main );
137 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
140 static void check_user_privs(void)
142 DWORD ret;
143 HKEY hkey = (HKEY)0xdeadbeef;
145 ret = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WRITE, &hkey);
146 ok(ret == ERROR_SUCCESS || ret == ERROR_ACCESS_DENIED, "expected success or access denied, got %i\n", ret);
147 if (ret == ERROR_SUCCESS)
149 ok(hkey != NULL, "RegOpenKeyExA succeeded but returned NULL hkey\n");
150 RegCloseKey(hkey);
152 else
154 ok(hkey == NULL, "RegOpenKeyExA failed but returned hkey %p\n", hkey);
155 limited_user = TRUE;
156 trace("running as limited user\n");
160 #define lok ok_(__FILE__, line)
161 #define test_hkey_main_Value_A(name, string, full_byte_len) _test_hkey_main_Value_A(__LINE__, name, string, full_byte_len)
162 static void _test_hkey_main_Value_A(int line, LPCSTR name, LPCSTR string,
163 DWORD full_byte_len)
165 DWORD ret, type, cbData;
166 DWORD str_byte_len;
167 BYTE* value;
169 type=0xdeadbeef;
170 cbData=0xdeadbeef;
171 /* When successful RegQueryValueExA() leaves GLE as is,
172 * so we must reset it to detect unimplemented functions.
174 SetLastError(0xdeadbeef);
175 ret = RegQueryValueExA(hkey_main, name, NULL, &type, NULL, &cbData);
176 GLE = GetLastError();
177 lok(ret == ERROR_SUCCESS, "RegQueryValueExA/1 failed: %d, GLE=%d\n", ret, GLE);
178 /* It is wrong for the Ansi version to not be implemented */
179 ok(GLE == 0xdeadbeef, "RegQueryValueExA set GLE = %u\n", GLE);
180 if(GLE == ERROR_CALL_NOT_IMPLEMENTED) return;
182 str_byte_len = (string ? lstrlenA(string) : 0) + 1;
183 lok(type == REG_SZ, "RegQueryValueExA/1 returned type %d\n", type);
184 lok(cbData == full_byte_len, "cbData=%d instead of %d or %d\n", cbData, full_byte_len, str_byte_len);
186 value = HeapAlloc(GetProcessHeap(), 0, cbData+1);
187 memset(value, 0xbd, cbData+1);
188 type=0xdeadbeef;
189 ret = RegQueryValueExA(hkey_main, name, NULL, &type, value, &cbData);
190 GLE = GetLastError();
191 lok(ret == ERROR_SUCCESS, "RegQueryValueExA/2 failed: %d, GLE=%d\n", ret, GLE);
192 if (!string)
194 /* When cbData == 0, RegQueryValueExA() should not modify the buffer */
195 lok(*value == 0xbd, "RegQueryValueExA overflowed: cbData=%u *value=%02x\n", cbData, *value);
197 else
199 lok(memcmp(value, string, cbData) == 0, "RegQueryValueExA/2 failed: %s/%d != %s/%d\n",
200 debugstr_an((char*)value, cbData), cbData,
201 debugstr_an(string, full_byte_len), full_byte_len);
202 lok(*(value+cbData) == 0xbd, "RegQueryValueExA/2 overflowed at offset %u: %02x != bd\n", cbData, *(value+cbData));
204 HeapFree(GetProcessHeap(), 0, value);
207 #define test_hkey_main_Value_W(name, string, full_byte_len) _test_hkey_main_Value_W(__LINE__, name, string, full_byte_len)
208 static void _test_hkey_main_Value_W(int line, LPCWSTR name, LPCWSTR string,
209 DWORD full_byte_len)
211 DWORD ret, type, cbData;
212 BYTE* value;
214 type=0xdeadbeef;
215 cbData=0xdeadbeef;
216 /* When successful RegQueryValueExW() leaves GLE as is,
217 * so we must reset it to detect unimplemented functions.
219 SetLastError(0xdeadbeef);
220 ret = RegQueryValueExW(hkey_main, name, NULL, &type, NULL, &cbData);
221 GLE = GetLastError();
222 lok(ret == ERROR_SUCCESS, "RegQueryValueExW/1 failed: %d, GLE=%d\n", ret, GLE);
223 if(GLE == ERROR_CALL_NOT_IMPLEMENTED)
225 win_skip("RegQueryValueExW() is not implemented\n");
226 return;
229 lok(type == REG_SZ, "RegQueryValueExW/1 returned type %d\n", type);
230 lok(cbData == full_byte_len,
231 "cbData=%d instead of %d\n", cbData, full_byte_len);
233 /* Give enough space to overflow by one WCHAR */
234 value = HeapAlloc(GetProcessHeap(), 0, cbData+2);
235 memset(value, 0xbd, cbData+2);
236 type=0xdeadbeef;
237 ret = RegQueryValueExW(hkey_main, name, NULL, &type, value, &cbData);
238 GLE = GetLastError();
239 lok(ret == ERROR_SUCCESS, "RegQueryValueExW/2 failed: %d, GLE=%d\n", ret, GLE);
240 if (string)
242 lok(memcmp(value, string, cbData) == 0, "RegQueryValueExW failed: %s/%d != %s/%d\n",
243 wine_dbgstr_wn((WCHAR*)value, cbData / sizeof(WCHAR)), cbData,
244 wine_dbgstr_wn(string, full_byte_len / sizeof(WCHAR)), full_byte_len);
246 /* This implies that when cbData == 0, RegQueryValueExW() should not modify the buffer */
247 lok(*(value+cbData) == 0xbd, "RegQueryValueExW/2 overflowed at %u: %02x != bd\n", cbData, *(value+cbData));
248 lok(*(value+cbData+1) == 0xbd, "RegQueryValueExW/2 overflowed at %u+1: %02x != bd\n", cbData, *(value+cbData+1));
249 HeapFree(GetProcessHeap(), 0, value);
252 static void test_set_value(void)
254 DWORD ret;
256 static const WCHAR name1W[] = L"CleanSingleString";
257 static const WCHAR name2W[] = L"SomeIntraZeroedString";
258 static const WCHAR emptyW[] = L"";
259 static const WCHAR string1W[] = L"ThisNeverBreaks";
260 static const WCHAR string2W[] = L"This\0Breaks\0\0A\0\0\0Lot\0\0\0\0";
261 static const WCHAR substring2W[] = L"This";
263 static const char name1A[] = "CleanSingleString";
264 static const char name2A[] = "SomeIntraZeroedString";
265 static const char emptyA[] = "";
266 static const char string1A[] = "ThisNeverBreaks";
267 static const char string2A[] = "This\0Breaks\0\0A\0\0\0Lot\0\0\0\0";
268 static const char substring2A[] = "This";
270 if (0)
272 /* Crashes on NT4, Windows 2000 and XP SP1 */
273 ret = RegSetValueA(hkey_main, NULL, REG_SZ, NULL, 0);
274 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have failed with ERROR_INVALID_PARAMETER instead of %d\n", ret);
277 ret = RegSetValueA(hkey_main, NULL, REG_SZ, string1A, sizeof(string1A));
278 ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %d, GLE=%d\n", ret, GetLastError());
279 test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
280 test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
282 /* RegSetValueA ignores the size passed in */
283 ret = RegSetValueA(hkey_main, NULL, REG_SZ, string1A, 4);
284 ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %d, GLE=%d\n", ret, GetLastError());
285 test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
286 test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
288 /* stops at first null */
289 ret = RegSetValueA(hkey_main, NULL, REG_SZ, string2A, sizeof(string2A));
290 ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %d, GLE=%d\n", ret, GetLastError());
291 test_hkey_main_Value_A(NULL, substring2A, sizeof(substring2A));
292 test_hkey_main_Value_W(NULL, substring2W, sizeof(substring2W));
294 /* only REG_SZ is supported on NT*/
295 ret = RegSetValueA(hkey_main, NULL, REG_BINARY, string2A, sizeof(string2A));
296 ok(ret == ERROR_INVALID_PARAMETER, "got %d (expected ERROR_INVALID_PARAMETER)\n", ret);
298 ret = RegSetValueA(hkey_main, NULL, REG_EXPAND_SZ, string2A, sizeof(string2A));
299 ok(ret == ERROR_INVALID_PARAMETER, "got %d (expected ERROR_INVALID_PARAMETER)\n", ret);
301 ret = RegSetValueA(hkey_main, NULL, REG_MULTI_SZ, string2A, sizeof(string2A));
302 ok(ret == ERROR_INVALID_PARAMETER, "got %d (expected ERROR_INVALID_PARAMETER)\n", ret);
304 /* Test RegSetValueExA with a 'zero-byte' string (as Office 2003 does).
305 * Surprisingly enough we're supposed to get zero bytes out of it.
307 ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)emptyA, 0);
308 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
309 test_hkey_main_Value_A(name1A, NULL, 0);
310 test_hkey_main_Value_W(name1W, NULL, 0);
312 /* test RegSetValueExA with an empty string */
313 ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)emptyA, sizeof(emptyA));
314 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
315 test_hkey_main_Value_A(name1A, emptyA, sizeof(emptyA));
316 test_hkey_main_Value_W(name1W, emptyW, sizeof(emptyW));
318 /* test RegSetValueExA with off-by-one size */
319 ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)string1A, sizeof(string1A)-sizeof(string1A[0]));
320 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
321 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
322 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
324 /* test RegSetValueExA with normal string */
325 ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)string1A, sizeof(string1A));
326 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
327 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
328 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
330 /* test RegSetValueExA with intrazeroed string */
331 ret = RegSetValueExA(hkey_main, name2A, 0, REG_SZ, (const BYTE *)string2A, sizeof(string2A));
332 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
333 test_hkey_main_Value_A(name2A, string2A, sizeof(string2A));
334 test_hkey_main_Value_W(name2W, string2W, sizeof(string2W));
336 if (0)
338 /* Crashes on NT4, Windows 2000 and XP SP1 */
339 ret = RegSetValueW(hkey_main, NULL, REG_SZ, NULL, 0);
340 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have failed with ERROR_INVALID_PARAMETER instead of %d\n", ret);
342 RegSetValueExA(hkey_main, name2A, 0, REG_SZ, (const BYTE *)1, 1);
343 RegSetValueExA(hkey_main, name2A, 0, REG_DWORD, (const BYTE *)1, 1);
346 ret = RegSetValueW(hkey_main, NULL, REG_SZ, string1W, sizeof(string1W));
347 ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %d, GLE=%d\n", ret, GetLastError());
348 test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
349 test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
351 ret = RegSetValueW(hkey_main, name1W, REG_SZ, string1W, sizeof(string1W));
352 ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %d, GLE=%d\n", ret, GetLastError());
353 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
354 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
356 /* RegSetValueW ignores the size passed in */
357 ret = RegSetValueW(hkey_main, NULL, REG_SZ, string1W, 4 * sizeof(string1W[0]));
358 ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %d, GLE=%d\n", ret, GetLastError());
359 test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
360 test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
362 /* stops at first null */
363 ret = RegSetValueW(hkey_main, NULL, REG_SZ, string2W, sizeof(string2W));
364 ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %d, GLE=%d\n", ret, GetLastError());
365 test_hkey_main_Value_A(NULL, substring2A, sizeof(substring2A));
366 test_hkey_main_Value_W(NULL, substring2W, sizeof(substring2W));
368 /* only REG_SZ is supported */
369 ret = RegSetValueW(hkey_main, NULL, REG_BINARY, string2W, sizeof(string2W));
370 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
371 ret = RegSetValueW(hkey_main, NULL, REG_EXPAND_SZ, string2W, sizeof(string2W));
372 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
373 ret = RegSetValueW(hkey_main, NULL, REG_MULTI_SZ, string2W, sizeof(string2W));
374 ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
376 /* test RegSetValueExW with off-by-one size */
377 ret = RegSetValueExW(hkey_main, name1W, 0, REG_SZ, (const BYTE *)string1W, sizeof(string1W)-sizeof(string1W[0]));
378 ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %d, GLE=%d\n", ret, GetLastError());
379 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
380 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
382 /* test RegSetValueExW with normal string */
383 ret = RegSetValueExW(hkey_main, name1W, 0, REG_SZ, (const BYTE *)string1W, sizeof(string1W));
384 ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %d, GLE=%d\n", ret, GetLastError());
385 test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
386 test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
388 /* test RegSetValueExW with intrazeroed string */
389 ret = RegSetValueExW(hkey_main, name2W, 0, REG_SZ, (const BYTE *)string2W, sizeof(string2W));
390 ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %d, GLE=%d\n", ret, GetLastError());
391 test_hkey_main_Value_A(name2A, string2A, sizeof(string2A));
392 test_hkey_main_Value_W(name2W, string2W, sizeof(string2W));
394 /* test RegSetValueExW with data = 1 */
395 ret = RegSetValueExW(hkey_main, name2W, 0, REG_SZ, (const BYTE *)1, 1);
396 ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %d, GLE=%d\n", ret, GetLastError());
397 ret = RegSetValueExW(hkey_main, name2W, 0, REG_DWORD, (const BYTE *)1, 1);
398 ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %d, GLE=%d\n", ret, GetLastError());
400 if (pRegGetValueA) /* avoid a crash on Windows 2000 */
402 ret = RegSetValueExW(hkey_main, NULL, 0, REG_SZ, NULL, 4);
403 ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %d, GLE=%d\n", ret, GetLastError());
405 ret = RegSetValueExW(hkey_main, NULL, 0, REG_SZ, NULL, 0);
406 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
408 ret = RegSetValueExW(hkey_main, NULL, 0, REG_DWORD, NULL, 4);
409 ok(ret == ERROR_NOACCESS, "RegSetValueExW should have failed with ERROR_NOACCESS: %d, GLE=%d\n", ret, GetLastError());
411 ret = RegSetValueExW(hkey_main, NULL, 0, REG_DWORD, NULL, 0);
412 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
415 /* RegSetKeyValue */
416 if (!pRegSetKeyValueW)
417 win_skip("RegSetKeyValue() is not supported.\n");
418 else
420 DWORD len, type;
421 HKEY subkey;
423 ret = pRegSetKeyValueW(hkey_main, NULL, name1W, REG_SZ, (const BYTE*)string2W, sizeof(string2W));
424 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
425 test_hkey_main_Value_A(name1A, string2A, sizeof(string2A));
426 test_hkey_main_Value_W(name1W, string2W, sizeof(string2W));
428 ret = pRegSetKeyValueW(hkey_main, L"subkey", name1W, REG_SZ, string1W, sizeof(string1W));
429 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
431 ret = RegOpenKeyExW(hkey_main, L"subkey", 0, KEY_QUERY_VALUE, &subkey);
432 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
433 type = len = 0;
434 ret = RegQueryValueExW(subkey, name1W, 0, &type, NULL, &len);
435 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
436 ok(len == sizeof(string1W), "got %d\n", len);
437 ok(type == REG_SZ, "got type %d\n", type);
439 ret = pRegSetKeyValueW(hkey_main, L"subkey", name1W, REG_SZ, NULL, 0);
440 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
442 ret = pRegSetKeyValueW(hkey_main, L"subkey", name1W, REG_SZ, NULL, 4);
443 ok(ret == ERROR_NOACCESS, "got %d\n", ret);
445 ret = pRegSetKeyValueW(hkey_main, L"subkey", name1W, REG_DWORD, NULL, 4);
446 ok(ret == ERROR_NOACCESS, "got %d\n", ret);
448 RegCloseKey(subkey);
452 static void create_test_entries(void)
454 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
456 SetEnvironmentVariableA("LONGSYSTEMVAR", "bar");
457 SetEnvironmentVariableA("FOO", "ImARatherLongButIndeedNeededString");
459 ok(!RegSetValueExA(hkey_main,"TP1_EXP_SZ",0,REG_EXPAND_SZ, (const BYTE *)sTestpath1, strlen(sTestpath1)+1),
460 "RegSetValueExA failed\n");
461 ok(!RegSetValueExA(hkey_main,"TP1_SZ",0,REG_SZ, (const BYTE *)sTestpath1, strlen(sTestpath1)+1),
462 "RegSetValueExA failed\n");
463 ok(!RegSetValueExA(hkey_main,"TP1_ZB_SZ",0,REG_SZ, (const BYTE *)"", 0),
464 "RegSetValueExA failed\n");
465 ok(!RegSetValueExA(hkey_main,"TP2_EXP_SZ",0,REG_EXPAND_SZ, (const BYTE *)sTestpath2, strlen(sTestpath2)+1),
466 "RegSetValueExA failed\n");
467 ok(!RegSetValueExA(hkey_main,"DWORD",0,REG_DWORD, (const BYTE *)qw, 4),
468 "RegSetValueExA failed\n");
469 ok(!RegSetValueExA(hkey_main,"BIN32",0,REG_BINARY, (const BYTE *)qw, 4),
470 "RegSetValueExA failed\n");
471 ok(!RegSetValueExA(hkey_main,"BIN64",0,REG_BINARY, (const BYTE *)qw, 8),
472 "RegSetValueExA failed\n");
475 static void test_enum_value(void)
477 DWORD res;
478 HKEY test_key;
479 char value[20], data[20];
480 WCHAR valueW[20], dataW[20];
481 DWORD val_count, data_count, type;
483 /* create the working key for new 'Test' value */
484 res = RegCreateKeyA( hkey_main, "TestKey", &test_key );
485 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res);
487 /* check NULL data with zero length */
488 res = RegSetValueExA( test_key, "Test", 0, REG_SZ, NULL, 0 );
489 if (GetVersion() & 0x80000000)
490 ok( res == ERROR_INVALID_PARAMETER, "RegSetValueExA returned %d\n", res );
491 else
492 ok( !res, "RegSetValueExA returned %d\n", res );
493 res = RegSetValueExA( test_key, "Test", 0, REG_EXPAND_SZ, NULL, 0 );
494 ok( ERROR_SUCCESS == res || ERROR_INVALID_PARAMETER == res, "RegSetValueExA returned %d\n", res );
495 res = RegSetValueExA( test_key, "Test", 0, REG_BINARY, NULL, 0 );
496 ok( ERROR_SUCCESS == res || ERROR_INVALID_PARAMETER == res, "RegSetValueExA returned %d\n", res );
498 /* test reading the value and data without setting them */
499 val_count = 20;
500 data_count = 20;
501 type = 1234;
502 strcpy( value, "xxxxxxxxxx" );
503 strcpy( data, "xxxxxxxxxx" );
504 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
505 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res );
506 ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
507 ok( data_count == 0, "data_count set to %d instead of 0\n", data_count );
508 ok( type == REG_BINARY, "type %d is not REG_BINARY\n", type );
509 ok( !strcmp( value, "Test" ), "value is '%s' instead of Test\n", value );
510 ok( !strcmp( data, "xxxxxxxxxx" ), "data is '%s' instead of xxxxxxxxxx\n", data );
512 val_count = 20;
513 data_count = 20;
514 type = 1234;
515 wcscpy( valueW, L"xxxxxxxx" );
516 wcscpy( dataW, L"xxxxxxxx" );
517 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
518 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res );
519 ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
520 ok( data_count == 0, "data_count set to %d instead of 0\n", data_count );
521 ok( type == REG_BINARY, "type %d is not REG_BINARY\n", type );
522 ok( !wcscmp( valueW, L"Test" ), "value is not 'Test'\n" );
523 ok( !wcscmp( dataW, L"xxxxxxxx" ), "data is not 'xxxxxxxx'\n" );
525 res = RegSetValueExA( test_key, "Test", 0, REG_SZ, (const BYTE *)"foobar", 7 );
526 ok( res == 0, "RegSetValueExA failed error %d\n", res );
528 /* overflow both name and data */
529 val_count = 2;
530 data_count = 2;
531 type = 1234;
532 strcpy( value, "xxxxxxxxxx" );
533 strcpy( data, "xxxxxxxxxx" );
534 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
535 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
536 ok( val_count == 2, "val_count set to %d\n", val_count );
537 ok( data_count == 7 || broken( data_count == 8 ), "data_count set to %d instead of 7\n", data_count );
538 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
539 ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
540 ok( !strcmp( data, "xxxxxxxxxx" ), "data set to '%s'\n", data );
542 /* overflow name */
543 val_count = 3;
544 data_count = 20;
545 type = 1234;
546 strcpy( value, "xxxxxxxxxx" );
547 strcpy( data, "xxxxxxxxxx" );
548 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
549 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
550 ok( val_count == 3, "val_count set to %d\n", val_count );
551 ok( data_count == 7 || broken( data_count == 8 ), "data_count set to %d instead of 7\n", data_count );
552 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
553 /* v5.1.2600.0 (XP Home and Professional) does not touch value or data in this case */
554 ok( !strcmp( value, "Te" ) || !strcmp( value, "xxxxxxxxxx" ),
555 "value set to '%s' instead of 'Te' or 'xxxxxxxxxx'\n", value );
556 ok( !strcmp( data, "foobar" ) || !strcmp( data, "xxxxxxx" ) || broken( !strcmp( data, "xxxxxxxx" ) && data_count == 8 ),
557 "data set to '%s' instead of 'foobar' or 'xxxxxxx'\n", data );
559 /* overflow empty name */
560 val_count = 0;
561 data_count = 20;
562 type = 1234;
563 strcpy( value, "xxxxxxxxxx" );
564 strcpy( data, "xxxxxxxxxx" );
565 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
566 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
567 ok( val_count == 0, "val_count set to %d\n", val_count );
568 ok( data_count == 7 || broken( data_count == 8 ), "data_count set to %d instead of 7\n", data_count );
569 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
570 ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
571 /* v5.1.2600.0 (XP Home and Professional) does not touch data in this case */
572 ok( !strcmp( data, "foobar" ) || !strcmp( data, "xxxxxxx" ) || broken( !strcmp( data, "xxxxxxxx" ) && data_count == 8 ),
573 "data set to '%s' instead of 'foobar' or 'xxxxxxx'\n", data );
575 /* overflow data */
576 val_count = 20;
577 data_count = 2;
578 type = 1234;
579 strcpy( value, "xxxxxxxxxx" );
580 strcpy( data, "xxxxxxxxxx" );
581 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
582 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
583 ok( val_count == 20, "val_count set to %d\n", val_count );
584 ok( data_count == 7, "data_count set to %d instead of 7\n", data_count );
585 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
586 ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
587 ok( !strcmp( data, "xxxxxxxxxx" ), "data set to '%s'\n", data );
589 /* no overflow */
590 val_count = 20;
591 data_count = 20;
592 type = 1234;
593 strcpy( value, "xxxxxxxxxx" );
594 strcpy( data, "xxxxxxxxxx" );
595 res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
596 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res );
597 ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
598 ok( data_count == 7, "data_count set to %d instead of 7\n", data_count );
599 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
600 ok( !strcmp( value, "Test" ), "value is '%s' instead of Test\n", value );
601 ok( !strcmp( data, "foobar" ), "data is '%s' instead of foobar\n", data );
603 if (pRegGetValueA) /* avoid a crash on Windows 2000 */
605 /* no value and no val_count parameter */
606 data_count = 20;
607 type = 1234;
608 strcpy( data, "xxxxxxxxxx" );
609 res = RegEnumValueA( test_key, 0, NULL, NULL, NULL, &type, (BYTE*)data, &data_count );
610 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
612 /* no value parameter */
613 val_count = 20;
614 data_count = 20;
615 type = 1234;
616 strcpy( data, "xxxxxxxxxx" );
617 res = RegEnumValueA( test_key, 0, NULL, &val_count, NULL, &type, (BYTE*)data, &data_count );
618 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
620 /* no val_count parameter */
621 data_count = 20;
622 type = 1234;
623 strcpy( value, "xxxxxxxxxx" );
624 strcpy( data, "xxxxxxxxxx" );
625 res = RegEnumValueA( test_key, 0, value, NULL, NULL, &type, (BYTE*)data, &data_count );
626 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
629 /* Unicode tests */
631 SetLastError(0xdeadbeef);
632 res = RegSetValueExW( test_key, L"Test", 0, REG_SZ, (const BYTE *)L"foobar", 7*sizeof(WCHAR) );
633 if (res==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
635 win_skip("RegSetValueExW is not implemented\n");
636 goto cleanup;
638 ok( res == 0, "RegSetValueExW failed error %d\n", res );
640 /* overflow both name and data */
641 val_count = 2;
642 data_count = 2;
643 type = 1234;
644 wcscpy( valueW, L"xxxxxxxx" );
645 wcscpy( dataW, L"xxxxxxxx" );
646 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
647 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
648 ok( val_count == 2, "val_count set to %d\n", val_count );
649 ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
650 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
651 ok( !wcscmp( valueW, L"xxxxxxxx" ), "value modified\n" );
652 ok( !wcscmp( dataW, L"xxxxxxxx" ), "data modified\n" );
654 /* overflow name */
655 val_count = 3;
656 data_count = 20;
657 type = 1234;
658 wcscpy( valueW, L"xxxxxxxx" );
659 wcscpy( dataW, L"xxxxxxxx" );
660 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
661 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
662 ok( val_count == 3, "val_count set to %d\n", val_count );
663 ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
664 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
665 ok( !wcscmp( valueW, L"xxxxxxxx" ), "value modified\n" );
666 ok( !wcscmp( dataW, L"xxxxxxxx" ), "data modified\n" );
668 /* overflow data */
669 val_count = 20;
670 data_count = 2;
671 type = 1234;
672 wcscpy( valueW, L"xxxxxxxx" );
673 wcscpy( dataW, L"xxxxxxxx" );
674 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
675 ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
676 ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
677 ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
678 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
679 ok( !wcscmp( valueW, L"Test" ), "value is not 'Test'\n" );
680 ok( !wcscmp( dataW, L"xxxxxxxx" ), "data modified\n" );
682 /* no overflow */
683 val_count = 20;
684 data_count = 20;
685 type = 1234;
686 wcscpy( valueW, L"xxxxxxxx" );
687 wcscpy( dataW, L"xxxxxxxx" );
688 res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
689 ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res );
690 ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
691 ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
692 ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
693 ok( !wcscmp( valueW, L"Test" ), "value is not 'Test'\n" );
694 ok( !wcscmp( dataW, L"foobar" ), "data is not 'foobar'\n" );
696 if (pRegGetValueA) /* avoid a crash on Windows 2000 */
698 /* no valueW and no val_count parameter */
699 data_count = 20;
700 type = 1234;
701 wcscpy( dataW, L"xxxxxxxx" );
702 res = RegEnumValueW( test_key, 0, NULL, NULL, NULL, &type, (BYTE*)dataW, &data_count );
703 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
705 /* no valueW parameter */
706 val_count = 20;
707 data_count = 20;
708 type = 1234;
709 wcscpy( dataW, L"xxxxxxxx" );
710 res = RegEnumValueW( test_key, 0, NULL, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
711 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
713 /* no val_count parameter */
714 data_count = 20;
715 type = 1234;
716 wcscpy( valueW, L"xxxxxxxx" );
717 wcscpy( dataW, L"xxxxxxxx" );
718 res = RegEnumValueW( test_key, 0, valueW, NULL, NULL, &type, (BYTE*)dataW, &data_count );
719 ok( res == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", res );
722 cleanup:
723 RegDeleteKeyA(test_key, "");
724 RegCloseKey(test_key);
727 static void test_query_value_ex(void)
729 DWORD ret, size, type;
730 BYTE buffer[10];
732 size = sizeof(buffer);
733 ret = RegQueryValueExA(hkey_main, "TP1_SZ", NULL, &type, NULL, &size);
734 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
735 ok(size == strlen(sTestpath1) + 1, "(%d,%d)\n", (DWORD)strlen(sTestpath1) + 1, size);
736 ok(type == REG_SZ, "type %d is not REG_SZ\n", type);
738 type = 0xdeadbeef;
739 size = 0xdeadbeef;
740 ret = RegQueryValueExA(HKEY_CLASSES_ROOT, "Nonexistent Value", NULL, &type, NULL, &size);
741 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
742 ok(size == 0, "size should have been set to 0 instead of %d\n", size);
744 size = sizeof(buffer);
745 ret = RegQueryValueExA(HKEY_CLASSES_ROOT, "Nonexistent Value", NULL, &type, buffer, &size);
746 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
747 ok(size == sizeof(buffer), "size shouldn't have been changed to %d\n", size);
749 size = 4;
750 ret = RegQueryValueExA(hkey_main, "BIN32", NULL, &size, buffer, &size);
751 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
754 static void test_get_value(void)
756 DWORD ret;
757 DWORD size;
758 DWORD type;
759 DWORD dw, qw[2];
760 CHAR buf[80];
761 CHAR expanded[] = "bar\\subdir1";
762 CHAR expanded2[] = "ImARatherLongButIndeedNeededString\\subdir1";
764 if(!pRegGetValueA)
766 win_skip("RegGetValue not available on this platform\n");
767 return;
770 /* Invalid parameter */
771 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD, &type, &dw, NULL);
772 ok(ret == ERROR_INVALID_PARAMETER, "ret=%d\n", ret);
774 /* Query REG_DWORD using RRF_RT_REG_DWORD (ok) */
775 size = type = dw = 0xdeadbeef;
776 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD, &type, &dw, &size);
777 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
778 ok(size == 4, "size=%d\n", size);
779 ok(type == REG_DWORD, "type=%d\n", type);
780 ok(dw == 0x12345678, "dw=%d\n", dw);
782 /* Check RRF_SUBKEY_WOW64*KEY validation on a case without a subkey */
783 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY | RRF_SUBKEY_WOW6432KEY, NULL, NULL, NULL);
784 ok(ret == ERROR_INVALID_PARAMETER || broken(ret == ERROR_SUCCESS), /* Before Win10 */
785 "ret=%d\n", ret);
786 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY, NULL, NULL, NULL);
787 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
788 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6432KEY, NULL, NULL, NULL);
789 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
791 /* Query by subkey-name */
792 ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD, NULL, NULL, NULL);
793 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
795 /* Check RRF_SUBKEY_WOW64*KEY validation on a case with a subkey */
796 ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY | RRF_SUBKEY_WOW6432KEY, NULL, NULL, NULL);
797 ok(ret == ERROR_INVALID_PARAMETER || broken(ret == ERROR_SUCCESS), /* Before Win10 */
798 "ret=%d\n", ret);
799 ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY, NULL, NULL, NULL);
800 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
801 ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6432KEY, NULL, NULL, NULL);
802 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
804 /* Query REG_DWORD using RRF_RT_REG_BINARY (restricted) */
805 size = type = dw = 0xdeadbeef;
806 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_BINARY, &type, &dw, &size);
807 ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
808 /* Although the function failed all values are retrieved */
809 ok(size == 4, "size=%d\n", size);
810 ok(type == REG_DWORD, "type=%d\n", type);
811 ok(dw == 0x12345678, "dw=%d\n", dw);
813 /* Test RRF_ZEROONFAILURE */
814 type = dw = 0xdeadbeef; size = 4;
815 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_SZ|RRF_ZEROONFAILURE, &type, &dw, &size);
816 ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
817 /* Again all values are retrieved ... */
818 ok(size == 4, "size=%d\n", size);
819 ok(type == REG_DWORD, "type=%d\n", type);
820 /* ... except the buffer, which is zeroed out */
821 ok(dw == 0, "dw=%d\n", dw);
823 /* Test RRF_ZEROONFAILURE with a NULL buffer... */
824 type = size = 0xbadbeef;
825 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_SZ|RRF_ZEROONFAILURE, &type, NULL, &size);
826 ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
827 ok(size == 4, "size=%d\n", size);
828 ok(type == REG_DWORD, "type=%d\n", type);
830 /* Query REG_DWORD using RRF_RT_DWORD (ok) */
831 size = type = dw = 0xdeadbeef;
832 ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_DWORD, &type, &dw, &size);
833 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
834 ok(size == 4, "size=%d\n", size);
835 ok(type == REG_DWORD, "type=%d\n", type);
836 ok(dw == 0x12345678, "dw=%d\n", dw);
838 /* Query 32-bit REG_BINARY using RRF_RT_DWORD (ok) */
839 size = type = dw = 0xdeadbeef;
840 ret = pRegGetValueA(hkey_main, NULL, "BIN32", RRF_RT_DWORD, &type, &dw, &size);
841 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
842 ok(size == 4, "size=%d\n", size);
843 ok(type == REG_BINARY, "type=%d\n", type);
844 ok(dw == 0x12345678, "dw=%d\n", dw);
846 /* Query 64-bit REG_BINARY using RRF_RT_DWORD (type mismatch) */
847 qw[0] = qw[1] = size = type = 0xdeadbeef;
848 ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_DWORD, &type, qw, &size);
849 ok(ret == ERROR_DATATYPE_MISMATCH, "ret=%d\n", ret);
850 ok(size == 8, "size=%d\n", size);
851 ok(type == REG_BINARY, "type=%d\n", type);
852 ok(qw[0] == 0x12345678 &&
853 qw[1] == 0x87654321, "qw={%d,%d}\n", qw[0], qw[1]);
855 /* Query 64-bit REG_BINARY using 32-bit buffer (buffer too small) */
856 type = dw = 0xdeadbeef; size = 4;
857 ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_REG_BINARY, &type, &dw, &size);
858 ok(ret == ERROR_MORE_DATA, "ret=%d\n", ret);
859 ok(dw == 0xdeadbeef, "dw=%d\n", dw);
860 ok(size == 8, "size=%d\n", size);
862 /* Query 64-bit REG_BINARY using RRF_RT_QWORD (ok) */
863 qw[0] = qw[1] = size = type = 0xdeadbeef;
864 ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_QWORD, &type, qw, &size);
865 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
866 ok(size == 8, "size=%d\n", size);
867 ok(type == REG_BINARY, "type=%d\n", type);
868 ok(qw[0] == 0x12345678 &&
869 qw[1] == 0x87654321, "qw={%d,%d}\n", qw[0], qw[1]);
871 /* Query REG_SZ using RRF_RT_REG_SZ (ok) */
872 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
873 ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ, &type, buf, &size);
874 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
875 ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
876 ok(type == REG_SZ, "type=%d\n", type);
877 ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
879 /* Query REG_SZ using RRF_RT_REG_SZ and no buffer (ok) */
880 type = 0xdeadbeef; size = 0;
881 ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ, &type, NULL, &size);
882 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
883 /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
884 ok(size == strlen(sTestpath1)+1 || broken(size == strlen(sTestpath1)+2),
885 "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
886 ok(type == REG_SZ, "type=%d\n", type);
888 /* Query REG_SZ using RRF_RT_REG_SZ on a zero-byte value (ok) */
889 strcpy(buf, sTestpath1);
890 type = 0xdeadbeef;
891 size = sizeof(buf);
892 ret = pRegGetValueA(hkey_main, NULL, "TP1_ZB_SZ", RRF_RT_REG_SZ, &type, buf, &size);
893 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
894 /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
895 ok(size == 0 ||
896 size == 1, /* win2k3 */
897 "size=%d\n", size);
898 ok(type == REG_SZ, "type=%d\n", type);
899 ok(!strcmp(sTestpath1, buf) ||
900 !strcmp(buf, ""),
901 "Expected \"%s\" or \"\", got \"%s\"\n", sTestpath1, buf);
903 /* Query REG_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (ok) */
904 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
905 ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ|RRF_NOEXPAND, &type, buf, &size);
906 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
907 ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
908 ok(type == REG_SZ, "type=%d\n", type);
909 ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
911 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ and no buffer (ok, expands) */
912 size = 0;
913 ret = pRegGetValueA(hkey_main, NULL, "TP2_EXP_SZ", RRF_RT_REG_SZ, NULL, NULL, &size);
914 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
915 ok((size == strlen(expanded2)+1) || /* win2k3 SP1 */
916 (size == strlen(expanded2)+2) || /* win2k3 SP2 */
917 (size == strlen(sTestpath2)+1),
918 "strlen(expanded2)=%d, strlen(sTestpath2)=%d, size=%d\n", lstrlenA(expanded2), lstrlenA(sTestpath2), size);
920 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ (ok, expands) */
921 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
922 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_SZ, &type, buf, &size);
923 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
924 /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath1 length + 1 here. */
925 ok(size == strlen(expanded)+1 || broken(size == strlen(sTestpath1)+1),
926 "strlen(expanded)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded), lstrlenA(sTestpath1), size);
927 ok(type == REG_SZ, "type=%d\n", type);
928 ok(!strcmp(expanded, buf), "expanded=\"%s\" buf=\"%s\"\n", expanded, buf);
930 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ (ok, expands a lot) */
931 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
932 ret = pRegGetValueA(hkey_main, NULL, "TP2_EXP_SZ", RRF_RT_REG_SZ, &type, buf, &size);
933 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
934 /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath2 length + 1 here. */
935 ok(size == strlen(expanded2)+1 || broken(size == strlen(sTestpath2)+1),
936 "strlen(expanded2)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded2), lstrlenA(sTestpath2), size);
937 ok(type == REG_SZ, "type=%d\n", type);
938 ok(!strcmp(expanded2, buf), "expanded2=\"%s\" buf=\"%s\"\n", expanded2, buf);
940 /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND (ok, doesn't expand) */
941 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
942 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND, &type, buf, &size);
943 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
944 ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
945 ok(type == REG_EXPAND_SZ, "type=%d\n", type);
946 ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
948 /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND and no buffer (ok, doesn't expand) */
949 size = 0xbadbeef;
950 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND, NULL, NULL, &size);
951 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
952 /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
953 ok(size == strlen(sTestpath1)+1 || broken(size == strlen(sTestpath1)+2),
954 "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
956 /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (type mismatch) */
957 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_SZ|RRF_NOEXPAND, NULL, NULL, NULL);
958 ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
960 /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ (not allowed without RRF_NOEXPAND) */
961 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ, NULL, NULL, NULL);
962 /* before win8: ERROR_INVALID_PARAMETER, win8: ERROR_UNSUPPORTED_TYPE */
963 ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
965 /* Query REG_EXPAND_SZ using RRF_RT_ANY */
966 buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
967 ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_ANY, &type, buf, &size);
968 ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
969 /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath1 length + 1 here. */
970 ok(size == strlen(expanded)+1 || broken(size == strlen(sTestpath1)+1),
971 "strlen(expanded)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded), lstrlenA(sTestpath1), size);
972 ok(type == REG_SZ, "type=%d\n", type);
973 ok(!strcmp(expanded, buf), "expanded=\"%s\" buf=\"%s\"\n", expanded, buf);
976 static void test_reg_open_key(void)
978 DWORD ret = 0;
979 HKEY hkResult = NULL;
980 HKEY hkPreserve = NULL;
981 HKEY hkRoot64 = NULL;
982 HKEY hkRoot32 = NULL;
983 BOOL bRet;
984 SID_IDENTIFIER_AUTHORITY sid_authority = {SECURITY_WORLD_SID_AUTHORITY};
985 PSID world_sid;
986 EXPLICIT_ACCESSA access;
987 PACL key_acl;
988 SECURITY_DESCRIPTOR *sd;
990 /* successful open */
991 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
992 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
993 ok(hkResult != NULL, "expected hkResult != NULL\n");
994 hkPreserve = hkResult;
996 /* open same key twice */
997 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
998 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
999 ok(hkResult != hkPreserve, "expected hkResult != hkPreserve\n");
1000 ok(hkResult != NULL, "hkResult != NULL\n");
1001 RegCloseKey(hkResult);
1003 /* trailing slashes */
1004 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test\\\\", &hkResult);
1005 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1006 RegCloseKey(hkResult);
1008 /* open nonexistent key
1009 * check that hkResult is set to NULL
1011 hkResult = hkPreserve;
1012 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Nonexistent", &hkResult);
1013 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
1014 ok(hkResult == NULL, "expected hkResult == NULL\n");
1016 /* open the same nonexistent key again to make sure the key wasn't created */
1017 hkResult = hkPreserve;
1018 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Nonexistent", &hkResult);
1019 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
1020 ok(hkResult == NULL, "expected hkResult == NULL\n");
1022 /* send in NULL lpSubKey
1023 * check that hkResult receives the value of hKey
1025 hkResult = hkPreserve;
1026 ret = RegOpenKeyA(HKEY_CURRENT_USER, NULL, &hkResult);
1027 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1028 ok(hkResult == HKEY_CURRENT_USER, "expected hkResult == HKEY_CURRENT_USER\n");
1030 /* send empty-string in lpSubKey */
1031 hkResult = hkPreserve;
1032 ret = RegOpenKeyA(HKEY_CURRENT_USER, "", &hkResult);
1033 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1034 ok(hkResult == HKEY_CURRENT_USER, "expected hkResult == HKEY_CURRENT_USER\n");
1036 /* send in NULL lpSubKey and NULL hKey
1037 * hkResult is set to NULL
1039 hkResult = hkPreserve;
1040 ret = RegOpenKeyA(NULL, NULL, &hkResult);
1041 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1042 ok(hkResult == NULL, "expected hkResult == NULL\n");
1044 /* only send NULL hKey
1045 * the value of hkResult remains unchanged
1047 hkResult = hkPreserve;
1048 ret = RegOpenKeyA(NULL, "Software\\Wine\\Test", &hkResult);
1049 ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 95 returns BADKEY */
1050 "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
1051 ok(hkResult == hkPreserve, "expected hkResult == hkPreserve\n");
1053 /* send in NULL hkResult */
1054 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", NULL);
1055 ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", ret);
1057 ret = RegOpenKeyA(HKEY_CURRENT_USER, NULL, NULL);
1058 ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", ret);
1060 ret = RegOpenKeyA(NULL, NULL, NULL);
1061 ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", ret);
1063 /* beginning backslash character */
1064 ret = RegOpenKeyA(HKEY_CURRENT_USER, "\\Software\\Wine\\Test", &hkResult);
1065 ok(ret == ERROR_BAD_PATHNAME || /* NT/2k/XP */
1066 broken(ret == ERROR_SUCCESS), /* wow64 */
1067 "expected ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret);
1068 if (!ret) RegCloseKey(hkResult);
1070 hkResult = NULL;
1071 ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "\\clsid", 0, KEY_QUERY_VALUE, &hkResult);
1072 ok(ret == ERROR_SUCCESS || /* 2k/XP */
1073 ret == ERROR_BAD_PATHNAME, /* NT */
1074 "expected ERROR_SUCCESS, ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret);
1075 RegCloseKey(hkResult);
1077 /* NULL or empty subkey of special root */
1078 hkResult = NULL;
1079 ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, NULL, 0, KEY_QUERY_VALUE, &hkResult);
1080 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1081 ok(hkResult == HKEY_CLASSES_ROOT, "expected hkResult == HKEY_CLASSES_ROOT\n");
1083 hkResult = NULL;
1084 ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "", 0, KEY_QUERY_VALUE, &hkResult);
1085 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1086 ok(hkResult == HKEY_CLASSES_ROOT, "expected hkResult == HKEY_CLASSES_ROOT\n");
1088 hkResult = NULL;
1089 ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "\\", 0, KEY_QUERY_VALUE, &hkResult);
1090 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1091 ok(hkResult != HKEY_CLASSES_ROOT, "expected hkResult to be a new key\n");
1092 ok(!RegCloseKey(hkResult), "got invalid hkey\n");
1094 /* empty subkey of existing handle */
1095 hkResult = hkPreserve;
1096 ret = RegOpenKeyExA(hkPreserve, "", 0, KEY_QUERY_VALUE, &hkResult);
1097 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1098 ok(hkResult != hkPreserve, "expected hkResult != hkPreserve\n");
1099 ok(!RegCloseKey(hkResult), "got invalid hkey\n");
1101 /* NULL subkey of existing handle */
1102 hkResult = hkPreserve;
1103 ret = RegOpenKeyExA(hkPreserve, NULL, 0, KEY_QUERY_VALUE, &hkResult);
1104 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1105 ok(hkResult != hkPreserve, "expected hkResult != hkPreserve\n");
1106 ok(!RegCloseKey(hkResult), "got invalid hkey\n");
1108 /* empty subkey of NULL */
1109 hkResult = hkPreserve;
1110 ret = RegOpenKeyExW(NULL, L"", 0, KEY_QUERY_VALUE, &hkResult);
1111 ok(ret == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", ret);
1112 ok(hkResult == NULL || broken(hkResult == hkPreserve /* Windows XP */), "expected hkResult == NULL\n");
1114 hkResult = hkPreserve;
1115 ret = RegOpenKeyExA(NULL, "", 0, KEY_QUERY_VALUE, &hkResult);
1116 ok(ret == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", ret);
1117 ok(hkResult == hkPreserve, "expected hkResult == hkPreserve\n");
1119 RegCloseKey(hkPreserve);
1121 /* WOW64 flags */
1122 hkResult = NULL;
1123 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WOW64_32KEY, &hkResult);
1124 ok((ret == ERROR_SUCCESS && hkResult != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */),
1125 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
1126 RegCloseKey(hkResult);
1128 hkResult = NULL;
1129 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WOW64_64KEY, &hkResult);
1130 ok((ret == ERROR_SUCCESS && hkResult != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */),
1131 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
1132 RegCloseKey(hkResult);
1134 /* check special HKEYs on 64bit
1135 * only the lower 4 bytes of the supplied key are used
1137 if (ptr_size == 64)
1139 /* HKEY_CURRENT_USER */
1140 ret = RegOpenKeyA(UlongToHandle(HandleToUlong(HKEY_CURRENT_USER)), "Software", &hkResult);
1141 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1142 ok(hkResult != NULL, "expected hkResult != NULL\n");
1143 RegCloseKey(hkResult);
1145 ret = RegOpenKeyA((HKEY)(HandleToUlong(HKEY_CURRENT_USER) | (ULONG64)1 << 32), "Software", &hkResult);
1146 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1147 ok(hkResult != NULL, "expected hkResult != NULL\n");
1148 RegCloseKey(hkResult);
1150 ret = RegOpenKeyA((HKEY)(HandleToUlong(HKEY_CURRENT_USER) | (ULONG64)0xdeadbeef << 32), "Software", &hkResult);
1151 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1152 ok(hkResult != NULL, "expected hkResult != NULL\n");
1153 RegCloseKey(hkResult);
1155 ret = RegOpenKeyA((HKEY)(HandleToUlong(HKEY_CURRENT_USER) | (ULONG64)0xffffffff << 32), "Software", &hkResult);
1156 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1157 ok(hkResult != NULL, "expected hkResult != NULL\n");
1158 RegCloseKey(hkResult);
1160 /* HKEY_LOCAL_MACHINE */
1161 ret = RegOpenKeyA((HKEY)(HandleToUlong(HKEY_LOCAL_MACHINE) | (ULONG64)0xdeadbeef << 32), "Software", &hkResult);
1162 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1163 ok(hkResult != NULL, "expected hkResult != NULL\n");
1164 RegCloseKey(hkResult);
1167 /* Try using WOW64 flags when opening a key with a DACL set to verify that
1168 * the registry access check is performed correctly. Redirection isn't
1169 * being tested, so the tests don't care about whether the process is
1170 * running under WOW64. */
1171 if (!pIsWow64Process)
1173 win_skip("WOW64 flags are not recognized\n");
1174 return;
1177 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1178 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &hkRoot32, NULL);
1179 if (limited_user)
1180 ok(ret == ERROR_ACCESS_DENIED && hkRoot32 == NULL,
1181 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
1182 else
1183 ok(ret == ERROR_SUCCESS && hkRoot32 != NULL,
1184 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
1186 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1187 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &hkRoot64, NULL);
1188 if (limited_user)
1189 ok(ret == ERROR_ACCESS_DENIED && hkRoot64 == NULL,
1190 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
1191 else
1192 ok(ret == ERROR_SUCCESS && hkRoot64 != NULL,
1193 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
1195 bRet = AllocateAndInitializeSid(&sid_authority, 1, SECURITY_WORLD_RID,
1196 0, 0, 0, 0, 0, 0, 0, &world_sid);
1197 ok(bRet == TRUE,
1198 "Expected AllocateAndInitializeSid to return TRUE, got %d, last error %u\n", bRet, GetLastError());
1200 access.grfAccessPermissions = GENERIC_ALL | STANDARD_RIGHTS_ALL;
1201 access.grfAccessMode = SET_ACCESS;
1202 access.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
1203 access.Trustee.pMultipleTrustee = NULL;
1204 access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1205 access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
1206 access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
1207 access.Trustee.ptstrName = (char *)world_sid;
1209 ret = SetEntriesInAclA(1, &access, NULL, &key_acl);
1210 ok(ret == ERROR_SUCCESS,
1211 "Expected SetEntriesInAclA to return ERROR_SUCCESS, got %u, last error %u\n", ret, GetLastError());
1213 sd = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
1214 bRet = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
1215 ok(bRet == TRUE,
1216 "Expected InitializeSecurityDescriptor to return TRUE, got %d, last error %u\n", bRet, GetLastError());
1218 bRet = SetSecurityDescriptorDacl(sd, TRUE, key_acl, FALSE);
1219 ok(bRet == TRUE,
1220 "Expected SetSecurityDescriptorDacl to return TRUE, got %d, last error %u\n", bRet, GetLastError());
1222 if (limited_user)
1224 skip("not enough privileges to modify HKLM\n");
1226 else
1228 LONG error;
1230 error = RegSetKeySecurity(hkRoot64, DACL_SECURITY_INFORMATION, sd);
1231 ok(error == ERROR_SUCCESS,
1232 "Expected RegSetKeySecurity to return success, got error %u\n", error);
1234 error = RegSetKeySecurity(hkRoot32, DACL_SECURITY_INFORMATION, sd);
1235 ok(error == ERROR_SUCCESS,
1236 "Expected RegSetKeySecurity to return success, got error %u\n", error);
1238 hkResult = NULL;
1239 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_WOW64_64KEY | KEY_READ, &hkResult);
1240 ok(ret == ERROR_SUCCESS && hkResult != NULL,
1241 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
1242 RegCloseKey(hkResult);
1244 hkResult = NULL;
1245 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_WOW64_32KEY | KEY_READ, &hkResult);
1246 ok(ret == ERROR_SUCCESS && hkResult != NULL,
1247 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
1248 RegCloseKey(hkResult);
1251 HeapFree(GetProcessHeap(), 0, sd);
1252 LocalFree(key_acl);
1253 FreeSid(world_sid);
1254 RegDeleteKeyA(hkRoot64, "");
1255 RegCloseKey(hkRoot64);
1256 RegDeleteKeyA(hkRoot32, "");
1257 RegCloseKey(hkRoot32);
1260 static void test_reg_create_key(void)
1262 LONG ret;
1263 HKEY hkey1, hkey2;
1264 HKEY hkRoot64 = NULL;
1265 HKEY hkRoot32 = NULL;
1266 DWORD dwRet;
1267 BOOL bRet;
1268 SID_IDENTIFIER_AUTHORITY sid_authority = {SECURITY_WORLD_SID_AUTHORITY};
1269 PSID world_sid;
1270 EXPLICIT_ACCESSA access;
1271 PACL key_acl;
1272 SECURITY_DESCRIPTOR *sd;
1274 ret = RegCreateKeyExA(hkey_main, "Subkey1", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
1275 ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
1276 /* should succeed: all versions of Windows ignore the access rights
1277 * to the parent handle */
1278 ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey2, NULL);
1279 ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
1281 /* clean up */
1282 RegDeleteKeyA(hkey2, "");
1283 RegDeleteKeyA(hkey1, "");
1284 RegCloseKey(hkey2);
1285 RegCloseKey(hkey1);
1287 /* test creation of volatile keys */
1288 ret = RegCreateKeyExA(hkey_main, "Volatile", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey1, NULL);
1289 ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
1290 ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey2, NULL);
1291 ok(ret == ERROR_CHILD_MUST_BE_VOLATILE, "RegCreateKeyExA failed with error %d\n", ret);
1292 if (!ret) RegCloseKey( hkey2 );
1293 ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey2, NULL);
1294 ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
1295 RegCloseKey(hkey2);
1296 /* should succeed if the key already exists */
1297 ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey2, NULL);
1298 ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
1300 /* clean up */
1301 RegDeleteKeyA(hkey2, "");
1302 RegDeleteKeyA(hkey1, "");
1303 RegCloseKey(hkey2);
1304 RegCloseKey(hkey1);
1306 /* beginning backslash character */
1307 ret = RegCreateKeyExA(hkey_main, "\\Subkey3", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
1308 if (!(GetVersion() & 0x80000000))
1309 ok(ret == ERROR_BAD_PATHNAME, "expected ERROR_BAD_PATHNAME, got %d\n", ret);
1310 else {
1311 ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
1312 RegDeleteKeyA(hkey1, "");
1313 RegCloseKey(hkey1);
1316 /* trailing backslash characters */
1317 ret = RegCreateKeyExA(hkey_main, "Subkey4\\\\", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
1318 ok(ret == ERROR_SUCCESS, "RegCreateKeyExA failed with error %d\n", ret);
1319 RegDeleteKeyA(hkey1, "");
1320 RegCloseKey(hkey1);
1322 /* WOW64 flags - open an existing key */
1323 hkey1 = NULL;
1324 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0, KEY_READ|KEY_WOW64_32KEY, NULL, &hkey1, NULL);
1325 ok((ret == ERROR_SUCCESS && hkey1 != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */),
1326 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
1327 RegCloseKey(hkey1);
1329 hkey1 = NULL;
1330 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0, KEY_READ|KEY_WOW64_64KEY, NULL, &hkey1, NULL);
1331 ok((ret == ERROR_SUCCESS && hkey1 != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */),
1332 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
1333 RegCloseKey(hkey1);
1335 /* Try using WOW64 flags when opening a key with a DACL set to verify that
1336 * the registry access check is performed correctly. Redirection isn't
1337 * being tested, so the tests don't care about whether the process is
1338 * running under WOW64. */
1339 if (!pIsWow64Process)
1341 win_skip("WOW64 flags are not recognized\n");
1342 return;
1345 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1346 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &hkRoot32, NULL);
1347 if (limited_user)
1348 ok(ret == ERROR_ACCESS_DENIED && hkRoot32 == NULL,
1349 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%d)\n", ret);
1350 else
1351 ok(ret == ERROR_SUCCESS && hkRoot32 != NULL,
1352 "RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%d)\n", ret);
1354 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1355 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &hkRoot64, NULL);
1356 if (limited_user)
1357 ok(ret == ERROR_ACCESS_DENIED && hkRoot64 == NULL,
1358 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%d)\n", ret);
1359 else
1360 ok(ret == ERROR_SUCCESS && hkRoot64 != NULL,
1361 "RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%d)\n", ret);
1363 bRet = AllocateAndInitializeSid(&sid_authority, 1, SECURITY_WORLD_RID,
1364 0, 0, 0, 0, 0, 0, 0, &world_sid);
1365 ok(bRet == TRUE,
1366 "Expected AllocateAndInitializeSid to return TRUE, got %d, last error %u\n", bRet, GetLastError());
1368 access.grfAccessPermissions = GENERIC_ALL | STANDARD_RIGHTS_ALL;
1369 access.grfAccessMode = SET_ACCESS;
1370 access.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
1371 access.Trustee.pMultipleTrustee = NULL;
1372 access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1373 access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
1374 access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
1375 access.Trustee.ptstrName = (char *)world_sid;
1377 dwRet = SetEntriesInAclA(1, &access, NULL, &key_acl);
1378 ok(dwRet == ERROR_SUCCESS,
1379 "Expected SetEntriesInAclA to return ERROR_SUCCESS, got %u, last error %u\n", dwRet, GetLastError());
1381 sd = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
1382 bRet = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
1383 ok(bRet == TRUE,
1384 "Expected InitializeSecurityDescriptor to return TRUE, got %d, last error %u\n", bRet, GetLastError());
1386 bRet = SetSecurityDescriptorDacl(sd, TRUE, key_acl, FALSE);
1387 ok(bRet == TRUE,
1388 "Expected SetSecurityDescriptorDacl to return TRUE, got %d, last error %u\n", bRet, GetLastError());
1390 if (limited_user)
1392 skip("not enough privileges to modify HKLM\n");
1394 else
1396 ret = RegSetKeySecurity(hkRoot64, DACL_SECURITY_INFORMATION, sd);
1397 ok(ret == ERROR_SUCCESS,
1398 "Expected RegSetKeySecurity to return success, got error %u\n", ret);
1400 ret = RegSetKeySecurity(hkRoot32, DACL_SECURITY_INFORMATION, sd);
1401 ok(ret == ERROR_SUCCESS,
1402 "Expected RegSetKeySecurity to return success, got error %u\n", ret);
1404 hkey1 = NULL;
1405 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1406 KEY_WOW64_64KEY | KEY_READ, NULL, &hkey1, NULL);
1407 ok(ret == ERROR_SUCCESS && hkey1 != NULL,
1408 "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
1409 RegCloseKey(hkey1);
1411 hkey1 = NULL;
1412 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
1413 KEY_WOW64_32KEY | KEY_READ, NULL, &hkey1, NULL);
1414 ok(ret == ERROR_SUCCESS && hkey1 != NULL,
1415 "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
1416 RegCloseKey(hkey1);
1419 HeapFree(GetProcessHeap(), 0, sd);
1420 LocalFree(key_acl);
1421 FreeSid(world_sid);
1422 RegDeleteKeyA(hkRoot64, "");
1423 RegCloseKey(hkRoot64);
1424 RegDeleteKeyA(hkRoot32, "");
1425 RegCloseKey(hkRoot32);
1428 static void test_reg_close_key(void)
1430 DWORD ret = 0;
1431 HKEY hkHandle;
1433 /* successfully close key
1434 * hkHandle remains changed after call to RegCloseKey
1436 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkHandle);
1437 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1438 ret = RegCloseKey(hkHandle);
1439 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1441 /* try to close the key twice */
1442 ret = RegCloseKey(hkHandle); /* Windows 95 doesn't mind. */
1443 ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_SUCCESS,
1444 "expected ERROR_INVALID_HANDLE or ERROR_SUCCESS, got %d\n", ret);
1446 /* try to close a NULL handle */
1447 ret = RegCloseKey(NULL);
1448 ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 95 returns BADKEY */
1449 "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
1451 /* Check to see if we didn't potentially close our main handle, which could happen on win98 as
1452 * win98 doesn't give a new handle when the same key is opened.
1453 * Not re-opening will make some next tests fail.
1455 if (hkey_main == hkHandle)
1457 trace("The main handle is most likely closed, so re-opening\n");
1458 RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main );
1462 static void test_reg_delete_key(void)
1464 DWORD ret;
1465 HKEY key;
1467 ret = RegDeleteKeyA(hkey_main, NULL);
1469 /* There is a bug in NT4 and W2K that doesn't check if the subkey is NULL. If
1470 * there are also no subkeys available it will delete the key pointed to by hkey_main.
1471 * Not re-creating will make some next tests fail.
1473 if (ret == ERROR_SUCCESS)
1475 trace("We are probably running on NT4 or W2K as the main key is deleted,"
1476 " re-creating the main key\n");
1477 setup_main_key();
1479 else
1480 ok(ret == ERROR_INVALID_PARAMETER ||
1481 ret == ERROR_ACCESS_DENIED ||
1482 ret == ERROR_BADKEY, /* Win95 */
1483 "ret=%d\n", ret);
1485 ret = RegCreateKeyA(hkey_main, "deleteme", &key);
1486 ok(ret == ERROR_SUCCESS, "Could not create key, got %d\n", ret);
1487 ret = RegDeleteKeyA(key, "");
1488 ok(ret == ERROR_SUCCESS, "RegDeleteKeyA failed, got %d\n", ret);
1489 RegCloseKey(key);
1490 ret = RegOpenKeyA(hkey_main, "deleteme", &key);
1491 ok(ret == ERROR_FILE_NOT_FOUND, "Key was not deleted, got %d\n", ret);
1492 RegCloseKey(key);
1495 static BOOL set_privileges(LPCSTR privilege, BOOL set)
1497 TOKEN_PRIVILEGES tp;
1498 HANDLE hToken;
1499 LUID luid;
1501 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
1502 return FALSE;
1504 if(!LookupPrivilegeValueA(NULL, privilege, &luid))
1506 CloseHandle(hToken);
1507 return FALSE;
1510 tp.PrivilegeCount = 1;
1511 tp.Privileges[0].Luid = luid;
1513 if (set)
1514 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1515 else
1516 tp.Privileges[0].Attributes = 0;
1518 AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
1519 if (GetLastError() != ERROR_SUCCESS)
1521 CloseHandle(hToken);
1522 return FALSE;
1525 CloseHandle(hToken);
1526 return TRUE;
1529 static void test_reg_save_key(void)
1531 DWORD ret;
1533 if (!set_privileges(SE_BACKUP_NAME, TRUE) ||
1534 !set_privileges(SE_RESTORE_NAME, FALSE))
1536 win_skip("Failed to set SE_BACKUP_NAME privileges, skipping tests\n");
1537 return;
1540 ret = RegSaveKeyA(hkey_main, "saved_key", NULL);
1541 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1543 set_privileges(SE_BACKUP_NAME, FALSE);
1546 static void test_reg_load_key(void)
1548 DWORD ret;
1549 HKEY hkHandle;
1551 if (!set_privileges(SE_RESTORE_NAME, TRUE) ||
1552 !set_privileges(SE_BACKUP_NAME, FALSE))
1554 win_skip("Failed to set SE_RESTORE_NAME privileges, skipping tests\n");
1555 return;
1558 ret = RegLoadKeyA(HKEY_LOCAL_MACHINE, "Test", "saved_key");
1559 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1561 set_privileges(SE_RESTORE_NAME, FALSE);
1563 ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, "Test", &hkHandle);
1564 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1566 RegCloseKey(hkHandle);
1569 static void test_reg_unload_key(void)
1571 UNICODE_STRING key_name;
1572 OBJECT_ATTRIBUTES attr;
1573 NTSTATUS status;
1574 DWORD ret;
1575 HKEY key;
1577 if (!set_privileges(SE_RESTORE_NAME, TRUE) ||
1578 !set_privileges(SE_BACKUP_NAME, FALSE))
1580 win_skip("Failed to set SE_RESTORE_NAME privileges, skipping tests\n");
1581 return;
1584 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Test", 0, KEY_READ, &key);
1585 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1587 /* try to unload though the key handle is live */
1588 pRtlInitUnicodeString(&key_name, L"\\REGISTRY\\Machine\\Test");
1589 InitializeObjectAttributes(&attr, &key_name, OBJ_CASE_INSENSITIVE, NULL, NULL);
1590 status = pNtUnloadKey(&attr);
1591 ok(status == STATUS_CANNOT_DELETE, "expected STATUS_CANNOT_DELETE, got %08x\n", status);
1593 RegCloseKey(key);
1595 ret = RegUnLoadKeyA(HKEY_LOCAL_MACHINE, "Test");
1596 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
1598 set_privileges(SE_RESTORE_NAME, FALSE);
1600 DeleteFileA("saved_key");
1601 DeleteFileA("saved_key.LOG");
1604 /* tests that show that RegConnectRegistry and
1605 OpenSCManager accept computer names without the
1606 \\ prefix (what MSDN says). */
1607 static void test_regconnectregistry( void)
1609 CHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
1610 CHAR netwName[MAX_COMPUTERNAME_LENGTH + 3]; /* 2 chars for double backslash */
1611 DWORD len = sizeof(compName) ;
1612 BOOL ret;
1613 LONG retl;
1614 HKEY hkey;
1615 SC_HANDLE schnd;
1617 SetLastError(0xdeadbeef);
1618 ret = GetComputerNameA(compName, &len);
1619 ok( ret, "GetComputerName failed err = %d\n", GetLastError());
1620 if( !ret) return;
1622 lstrcpyA(netwName, "\\\\");
1623 lstrcpynA(netwName+2, compName, MAX_COMPUTERNAME_LENGTH + 1);
1625 retl = RegConnectRegistryA( compName, HKEY_LOCAL_MACHINE, &hkey);
1626 ok( !retl ||
1627 retl == ERROR_DLL_INIT_FAILED ||
1628 retl == ERROR_BAD_NETPATH, /* some win2k */
1629 "RegConnectRegistryA failed err = %d\n", retl);
1630 if( !retl) RegCloseKey( hkey);
1632 retl = RegConnectRegistryA( netwName, HKEY_LOCAL_MACHINE, &hkey);
1633 ok( !retl ||
1634 retl == ERROR_DLL_INIT_FAILED ||
1635 retl == ERROR_BAD_NETPATH, /* some win2k */
1636 "RegConnectRegistryA failed err = %d\n", retl);
1637 if( !retl) RegCloseKey( hkey);
1639 SetLastError(0xdeadbeef);
1640 schnd = OpenSCManagerA( compName, NULL, GENERIC_READ);
1641 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1643 win_skip("OpenSCManagerA is not implemented\n");
1644 return;
1647 ok( schnd != NULL, "OpenSCManagerA failed err = %d\n", GetLastError());
1648 CloseServiceHandle( schnd);
1650 SetLastError(0xdeadbeef);
1651 schnd = OpenSCManagerA( netwName, NULL, GENERIC_READ);
1652 ok( schnd != NULL, "OpenSCManagerA failed err = %d\n", GetLastError());
1653 CloseServiceHandle( schnd);
1657 static void test_reg_query_value(void)
1659 HKEY subkey;
1660 CHAR val[MAX_PATH];
1661 WCHAR valW[5];
1662 LONG size, ret;
1664 ret = RegCreateKeyA(hkey_main, "subkey", &subkey);
1665 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1667 ret = RegSetValueA(subkey, NULL, REG_SZ, "data", 4);
1668 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1670 /* try an invalid hkey */
1671 SetLastError(0xdeadbeef);
1672 size = MAX_PATH;
1673 ret = RegQueryValueA((HKEY)0xcafebabe, "subkey", val, &size);
1674 ok(ret == ERROR_INVALID_HANDLE ||
1675 ret == ERROR_BADKEY || /* Windows 98 returns BADKEY */
1676 ret == ERROR_ACCESS_DENIED, /* non-admin winxp */
1677 "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
1678 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1680 /* try a NULL hkey */
1681 SetLastError(0xdeadbeef);
1682 size = MAX_PATH;
1683 ret = RegQueryValueA(NULL, "subkey", val, &size);
1684 ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 98 returns BADKEY */
1685 "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
1686 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1688 /* try a NULL value */
1689 size = MAX_PATH;
1690 ret = RegQueryValueA(hkey_main, "subkey", NULL, &size);
1691 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1692 ok(size == 5, "Expected 5, got %d\n", size);
1694 /* try a NULL size */
1695 SetLastError(0xdeadbeef);
1696 val[0] = '\0';
1697 ret = RegQueryValueA(hkey_main, "subkey", val, NULL);
1698 ok(ret == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", ret);
1699 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1700 ok(!val[0], "Expected val to be untouched, got %s\n", val);
1702 /* try a NULL value and size */
1703 ret = RegQueryValueA(hkey_main, "subkey", NULL, NULL);
1704 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1706 /* try a size too small */
1707 SetLastError(0xdeadbeef);
1708 val[0] = '\0';
1709 size = 1;
1710 ret = RegQueryValueA(hkey_main, "subkey", val, &size);
1711 ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret);
1712 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1713 ok(!val[0], "Expected val to be untouched, got %s\n", val);
1714 ok(size == 5, "Expected 5, got %d\n", size);
1716 /* successfully read the value using 'subkey' */
1717 size = MAX_PATH;
1718 ret = RegQueryValueA(hkey_main, "subkey", val, &size);
1719 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1720 ok(!lstrcmpA(val, "data"), "Expected 'data', got '%s'\n", val);
1721 ok(size == 5, "Expected 5, got %d\n", size);
1723 /* successfully read the value using the subkey key */
1724 size = MAX_PATH;
1725 ret = RegQueryValueA(subkey, NULL, val, &size);
1726 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1727 ok(!lstrcmpA(val, "data"), "Expected 'data', got '%s'\n", val);
1728 ok(size == 5, "Expected 5, got %d\n", size);
1730 /* unicode - try size too small */
1731 SetLastError(0xdeadbeef);
1732 valW[0] = '\0';
1733 size = 0;
1734 ret = RegQueryValueW(subkey, NULL, valW, &size);
1735 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1737 win_skip("RegQueryValueW is not implemented\n");
1738 goto cleanup;
1740 ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret);
1741 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1742 ok(!valW[0], "Expected valW to be untouched\n");
1743 ok(size == 10, "Got wrong size: %d\n", size);
1745 /* unicode - try size in WCHARS */
1746 SetLastError(0xdeadbeef);
1747 size = ARRAY_SIZE(valW);
1748 ret = RegQueryValueW(subkey, NULL, valW, &size);
1749 ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret);
1750 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1751 ok(!valW[0], "Expected valW to be untouched\n");
1752 ok(size == 10, "Got wrong size: %d\n", size);
1754 /* unicode - successfully read the value */
1755 size = sizeof(valW);
1756 ret = RegQueryValueW(subkey, NULL, valW, &size);
1757 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1758 ok(!lstrcmpW(valW, L"data"), "Got wrong value\n");
1759 ok(size == 10, "Got wrong size: %d\n", size);
1761 /* unicode - set the value without a NULL terminator */
1762 ret = RegSetValueW(subkey, NULL, REG_SZ, L"data", 8);
1763 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1765 /* unicode - read the unterminated value, value is terminated for us */
1766 memset(valW, 'a', sizeof(valW));
1767 size = sizeof(valW);
1768 ret = RegQueryValueW(subkey, NULL, valW, &size);
1769 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1770 ok(!lstrcmpW(valW, L"data"), "Got wrong value\n");
1771 ok(size == 10, "Got wrong size: %d\n", size);
1773 cleanup:
1774 RegDeleteKeyA(subkey, "");
1775 RegCloseKey(subkey);
1778 static void test_reg_query_info(void)
1780 HKEY subkey;
1781 HKEY subsubkey;
1782 LONG ret;
1783 char classbuffer[32];
1784 WCHAR classbufferW[32];
1785 char expectbuffer[32];
1786 WCHAR expectbufferW[32];
1787 char subkey_class[] = "subkey class";
1788 WCHAR subkey_classW[] = L"subkey class";
1789 char subsubkey_class[] = "subsubkey class";
1790 DWORD classlen;
1791 DWORD subkeys, maxsubkeylen, maxclasslen;
1792 DWORD values, maxvaluenamelen, maxvaluelen;
1793 DWORD sdlen;
1794 FILETIME lastwrite;
1796 ret = RegCreateKeyExA(hkey_main, "subkey", 0, subkey_class, 0, KEY_ALL_ACCESS, NULL, &subkey, NULL);
1797 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1799 /* all parameters NULL */
1800 ret = RegQueryInfoKeyA(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1801 ok(ret == ERROR_INVALID_HANDLE, "ret = %d\n", ret);
1803 ret = RegQueryInfoKeyW(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1804 ok(ret == ERROR_INVALID_HANDLE, "ret = %d\n", ret);
1806 /* not requesting any information */
1807 ret = RegQueryInfoKeyA(subkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1808 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1810 ret = RegQueryInfoKeyW(subkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1811 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1813 /* class without length is invalid */
1814 memset(classbuffer, 0x55, sizeof(classbuffer));
1815 ret = RegQueryInfoKeyA(subkey, classbuffer, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1816 ok(ret == ERROR_INVALID_PARAMETER, "ret = %d\n", ret);
1817 ok(classbuffer[0] == 0x55, "classbuffer[0] = 0x%x\n", classbuffer[0]);
1819 memset(classbufferW, 0x55, sizeof(classbufferW));
1820 ret = RegQueryInfoKeyW(subkey, classbufferW, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1821 ok(ret == ERROR_INVALID_PARAMETER, "ret = %d\n", ret);
1822 ok(classbufferW[0] == 0x5555, "classbufferW[0] = 0x%x\n", classbufferW[0]);
1824 /* empty key */
1825 sdlen = classlen =0;
1826 ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1827 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1828 ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
1829 ok(subkeys == 0, "subkeys = %u\n", subkeys);
1830 ok(maxsubkeylen == 0, "maxsubkeylen = %u\n", maxsubkeylen);
1831 ok(maxclasslen == 0, "maxclasslen = %u\n", maxclasslen);
1832 ok(values == 0, "values = %u\n", values);
1833 ok(maxvaluenamelen == 0, "maxvaluenamelen = %u\n", maxvaluenamelen);
1834 ok(maxvaluelen == 0, "maxvaluelen = %u\n", maxvaluelen);
1835 todo_wine ok(sdlen != 0, "sdlen = %u\n", sdlen);
1836 ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
1837 ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
1839 sdlen = classlen = 0;
1840 ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1841 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1842 ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
1843 ok(subkeys == 0, "subkeys = %u\n", subkeys);
1844 ok(maxsubkeylen == 0, "maxsubkeylen = %u\n", maxsubkeylen);
1845 ok(maxclasslen == 0, "maxclasslen = %u\n", maxclasslen);
1846 ok(values == 0, "values = %u\n", values);
1847 ok(maxvaluenamelen == 0, "maxvaluenamelen = %u\n", maxvaluenamelen);
1848 ok(maxvaluelen == 0, "maxvaluelen = %u\n", maxvaluelen);
1849 todo_wine ok(sdlen != 0, "sdlen = %u\n", sdlen);
1850 ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
1851 ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
1853 ret = RegCreateKeyExA(subkey, "subsubkey", 0, subsubkey_class, 0, KEY_ALL_ACCESS, NULL, &subsubkey, NULL);
1854 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1856 ret = RegSetValueExA(subkey, NULL, 0, REG_SZ, (const BYTE*)"data", 5);
1857 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1859 /* with subkey & default value */
1860 sdlen = classlen = 0;
1861 ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1862 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1863 ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
1864 ok(subkeys == 1, "subkeys = %u\n", subkeys);
1865 ok(maxsubkeylen == strlen("subsubkey"), "maxsubkeylen = %u\n", maxsubkeylen);
1866 ok(maxclasslen == strlen(subsubkey_class), "maxclasslen = %u\n", maxclasslen);
1867 ok(values == 1, "values = %u\n", values);
1868 ok(maxvaluenamelen == 0, "maxvaluenamelen = %u\n", maxvaluenamelen);
1869 ok(maxvaluelen == sizeof("data") * sizeof(WCHAR), "maxvaluelen = %u\n", maxvaluelen);
1870 todo_wine ok(sdlen != 0, "sdlen = %u\n", sdlen);
1871 ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
1872 ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
1874 sdlen = classlen = 0;
1875 ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1876 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1877 ok(classlen == strlen(subkey_class), "classlen = %u\n", classlen);
1878 ok(subkeys == 1, "subkeys = %u\n", subkeys);
1879 ok(maxsubkeylen == strlen("subsubkey"), "maxsubkeylen = %u\n", maxsubkeylen);
1880 ok(maxclasslen == strlen(subsubkey_class), "maxclasslen = %u\n", maxclasslen);
1881 ok(values == 1, "values = %u\n", values);
1882 ok(maxvaluenamelen == 0, "maxvaluenamelen = %u\n", maxvaluenamelen);
1883 ok(maxvaluelen == sizeof("data") * sizeof(WCHAR), "maxvaluelen = %u\n", maxvaluelen);
1884 todo_wine ok(sdlen != 0, "sdlen = %u\n", sdlen);
1885 ok(lastwrite.dwLowDateTime != 0, "lastwrite.dwLowDateTime = %u\n", lastwrite.dwLowDateTime);
1886 ok(lastwrite.dwHighDateTime != 0, "lastwrite.dwHighDateTime = %u\n", lastwrite.dwHighDateTime);
1888 ret = RegSetValueExA(subkey, "value one", 0, REG_SZ, (const BYTE*)"first value data", 17);
1889 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1891 ret = RegSetValueExA(subkey, "value 2", 0, REG_SZ, (const BYTE*)"second value data", 18);
1892 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
1894 /* with named value */
1895 classlen = 0;
1896 ret = RegQueryInfoKeyA(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1897 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1898 ok(values == 3, "values = %u\n", values);
1899 ok(maxvaluenamelen == strlen("value one"), "maxvaluenamelen = %u\n", maxvaluenamelen);
1900 ok(maxvaluelen == sizeof("second value data") * sizeof(WCHAR), "maxvaluelen = %u\n", maxvaluelen);
1902 classlen = 0;
1903 ret = RegQueryInfoKeyW(subkey, NULL, &classlen, NULL, &subkeys, &maxsubkeylen, &maxclasslen, &values, &maxvaluenamelen, &maxvaluelen, &sdlen, &lastwrite);
1904 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1905 ok(values == 3, "values = %u\n", values);
1906 ok(maxvaluenamelen == strlen("value one"), "maxvaluenamelen = %u\n", maxvaluenamelen);
1907 ok(maxvaluelen == sizeof("second value data") * sizeof(WCHAR), "maxvaluelen = %u\n", maxvaluelen);
1909 /* class name with zero size buffer */
1910 memset(classbuffer, 0x55, sizeof(classbuffer));
1911 classlen = 0;
1912 ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1913 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1914 ok(classlen == strlen(subkey_class) /* win2k */ ||
1915 classlen == 0, "classlen = %u\n", classlen);
1916 memset(expectbuffer, 0x55, sizeof(expectbuffer));
1917 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)), "classbuffer was modified\n");
1919 memset(classbufferW, 0x55, sizeof(classbufferW));
1920 classlen = 0;
1921 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1922 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1923 ok(classlen == strlen(subkey_class) /* win2k */ ||
1924 classlen == 0, "classlen = %u\n", classlen);
1925 memset(expectbufferW, 0x55, sizeof(expectbufferW));
1926 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)), "classbufferW was modified\n");
1928 /* class name with one char buffer */
1929 memset(classbuffer, 0x55, sizeof(classbuffer));
1930 classlen = 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 == 0, "classlen = %u\n", classlen);
1934 memset(expectbuffer, 0x55, sizeof(expectbuffer));
1935 expectbuffer[0] = 0;
1936 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)), "classbuffer was modified\n");
1938 memset(classbufferW, 0x55, sizeof(classbufferW));
1939 classlen = 1;
1940 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1941 /* failure-code changed to ERROR_MORE_DATA in recent win10 */
1942 ok((ret == ERROR_INSUFFICIENT_BUFFER) || (ret == ERROR_MORE_DATA), "ret = %d\n", ret);
1943 ok(classlen == 0 /* win8 */ ||
1944 classlen == strlen(subkey_class), "classlen = %u\n", classlen);
1945 memset(expectbufferW, 0x55, sizeof(expectbufferW));
1946 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)), "classbufferW was modified\n");
1948 /* class name with buffer one char too small */
1949 memset(classbuffer, 0x55, sizeof(classbuffer));
1950 classlen = sizeof(subkey_class) - 1;
1951 ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1952 ok(ret == ERROR_MORE_DATA, "ret = %d\n", ret);
1953 ok(classlen == sizeof(subkey_class) - 2, "classlen = %u\n", classlen);
1954 memset(expectbuffer, 0x55, sizeof(expectbuffer));
1955 strcpy(expectbuffer, subkey_class);
1956 expectbuffer[sizeof(subkey_class) - 2] = 0;
1957 expectbuffer[sizeof(subkey_class) - 1] = 0x55;
1958 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)),
1959 "classbuffer = %.*s, expected %s\n",
1960 (int)sizeof(classbuffer), classbuffer, expectbuffer);
1962 memset(classbufferW, 0x55, sizeof(classbufferW));
1963 classlen = sizeof(subkey_class) - 1;
1964 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1965 ok(ret == ERROR_INSUFFICIENT_BUFFER, "ret = %d\n", ret);
1966 ok(classlen == sizeof(subkey_class) - 2 /* win8 */ ||
1967 classlen == strlen(subkey_class), "classlen = %u\n", classlen);
1968 memset(expectbufferW, 0x55, sizeof(expectbufferW));
1969 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)), "classbufferW was modified\n");
1971 /* class name with large enough buffer */
1972 memset(classbuffer, 0x55, sizeof(classbuffer));
1973 classlen = sizeof(subkey_class);
1974 ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1975 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1976 ok(classlen == sizeof(subkey_class) - 1, "classlen = %u\n", classlen);
1977 memset(expectbuffer, 0x55, sizeof(expectbuffer));
1978 strcpy(expectbuffer, subkey_class);
1979 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)),
1980 "classbuffer = \"%.*s\", expected %s\n",
1981 (int)sizeof(classbuffer), classbuffer, expectbuffer);
1983 memset(classbuffer, 0x55, sizeof(classbuffer));
1984 classlen = 0xdeadbeef;
1985 ret = RegQueryInfoKeyA(subkey, classbuffer, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1986 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1987 ok(classlen == sizeof(subkey_class) - 1, "classlen = %u\n", classlen);
1988 memset(expectbuffer, 0x55, sizeof(expectbuffer));
1989 strcpy(expectbuffer, subkey_class);
1990 ok(!memcmp(classbuffer, expectbuffer, sizeof(classbuffer)),
1991 "classbuffer = \"%.*s\", expected %s\n",
1992 (int)sizeof(classbuffer), classbuffer, expectbuffer);
1994 memset(classbufferW, 0x55, sizeof(classbufferW));
1995 classlen = sizeof(subkey_class);
1996 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1997 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
1998 ok(classlen == sizeof(subkey_class) - 1, "classlen = %u\n", classlen);
1999 memset(expectbufferW, 0x55, sizeof(expectbufferW));
2000 lstrcpyW(expectbufferW, subkey_classW);
2001 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)),
2002 "classbufferW = %s, expected %s\n",
2003 wine_dbgstr_wn(classbufferW, ARRAY_SIZE(classbufferW)), wine_dbgstr_w(expectbufferW));
2005 memset(classbufferW, 0x55, sizeof(classbufferW));
2006 classlen = 0xdeadbeef;
2007 ret = RegQueryInfoKeyW(subkey, classbufferW, &classlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2008 ok(ret == ERROR_SUCCESS, "ret = %d\n", ret);
2009 ok(classlen == sizeof(subkey_class) - 1, "classlen = %u\n", classlen);
2010 memset(expectbufferW, 0x55, sizeof(expectbufferW));
2011 lstrcpyW(expectbufferW, subkey_classW);
2012 ok(!memcmp(classbufferW, expectbufferW, sizeof(classbufferW)),
2013 "classbufferW = %s, expected %s\n",
2014 wine_dbgstr_wn(classbufferW, ARRAY_SIZE(classbufferW)), wine_dbgstr_w(expectbufferW));
2016 RegDeleteKeyA(subsubkey, "");
2017 RegCloseKey(subsubkey);
2018 RegDeleteKeyA(subkey, "");
2019 RegCloseKey(subkey);
2022 static void test_string_termination(void)
2024 HKEY subkey;
2025 LSTATUS ret;
2026 static const char string[] = "FullString";
2027 char name[11];
2028 BYTE buffer[11];
2029 DWORD insize, outsize, nsize;
2031 ret = RegCreateKeyA(hkey_main, "string_termination", &subkey);
2032 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2034 /* Off-by-one RegSetValueExA -> adds a trailing '\0'! */
2035 insize=sizeof(string)-1;
2036 ret = RegSetValueExA(subkey, "stringtest", 0, REG_SZ, (BYTE*)string, insize);
2037 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", ret);
2038 outsize=insize;
2039 ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
2040 ok(ret == ERROR_MORE_DATA, "RegQueryValueExA returned: %d\n", ret);
2042 /* Off-by-two RegSetValueExA -> no trailing '\0' */
2043 insize=sizeof(string)-2;
2044 ret = RegSetValueExA(subkey, "stringtest", 0, REG_SZ, (BYTE*)string, insize);
2045 ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", ret);
2046 outsize=0;
2047 ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, NULL, &outsize);
2048 ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
2049 ok(outsize == insize, "wrong size %u != %u\n", outsize, insize);
2051 /* RegQueryValueExA may return a string with no trailing '\0' */
2052 outsize=insize;
2053 memset(buffer, 0xbd, sizeof(buffer));
2054 ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
2055 ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
2056 ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
2057 ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
2058 debugstr_an((char*)buffer, outsize), outsize, string);
2059 ok(buffer[insize] == 0xbd, "buffer overflow at %u %02x\n", insize, buffer[insize]);
2061 /* RegQueryValueExA adds a trailing '\0' if there is room */
2062 outsize=insize+1;
2063 memset(buffer, 0xbd, sizeof(buffer));
2064 ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
2065 ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
2066 ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
2067 ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
2068 debugstr_an((char*)buffer, outsize), outsize, string);
2069 ok(buffer[insize] == 0, "buffer overflow at %u %02x\n", insize, buffer[insize]);
2071 /* RegEnumValueA may return a string with no trailing '\0' */
2072 outsize=insize;
2073 memset(buffer, 0xbd, sizeof(buffer));
2074 nsize=sizeof(name);
2075 ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize);
2076 ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", ret);
2077 ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name);
2078 ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
2079 ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
2080 debugstr_an((char*)buffer, outsize), outsize, string);
2081 ok(buffer[insize] == 0xbd, "buffer overflow at %u %02x\n", insize, buffer[insize]);
2083 /* RegEnumValueA adds a trailing '\0' if there is room */
2084 outsize=insize+1;
2085 memset(buffer, 0xbd, sizeof(buffer));
2086 nsize=sizeof(name);
2087 ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize);
2088 ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", ret);
2089 ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name);
2090 ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
2091 ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
2092 debugstr_an((char*)buffer, outsize), outsize, string);
2093 ok(buffer[insize] == 0, "buffer overflow at %u %02x\n", insize, buffer[insize]);
2095 RegDeleteKeyA(subkey, "");
2096 RegCloseKey(subkey);
2099 static void test_reg_copy_tree(void)
2101 HKEY src, dst, subkey;
2102 CHAR buffer[MAX_PATH];
2103 DWORD dwsize, type;
2104 LONG size, ret;
2106 if (!pRegCopyTreeA)
2108 win_skip("Skipping RegCopyTreeA tests, function not present\n");
2109 return;
2112 ret = RegCreateKeyA(hkey_main, "src", &src);
2113 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2114 ret = RegCreateKeyA(hkey_main, "dst", &dst);
2115 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2117 /* Copy nonexistent subkey */
2118 ret = pRegCopyTreeA(src, "nonexistent_subkey", dst);
2119 ok(ret == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
2121 /* Create test keys and values */
2122 ret = RegSetValueA(src, NULL, REG_SZ, "data", 4);
2123 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2124 ret = RegSetValueExA(src, "value", 0, REG_SZ, (const BYTE *)"data2", 5);
2125 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2127 ret = RegCreateKeyA(src, "subkey2", &subkey);
2128 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2129 ret = RegSetValueA(subkey, NULL, REG_SZ, "data3", 5);
2130 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2131 ret = RegSetValueExA(subkey, "value", 0, REG_SZ, (const BYTE *)"data4", 5);
2132 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2133 ret = RegCloseKey(subkey);
2134 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2136 ret = RegCreateKeyA(src, "subkey3", &subkey);
2137 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2138 ret = RegCloseKey(subkey);
2139 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2141 /* Copy subkey */
2142 ret = pRegCopyTreeA(src, "subkey2", dst);
2143 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2145 size = MAX_PATH;
2146 ret = RegQueryValueA(dst, NULL, buffer, &size);
2147 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2148 ok(!strcmp(buffer, "data3"), "Expected 'data3', got '%s'\n", buffer);
2150 dwsize = MAX_PATH;
2151 ret = RegQueryValueExA(dst, "value", NULL, &type, (BYTE *)buffer, &dwsize);
2152 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2153 ok(type == REG_SZ, "Expected REG_SZ, got %u\n", type);
2154 ok(!strcmp(buffer, "data4"), "Expected 'data4', got '%s'\n", buffer);
2156 /* Copy full tree */
2157 ret = pRegCopyTreeA(src, NULL, dst);
2158 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2160 size = MAX_PATH;
2161 ret = RegQueryValueA(dst, NULL, buffer, &size);
2162 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2163 ok(!strcmp(buffer, "data"), "Expected 'data', got '%s'\n", buffer);
2165 dwsize = MAX_PATH;
2166 ret = RegQueryValueExA(dst, "value", NULL, &type, (BYTE *)buffer, &dwsize);
2167 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2168 ok(type == REG_SZ, "Expected REG_SZ, got %u\n", type);
2169 ok(!strcmp(buffer, "data2"), "Expected 'data2', got '%s'\n", buffer);
2171 ret = RegOpenKeyA(dst, "subkey2", &subkey);
2172 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2173 size = MAX_PATH;
2174 ret = RegQueryValueA(subkey, NULL, buffer, &size);
2175 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2176 ok(!strcmp(buffer, "data3"), "Expected 'data3', got '%s'\n", buffer);
2177 dwsize = MAX_PATH;
2178 ret = RegQueryValueExA(subkey, "value", NULL, &type, (BYTE *)buffer, &dwsize);
2179 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2180 ok(type == REG_SZ, "Expected REG_SZ, got %u\n", type);
2181 ok(!strcmp(buffer, "data4"), "Expected 'data4', got '%s'\n", buffer);
2182 ret = RegCloseKey(subkey);
2183 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2185 ret = RegOpenKeyA(dst, "subkey3", &subkey);
2186 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2187 ret = RegCloseKey(subkey);
2188 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2190 delete_key(src);
2191 delete_key(dst);
2194 static void test_reg_delete_tree(void)
2196 CHAR buffer[MAX_PATH];
2197 HKEY subkey, subkey2;
2198 DWORD dwsize, type;
2199 LONG size, ret;
2201 if(!pRegDeleteTreeA) {
2202 win_skip("Skipping RegDeleteTreeA tests, function not present\n");
2203 return;
2206 ret = RegCreateKeyA(hkey_main, "subkey", &subkey);
2207 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2208 ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
2209 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2210 ret = RegSetValueA(subkey, NULL, REG_SZ, "data", 4);
2211 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2212 ret = RegSetValueA(subkey2, NULL, REG_SZ, "data2", 5);
2213 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2214 ret = RegCloseKey(subkey2);
2215 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2217 ret = pRegDeleteTreeA(subkey, "subkey2");
2218 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2219 ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
2220 "subkey2 was not deleted\n");
2221 size = MAX_PATH;
2222 ok(!RegQueryValueA(subkey, NULL, buffer, &size),
2223 "Default value of subkey no longer present\n");
2225 ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
2226 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2227 ret = RegCloseKey(subkey2);
2228 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2229 ret = pRegDeleteTreeA(hkey_main, "subkey\\subkey2");
2230 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2231 ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
2232 "subkey2 was not deleted\n");
2233 ok(!RegQueryValueA(subkey, NULL, buffer, &size),
2234 "Default value of subkey no longer present\n");
2236 ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
2237 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2238 ret = RegCloseKey(subkey2);
2239 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2240 ret = RegCreateKeyA(subkey, "subkey3", &subkey2);
2241 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2242 ret = RegCloseKey(subkey2);
2243 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2244 ret = RegSetValueA(subkey, NULL, REG_SZ, "data", 4);
2245 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2246 ret = RegSetValueExA(subkey, "value", 0, REG_SZ, (const BYTE *)"data2", 5);
2247 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2248 ret = pRegDeleteTreeA(subkey, NULL);
2249 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2250 ok(!RegOpenKeyA(hkey_main, "subkey", &subkey),
2251 "subkey was deleted\n");
2252 ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
2253 "subkey2 was not deleted\n");
2254 ok(RegOpenKeyA(subkey, "subkey3", &subkey2),
2255 "subkey3 was not deleted\n");
2256 size = MAX_PATH;
2257 ret = RegQueryValueA(subkey, NULL, buffer, &size);
2258 ok(ret == ERROR_SUCCESS,
2259 "Default value of subkey is not present\n");
2260 ok(!buffer[0], "Expected length 0 got length %u(%s)\n", lstrlenA(buffer), buffer);
2261 dwsize = MAX_PATH;
2262 ok(RegQueryValueExA(subkey, "value", NULL, &type, (BYTE *)buffer, &dwsize),
2263 "Value is still present\n");
2264 ret = RegCloseKey(subkey);
2265 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2267 ret = RegOpenKeyA(hkey_main, "subkey", &subkey);
2268 ok(ret == ERROR_SUCCESS, "subkey was deleted\n");
2269 ret = pRegDeleteTreeA(subkey, "");
2270 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2271 ret = RegCloseKey(subkey);
2272 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2274 ret = RegOpenKeyA(hkey_main, "subkey", &subkey);
2275 ok(ret == ERROR_SUCCESS, "subkey was deleted\n");
2276 ret = RegCloseKey(subkey);
2277 ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
2279 ret = pRegDeleteTreeA(hkey_main, "not-here");
2280 ok(ret == ERROR_FILE_NOT_FOUND,
2281 "Expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
2284 static void test_rw_order(void)
2286 HKEY hKey;
2287 DWORD dw = 0;
2288 static const char keyname[] = "test_rw_order";
2289 char value_buf[2];
2290 DWORD values, value_len, value_name_max_len;
2291 LSTATUS ret;
2293 RegDeleteKeyA(HKEY_CURRENT_USER, keyname);
2294 ret = RegCreateKeyA(HKEY_CURRENT_USER, keyname, &hKey);
2295 if(ret != ERROR_SUCCESS) {
2296 skip("Couldn't create key. Skipping.\n");
2297 return;
2300 ok(!RegSetValueExA(hKey, "A", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)),
2301 "RegSetValueExA for value \"A\" failed\n");
2302 ok(!RegSetValueExA(hKey, "C", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)),
2303 "RegSetValueExA for value \"C\" failed\n");
2304 ok(!RegSetValueExA(hKey, "D", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)),
2305 "RegSetValueExA for value \"D\" failed\n");
2306 ok(!RegSetValueExA(hKey, "B", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)),
2307 "RegSetValueExA for value \"B\" failed\n");
2309 ok(!RegQueryInfoKeyA(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &values,
2310 &value_name_max_len, NULL, NULL, NULL), "RegQueryInfoKeyA failed\n");
2311 ok(values == 4, "Expected 4 values, got %u\n", values);
2313 /* Value enumeration preserves RegSetValueEx call order */
2314 value_len = 2;
2315 ok(!RegEnumValueA(hKey, 0, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n");
2316 ok(strcmp(value_buf, "A") == 0, "Expected name \"A\", got %s\n", value_buf);
2317 value_len = 2;
2318 ok(!RegEnumValueA(hKey, 1, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n");
2319 todo_wine ok(strcmp(value_buf, "C") == 0, "Expected name \"C\", got %s\n", value_buf);
2320 value_len = 2;
2321 ok(!RegEnumValueA(hKey, 2, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n");
2322 todo_wine ok(strcmp(value_buf, "D") == 0, "Expected name \"D\", got %s\n", value_buf);
2323 value_len = 2;
2324 ok(!RegEnumValueA(hKey, 3, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n");
2325 todo_wine ok(strcmp(value_buf, "B") == 0, "Expected name \"B\", got %s\n", value_buf);
2327 ok(!RegDeleteKeyA(HKEY_CURRENT_USER, keyname), "Failed to delete key\n");
2330 static void test_symlinks(void)
2332 static const WCHAR targetW[] = L"\\Software\\Wine\\Test\\target";
2333 BYTE buffer[1024];
2334 UNICODE_STRING target_str;
2335 WCHAR *target;
2336 HKEY key, link;
2337 NTSTATUS status;
2338 DWORD target_len, type, len, dw, err;
2340 if (!pRtlFormatCurrentUserKeyPath || !pNtDeleteKey)
2342 win_skip( "Can't perform symlink tests\n" );
2343 return;
2346 pRtlFormatCurrentUserKeyPath( &target_str );
2348 target_len = target_str.Length + sizeof(targetW);
2349 target = HeapAlloc( GetProcessHeap(), 0, target_len );
2350 memcpy( target, target_str.Buffer, target_str.Length );
2351 memcpy( target + target_str.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
2353 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, REG_OPTION_CREATE_LINK,
2354 KEY_ALL_ACCESS, NULL, &link, NULL );
2355 ok( err == ERROR_SUCCESS, "RegCreateKeyEx failed: %u\n", err );
2357 /* REG_SZ is not allowed */
2358 err = RegSetValueExA( link, "SymbolicLinkValue", 0, REG_SZ, (BYTE *)"foobar", sizeof("foobar") );
2359 ok( err == ERROR_ACCESS_DENIED, "RegSetValueEx wrong error %u\n", err );
2360 err = RegSetValueExA( link, "SymbolicLinkValue", 0, REG_LINK,
2361 (BYTE *)target, target_len - sizeof(WCHAR) );
2362 ok( err == ERROR_SUCCESS, "RegSetValueEx failed error %u\n", err );
2363 /* other values are not allowed */
2364 err = RegSetValueExA( link, "link", 0, REG_LINK, (BYTE *)target, target_len - sizeof(WCHAR) );
2365 ok( err == ERROR_ACCESS_DENIED, "RegSetValueEx wrong error %u\n", err );
2367 /* try opening the target through the link */
2369 err = RegOpenKeyA( hkey_main, "link", &key );
2370 ok( err == ERROR_FILE_NOT_FOUND, "RegOpenKey wrong error %u\n", err );
2372 err = RegCreateKeyExA( hkey_main, "target", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key, NULL );
2373 ok( err == ERROR_SUCCESS, "RegCreateKeyEx failed error %u\n", err );
2375 dw = 0xbeef;
2376 err = RegSetValueExA( key, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2377 ok( err == ERROR_SUCCESS, "RegSetValueEx failed error %u\n", err );
2378 RegCloseKey( key );
2380 err = RegOpenKeyA( hkey_main, "link", &key );
2381 ok( err == ERROR_SUCCESS, "RegOpenKey failed error %u\n", err );
2383 len = sizeof(buffer);
2384 err = RegQueryValueExA( key, "value", NULL, &type, buffer, &len );
2385 ok( err == ERROR_SUCCESS, "RegOpenKey failed error %u\n", err );
2386 ok( len == sizeof(DWORD), "wrong len %u\n", len );
2388 len = sizeof(buffer);
2389 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2390 ok( err == ERROR_FILE_NOT_FOUND, "RegQueryValueEx wrong error %u\n", err );
2392 /* REG_LINK can be created in non-link keys */
2393 err = RegSetValueExA( key, "SymbolicLinkValue", 0, REG_LINK,
2394 (BYTE *)target, target_len - sizeof(WCHAR) );
2395 ok( err == ERROR_SUCCESS, "RegSetValueEx failed error %u\n", err );
2396 len = sizeof(buffer);
2397 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2398 ok( err == ERROR_SUCCESS, "RegQueryValueEx failed error %u\n", err );
2399 ok( len == target_len - sizeof(WCHAR), "wrong len %u\n", len );
2400 err = RegDeleteValueA( key, "SymbolicLinkValue" );
2401 ok( err == ERROR_SUCCESS, "RegDeleteValue failed error %u\n", err );
2403 RegCloseKey( key );
2405 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &key, NULL );
2406 ok( err == ERROR_SUCCESS, "RegCreateKeyEx failed error %u\n", err );
2408 len = sizeof(buffer);
2409 err = RegQueryValueExA( key, "value", NULL, &type, buffer, &len );
2410 ok( err == ERROR_SUCCESS, "RegQueryValueEx failed error %u\n", err );
2411 ok( len == sizeof(DWORD), "wrong len %u\n", len );
2413 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2414 ok( err == ERROR_FILE_NOT_FOUND, "RegQueryValueEx wrong error %u\n", err );
2415 RegCloseKey( key );
2417 /* now open the symlink itself */
2419 err = RegOpenKeyExA( hkey_main, "link", REG_OPTION_OPEN_LINK, KEY_ALL_ACCESS, &key );
2420 ok( err == ERROR_SUCCESS, "RegOpenKeyEx failed error %u\n", err );
2421 len = sizeof(buffer);
2422 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2423 ok( err == ERROR_SUCCESS, "RegQueryValueEx failed error %u\n", err );
2424 ok( len == target_len - sizeof(WCHAR), "wrong len %u\n", len );
2425 RegCloseKey( key );
2427 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, REG_OPTION_OPEN_LINK,
2428 KEY_ALL_ACCESS, NULL, &key, NULL );
2429 ok( err == ERROR_SUCCESS, "RegCreateKeyEx failed error %u\n", err );
2430 len = sizeof(buffer);
2431 err = RegQueryValueExA( key, "SymbolicLinkValue", NULL, &type, buffer, &len );
2432 ok( err == ERROR_SUCCESS, "RegQueryValueEx failed error %u\n", err );
2433 ok( len == target_len - sizeof(WCHAR), "wrong len %u\n", len );
2434 RegCloseKey( key );
2436 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, REG_OPTION_CREATE_LINK,
2437 KEY_ALL_ACCESS, NULL, &key, NULL );
2438 ok( err == ERROR_ALREADY_EXISTS, "RegCreateKeyEx wrong error %u\n", err );
2440 err = RegCreateKeyExA( hkey_main, "link", 0, NULL, REG_OPTION_CREATE_LINK | REG_OPTION_OPEN_LINK,
2441 KEY_ALL_ACCESS, NULL, &key, NULL );
2442 ok( err == ERROR_ALREADY_EXISTS, "RegCreateKeyEx wrong error %u\n", err );
2444 err = RegDeleteKeyA( hkey_main, "target" );
2445 ok( err == ERROR_SUCCESS, "RegDeleteKey failed error %u\n", err );
2447 err = RegDeleteKeyA( hkey_main, "link" );
2448 ok( err == ERROR_FILE_NOT_FOUND, "RegDeleteKey wrong error %u\n", err );
2450 status = pNtDeleteKey( link );
2451 ok( !status, "NtDeleteKey failed: 0x%08x\n", status );
2452 RegCloseKey( link );
2454 HeapFree( GetProcessHeap(), 0, target );
2455 pRtlFreeUnicodeString( &target_str );
2458 static DWORD get_key_value( HKEY root, const char *name, DWORD flags )
2460 HKEY key;
2461 DWORD err, type, dw, len = sizeof(dw);
2463 err = RegCreateKeyExA( root, name, 0, NULL, 0, flags | KEY_ALL_ACCESS, NULL, &key, NULL );
2464 if (err == ERROR_FILE_NOT_FOUND) return 0;
2465 ok( err == ERROR_SUCCESS, "%08x: RegCreateKeyEx failed: %u\n", flags, err );
2467 err = RegQueryValueExA( key, "value", NULL, &type, (BYTE *)&dw, &len );
2468 if (err == ERROR_FILE_NOT_FOUND)
2469 dw = 0;
2470 else
2471 ok( err == ERROR_SUCCESS, "%08x: RegQueryValueEx failed: %u\n", flags, err );
2472 RegCloseKey( key );
2473 return dw;
2476 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
2478 DWORD dw = get_key_value( root, name, flags );
2479 ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect );
2481 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
2483 static void test_redirection(void)
2485 DWORD err, type, dw, len;
2486 HKEY key, root32, root64, key32, key64, native, op_key;
2487 BOOL is_vista = FALSE;
2488 REGSAM opposite = (sizeof(void*) == 8 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY);
2490 if (ptr_size != 64)
2492 BOOL is_wow64;
2493 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 ) || !is_wow64)
2495 skip( "Not on Wow64, no redirection\n" );
2496 return;
2500 if (limited_user)
2502 skip("not enough privileges to modify HKLM\n");
2503 return;
2506 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2507 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &root64, NULL );
2508 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2510 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2511 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &root32, NULL );
2512 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2514 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", 0, NULL, 0,
2515 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key64, NULL );
2516 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2518 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", 0, NULL, 0,
2519 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key32, NULL );
2520 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2522 dw = 64;
2523 err = RegSetValueExA( key64, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2524 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %u\n", err );
2526 dw = 32;
2527 err = RegSetValueExA( key32, "value", 0, REG_DWORD, (BYTE *)&dw, sizeof(dw) );
2528 ok( err == ERROR_SUCCESS, "RegSetValueExA failed: %u\n", err );
2530 dw = 0;
2531 len = sizeof(dw);
2532 err = RegQueryValueExA( key32, "value", NULL, &type, (BYTE *)&dw, &len );
2533 ok( err == ERROR_SUCCESS, "RegQueryValueExA failed: %u\n", err );
2534 ok( dw == 32, "wrong value %u\n", dw );
2536 dw = 0;
2537 len = sizeof(dw);
2538 err = RegQueryValueExA( key64, "value", NULL, &type, (BYTE *)&dw, &len );
2539 ok( err == ERROR_SUCCESS, "RegQueryValueExA failed: %u\n", err );
2540 ok( dw == 64, "wrong value %u\n", dw );
2542 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
2543 KEY_ALL_ACCESS, NULL, &key, NULL );
2544 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2546 if (ptr_size == 32)
2548 /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
2549 /* the new (and simpler) Win7 mechanism doesn't */
2550 if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
2552 trace( "using Vista-style Wow6432Node handling\n" );
2553 is_vista = TRUE;
2555 check_key_value( key, "Wine\\Winetest", 0, 32 );
2556 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2557 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2558 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
2559 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
2560 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
2562 else
2564 if (get_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY ) == 64)
2566 trace( "using Vista-style Wow6432Node handling\n" );
2567 is_vista = TRUE;
2569 check_key_value( key, "Wine\\Winetest", 0, 64 );
2570 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
2572 RegCloseKey( key );
2574 if (ptr_size == 32)
2576 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
2577 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2578 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2579 dw = get_key_value( key, "Wine\\Winetest", 0 );
2580 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
2581 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
2582 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2583 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
2584 dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY );
2585 ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw );
2586 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2587 RegCloseKey( key );
2589 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
2590 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2591 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2592 check_key_value( key, "Wine\\Winetest", 0, 32 );
2593 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2594 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2595 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
2596 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
2597 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
2598 RegCloseKey( key );
2600 else
2602 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
2603 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2604 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2605 check_key_value( key, "Wine\\Winetest", 0, 64 );
2606 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
2607 dw = get_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY );
2608 todo_wine ok( dw == 32, "wrong value %u\n", dw );
2609 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
2610 RegCloseKey( key );
2612 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0,
2613 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2614 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2615 check_key_value( key, "Wine\\Winetest", 0, 32 );
2616 dw = get_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY );
2617 ok( dw == 32 || broken(dw == 64) /* vista */, "wrong value %u\n", dw );
2618 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2619 RegCloseKey( key );
2622 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", 0, ptr_size );
2623 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
2624 if (ptr_size == 64)
2626 /* KEY_WOW64 flags have no effect on 64-bit */
2627 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
2628 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2629 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2630 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2632 else
2634 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
2635 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2636 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2637 check_key_value( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2640 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node", 0, NULL, 0,
2641 KEY_ALL_ACCESS, NULL, &key, NULL );
2642 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2643 check_key_value( key, "Wine\\Winetest", 0, 32 );
2644 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2645 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2646 RegCloseKey( key );
2648 if (ptr_size == 32)
2650 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node", 0, NULL, 0,
2651 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2652 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2653 dw = get_key_value( key, "Wine\\Winetest", 0 );
2654 ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
2655 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2656 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2657 RegCloseKey( key );
2659 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node", 0, NULL, 0,
2660 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2661 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2662 check_key_value( key, "Wine\\Winetest", 0, 32 );
2663 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2664 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
2665 RegCloseKey( key );
2668 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine", 0, NULL, 0,
2669 KEY_ALL_ACCESS, NULL, &key, NULL );
2670 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2671 check_key_value( key, "Winetest", 0, 32 );
2672 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2673 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
2674 RegCloseKey( key );
2676 if (ptr_size == 32)
2678 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine", 0, NULL, 0,
2679 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2680 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2681 dw = get_key_value( key, "Winetest", 0 );
2682 ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw );
2683 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2684 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
2685 RegCloseKey( key );
2687 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\Wine", 0, NULL, 0,
2688 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2689 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2690 check_key_value( key, "Winetest", 0, 32 );
2691 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2692 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
2693 RegCloseKey( key );
2696 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2697 KEY_ALL_ACCESS, NULL, &key, NULL );
2698 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2699 check_key_value( key, "Winetest", 0, ptr_size );
2700 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
2701 dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
2702 todo_wine_if (ptr_size != 32)
2703 ok( dw == 32, "wrong value %u\n", dw );
2704 RegCloseKey( key );
2706 if (ptr_size == 32)
2708 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2709 KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2710 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2711 dw = get_key_value( key, "Winetest", 0 );
2712 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
2713 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
2714 dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
2715 todo_wine ok( dw == 32, "wrong value %u\n", dw );
2716 RegCloseKey( key );
2718 err = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
2719 KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &key, NULL );
2720 ok( err == ERROR_SUCCESS, "RegCreateKeyExA failed: %u\n", err );
2721 check_key_value( key, "Winetest", 0, 32 );
2722 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
2723 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
2724 RegCloseKey( key );
2727 if (pRegDeleteKeyExA)
2729 err = pRegDeleteKeyExA( key32, "", KEY_WOW64_32KEY, 0 );
2730 ok( err == ERROR_SUCCESS, "RegDeleteKey failed: %u\n", err );
2731 err = pRegDeleteKeyExA( key64, "", KEY_WOW64_64KEY, 0 );
2732 ok( err == ERROR_SUCCESS, "RegDeleteKey failed: %u\n", err );
2733 pRegDeleteKeyExA( key64, "", KEY_WOW64_64KEY, 0 );
2734 pRegDeleteKeyExA( root64, "", KEY_WOW64_64KEY, 0 );
2736 else
2738 err = RegDeleteKeyA( key32, "" );
2739 ok( err == ERROR_SUCCESS, "RegDeleteKey failed: %u\n", err );
2740 err = RegDeleteKeyA( key64, "" );
2741 ok( err == ERROR_SUCCESS, "RegDeleteKey failed: %u\n", err );
2742 RegDeleteKeyA( key64, "" );
2743 RegDeleteKeyA( root64, "" );
2745 RegCloseKey( key32 );
2746 RegCloseKey( key64 );
2747 RegCloseKey( root32 );
2748 RegCloseKey( root64 );
2750 /* open key in native bit mode */
2751 err = RegOpenKeyExA(HKEY_CLASSES_ROOT, "Interface", 0, KEY_ALL_ACCESS, &native);
2752 ok(err == ERROR_SUCCESS, "got %i\n", err);
2754 pRegDeleteKeyExA(native, "AWineTest", 0, 0);
2756 /* write subkey in opposite bit mode */
2757 err = RegOpenKeyExA(HKEY_CLASSES_ROOT, "Interface", 0, KEY_ALL_ACCESS | opposite, &op_key);
2758 ok(err == ERROR_SUCCESS, "got %i\n", err);
2760 err = RegCreateKeyExA(op_key, "AWineTest", 0, NULL, 0, KEY_ALL_ACCESS | opposite,
2761 NULL, &key, NULL);
2762 ok(err == ERROR_SUCCESS || err == ERROR_ACCESS_DENIED, "got %i\n", err);
2763 if(err != ERROR_SUCCESS){
2764 win_skip("Can't write to registry\n");
2765 RegCloseKey(op_key);
2766 RegCloseKey(native);
2767 return;
2769 RegCloseKey(key);
2771 /* verify subkey is not present in native mode */
2772 err = RegOpenKeyExA(native, "AWineTest", 0, KEY_ALL_ACCESS, &key);
2773 ok(err == ERROR_FILE_NOT_FOUND ||
2774 broken(err == ERROR_SUCCESS), /* before Win7, HKCR is reflected instead of redirected */
2775 "got %i\n", err);
2777 err = pRegDeleteKeyExA(op_key, "AWineTest", opposite, 0);
2778 ok(err == ERROR_SUCCESS, "got %i\n", err);
2780 RegCloseKey(op_key);
2781 RegCloseKey(native);
2784 static void test_classesroot(void)
2786 HKEY hkey, hklm, hkcr, hkeysub1, hklmsub1, hkcrsub1, hklmsub2, hkcrsub2;
2787 DWORD size = 8;
2788 DWORD type = REG_SZ;
2789 static CHAR buffer[8];
2790 LONG res;
2792 /* create a key in the user's classes */
2793 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", &hkey ))
2795 delete_key( hkey );
2796 RegCloseKey( hkey );
2798 res = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", 0, NULL, 0,
2799 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkey, NULL );
2800 if (res == ERROR_ACCESS_DENIED)
2802 skip("not enough privileges to add a user class\n");
2803 return;
2805 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
2807 /* try to open that key in hkcr */
2808 res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "WineTestCls", 0,
2809 KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
2810 todo_wine ok(res == ERROR_SUCCESS ||
2811 broken(res == ERROR_FILE_NOT_FOUND /* WinNT */),
2812 "test key not found in hkcr: %d\n", res);
2813 if (res)
2815 skip("HKCR key merging not supported\n");
2816 delete_key( hkey );
2817 RegCloseKey( hkey );
2818 return;
2821 todo_wine ok(IS_HKCR(hkcr), "hkcr mask not set in %p\n", hkcr);
2823 /* set a value in user's classes */
2824 res = RegSetValueExA(hkey, "val1", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
2825 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2827 /* try to find the value in hkcr */
2828 res = RegQueryValueExA(hkcr, "val1", NULL, &type, (LPBYTE)buffer, &size);
2829 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2830 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2832 /* modify the value in hkcr */
2833 res = RegSetValueExA(hkcr, "val1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
2834 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2836 /* check if the value is also modified in user's classes */
2837 res = RegQueryValueExA(hkey, "val1", NULL, &type, (LPBYTE)buffer, &size);
2838 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2839 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
2841 /* set a value in hkcr */
2842 res = RegSetValueExA(hkcr, "val0", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
2843 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2845 /* try to find the value in user's classes */
2846 res = RegQueryValueExA(hkey, "val0", NULL, &type, (LPBYTE)buffer, &size);
2847 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2848 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
2850 /* modify the value in user's classes */
2851 res = RegSetValueExA(hkey, "val0", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
2852 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2854 /* check if the value is also modified in hkcr */
2855 res = RegQueryValueExA(hkcr, "val0", NULL, &type, (LPBYTE)buffer, &size);
2856 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2857 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2859 /* cleanup */
2860 delete_key( hkey );
2861 delete_key( hkcr );
2862 RegCloseKey( hkey );
2863 RegCloseKey( hkcr );
2865 /* create a key in the hklm classes */
2866 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", &hklm ))
2868 delete_key( hklm );
2869 RegCloseKey( hklm );
2871 res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", 0, NULL, REG_OPTION_NON_VOLATILE,
2872 KEY_ALL_ACCESS, NULL, &hklm, NULL );
2873 if (res == ERROR_ACCESS_DENIED)
2875 skip("not enough privileges to add a system class\n");
2876 return;
2878 ok(!IS_HKCR(hklm), "hkcr mask set in %p\n", hklm);
2880 /* try to open that key in hkcr */
2881 res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "WineTestCls", 0,
2882 KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
2883 ok(res == ERROR_SUCCESS,
2884 "test key not found in hkcr: %d\n", res);
2885 ok(IS_HKCR(hkcr), "hkcr mask not set in %p\n", hkcr);
2886 if (res)
2888 delete_key( hklm );
2889 RegCloseKey( hklm );
2890 return;
2893 /* set a value in hklm classes */
2894 res = RegSetValueExA(hklm, "val2", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
2895 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2897 /* try to find the value in hkcr */
2898 res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
2899 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2900 ok(!strcmp( buffer, "hklm" ), "value set to '%s'\n", buffer );
2902 /* modify the value in hkcr */
2903 res = RegSetValueExA(hkcr, "val2", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
2904 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2906 /* check that the value is modified in hklm classes */
2907 res = RegQueryValueExA(hklm, "val2", NULL, &type, (LPBYTE)buffer, &size);
2908 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2909 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
2911 if (RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", 0, NULL, 0,
2912 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkey, NULL )) return;
2913 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
2915 /* try to open that key in hkcr */
2916 res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "WineTestCls", 0,
2917 KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
2918 ok(res == ERROR_SUCCESS,
2919 "test key not found in hkcr: %d\n", res);
2920 ok(IS_HKCR(hkcr), "hkcr mask not set in %p\n", hkcr);
2922 /* set a value in user's classes */
2923 res = RegSetValueExA(hkey, "val2", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
2924 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2926 /* try to find the value in hkcr */
2927 res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
2928 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2929 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2931 /* modify the value in hklm */
2932 res = RegSetValueExA(hklm, "val2", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
2933 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2935 /* check that the value is not overwritten in hkcr or user's classes */
2936 res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
2937 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2938 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2939 res = RegQueryValueExA(hkey, "val2", NULL, &type, (LPBYTE)buffer, &size);
2940 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2941 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2943 /* modify the value in hkcr */
2944 res = RegSetValueExA(hkcr, "val2", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
2945 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2947 /* check that the value is overwritten in hklm and user's classes */
2948 res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
2949 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2950 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
2951 res = RegQueryValueExA(hkey, "val2", NULL, &type, (LPBYTE)buffer, &size);
2952 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2953 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
2955 /* create a subkey in hklm */
2956 if (RegCreateKeyExA( hklm, "subkey1", 0, NULL, 0,
2957 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hklmsub1, NULL )) return;
2958 ok(!IS_HKCR(hklmsub1), "hkcr mask set in %p\n", hklmsub1);
2959 /* try to open that subkey in hkcr */
2960 res = RegOpenKeyExA( hkcr, "subkey1", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcrsub1 );
2961 ok(res == ERROR_SUCCESS, "test key not found in hkcr: %d\n", res);
2962 ok(IS_HKCR(hkcrsub1), "hkcr mask not set in %p\n", hkcrsub1);
2964 /* set a value in hklm classes */
2965 res = RegSetValueExA(hklmsub1, "subval1", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
2966 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2968 /* try to find the value in hkcr */
2969 res = RegQueryValueExA(hkcrsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
2970 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2971 ok(!strcmp( buffer, "hklm" ), "value set to '%s'\n", buffer );
2973 /* modify the value in hkcr */
2974 res = RegSetValueExA(hkcrsub1, "subval1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
2975 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2977 /* check that the value is modified in hklm classes */
2978 res = RegQueryValueExA(hklmsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
2979 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
2980 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
2982 /* create a subkey in user's classes */
2983 if (RegCreateKeyExA( hkey, "subkey1", 0, NULL, 0,
2984 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkeysub1, NULL )) return;
2985 ok(!IS_HKCR(hkeysub1), "hkcr mask set in %p\n", hkeysub1);
2987 /* set a value in user's classes */
2988 res = RegSetValueExA(hkeysub1, "subval1", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
2989 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
2991 /* try to find the value in hkcr */
2992 res = RegQueryValueExA(hkcrsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
2993 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
2994 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
2996 /* modify the value in hklm */
2997 res = RegSetValueExA(hklmsub1, "subval1", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
2998 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
3000 /* check that the value is not overwritten in hkcr or user's classes */
3001 res = RegQueryValueExA(hkcrsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3002 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
3003 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
3004 res = RegQueryValueExA(hkeysub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3005 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
3006 ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
3008 /* modify the value in hkcr */
3009 res = RegSetValueExA(hkcrsub1, "subval1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
3010 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
3012 /* check that the value is not overwritten in hklm, but in user's classes */
3013 res = RegQueryValueExA(hklmsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3014 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
3015 ok(!strcmp( buffer, "hklm" ), "value set to '%s'\n", buffer );
3016 res = RegQueryValueExA(hkeysub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3017 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
3018 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
3020 /* new subkey in hkcr */
3021 if (RegCreateKeyExA( hkcr, "subkey2", 0, NULL, 0,
3022 KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkcrsub2, NULL )) return;
3023 ok(IS_HKCR(hkcrsub2), "hkcr mask not set in %p\n", hkcrsub2);
3024 res = RegSetValueExA(hkcrsub2, "subval1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
3025 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
3027 /* try to open that new subkey in user's classes and hklm */
3028 res = RegOpenKeyExA( hkey, "subkey2", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hklmsub2 );
3029 ok(res != ERROR_SUCCESS, "test key found in user's classes: %d\n", res);
3030 hklmsub2 = 0;
3031 res = RegOpenKeyExA( hklm, "subkey2", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hklmsub2 );
3032 ok(res == ERROR_SUCCESS, "test key not found in hklm: %d\n", res);
3033 ok(!IS_HKCR(hklmsub2), "hkcr mask set in %p\n", hklmsub2);
3035 /* check that the value is present in hklm */
3036 res = RegQueryValueExA(hklmsub2, "subval1", NULL, &type, (LPBYTE)buffer, &size);
3037 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
3038 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
3040 /* cleanup */
3041 RegCloseKey( hkeysub1 );
3042 RegCloseKey( hklmsub1 );
3044 /* delete subkey1 from hkcr (should point at user's classes) */
3045 res = RegDeleteKeyA(hkcr, "subkey1");
3046 ok(res == ERROR_SUCCESS, "RegDeleteKey failed: %d\n", res);
3048 /* confirm key was removed in hkey but not hklm */
3049 res = RegOpenKeyExA(hkey, "subkey1", 0, KEY_READ, &hkeysub1);
3050 ok(res == ERROR_FILE_NOT_FOUND, "test key found in user's classes: %d\n", res);
3051 res = RegOpenKeyExA(hklm, "subkey1", 0, KEY_READ, &hklmsub1);
3052 ok(res == ERROR_SUCCESS, "test key not found in hklm: %d\n", res);
3053 ok(!IS_HKCR(hklmsub1), "hkcr mask set in %p\n", hklmsub1);
3055 /* delete subkey1 from hkcr again (which should now point at hklm) */
3056 res = RegDeleteKeyA(hkcr, "subkey1");
3057 ok(res == ERROR_SUCCESS, "RegDeleteKey failed: %d\n", res);
3059 /* confirm hkey was removed in hklm */
3060 RegCloseKey( hklmsub1 );
3061 res = RegOpenKeyExA(hklm, "subkey1", 0, KEY_READ, &hklmsub1);
3062 ok(res == ERROR_FILE_NOT_FOUND, "test key found in hklm: %d\n", res);
3064 /* final cleanup */
3065 delete_key( hkey );
3066 delete_key( hklm );
3067 delete_key( hkcr );
3068 delete_key( hkeysub1 );
3069 delete_key( hklmsub1 );
3070 delete_key( hkcrsub1 );
3071 delete_key( hklmsub2 );
3072 delete_key( hkcrsub2 );
3073 RegCloseKey( hkey );
3074 RegCloseKey( hklm );
3075 RegCloseKey( hkcr );
3076 RegCloseKey( hkeysub1 );
3077 RegCloseKey( hklmsub1 );
3078 RegCloseKey( hkcrsub1 );
3079 RegCloseKey( hklmsub2 );
3080 RegCloseKey( hkcrsub2 );
3083 static void test_classesroot_enum(void)
3085 HKEY hkcu=0, hklm=0, hkcr=0, hkcusub[2]={0}, hklmsub[2]={0};
3086 DWORD size;
3087 static CHAR buffer[2];
3088 LONG res;
3090 /* prepare initial testing env in HKCU */
3091 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", &hkcu ))
3093 delete_key( hkcu );
3094 RegCloseKey( hkcu );
3096 res = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", 0, NULL, 0,
3097 KEY_SET_VALUE|KEY_ENUMERATE_SUB_KEYS, NULL, &hkcu, NULL );
3099 if (res != ERROR_SUCCESS)
3101 skip("failed to add a user class\n");
3102 return;
3105 res = RegOpenKeyA( HKEY_CLASSES_ROOT, "WineTestCls", &hkcr );
3106 todo_wine ok(res == ERROR_SUCCESS ||
3107 broken(res == ERROR_FILE_NOT_FOUND /* WinNT */),
3108 "test key not found in hkcr: %d\n", res);
3109 if (res)
3111 skip("HKCR key merging not supported\n");
3112 delete_key( hkcu );
3113 RegCloseKey( hkcu );
3114 return;
3117 res = RegSetValueExA( hkcu, "X", 0, REG_SZ, (const BYTE *) "AA", 3 );
3118 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", res);
3119 res = RegSetValueExA( hkcu, "Y", 0, REG_SZ, (const BYTE *) "B", 2 );
3120 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", res);
3121 res = RegCreateKeyA( hkcu, "A", &hkcusub[0] );
3122 ok(res == ERROR_SUCCESS, "RegCreateKeyA failed: %d\n", res);
3123 res = RegCreateKeyA( hkcu, "B", &hkcusub[1] );
3124 ok(res == ERROR_SUCCESS, "RegCreateKeyA failed: %d\n", res);
3126 /* test on values in HKCU */
3127 size = sizeof(buffer);
3128 res = RegEnumValueA( hkcr, 0, buffer, &size, NULL, NULL, NULL, NULL );
3129 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3130 ok(!strcmp( buffer, "X" ), "expected 'X', got '%s'\n", buffer);
3131 size = sizeof(buffer);
3132 res = RegEnumValueA( hkcr, 1, buffer, &size, NULL, NULL, NULL, NULL );
3133 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3134 ok(!strcmp( buffer, "Y" ), "expected 'Y', got '%s'\n", buffer);
3135 size = sizeof(buffer);
3136 res = RegEnumValueA( hkcr, 2, buffer, &size, NULL, NULL, NULL, NULL );
3137 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
3139 res = RegEnumKeyA( hkcr, 0, buffer, size );
3140 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3141 ok(!strcmp( buffer, "A" ), "expected 'A', got '%s'\n", buffer);
3142 res = RegEnumKeyA( hkcr, 1, buffer, size );
3143 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3144 ok(!strcmp( buffer, "B" ), "expected 'B', got '%s'\n", buffer);
3145 res = RegEnumKeyA( hkcr, 2, buffer, size );
3146 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
3148 /* prepare test env in HKLM */
3149 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", &hklm ))
3151 delete_key( hklm );
3152 RegCloseKey( hklm );
3155 res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", 0, NULL, 0,
3156 KEY_SET_VALUE|KEY_ENUMERATE_SUB_KEYS, NULL, &hklm, NULL );
3158 if (res == ERROR_ACCESS_DENIED)
3160 RegCloseKey( hkcusub[0] );
3161 RegCloseKey( hkcusub[1] );
3162 delete_key( hkcu );
3163 RegCloseKey( hkcu );
3164 RegCloseKey( hkcr );
3165 skip("not enough privileges to add a system class\n");
3166 return;
3169 res = RegSetValueExA( hklm, "X", 0, REG_SZ, (const BYTE *) "AB", 3 );
3170 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", res);
3171 res = RegSetValueExA( hklm, "Z", 0, REG_SZ, (const BYTE *) "C", 2 );
3172 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", res);
3173 res = RegCreateKeyA( hklm, "A", &hklmsub[0] );
3174 ok(res == ERROR_SUCCESS, "RegCreateKeyA failed: %d\n", res);
3175 res = RegCreateKeyA( hklm, "C", &hklmsub[1] );
3176 ok(res == ERROR_SUCCESS, "RegCreateKeyA failed: %d\n", res);
3178 /* test on values/keys in both HKCU and HKLM */
3179 size = sizeof(buffer);
3180 res = RegEnumValueA( hkcr, 0, buffer, &size, NULL, NULL, NULL, NULL );
3181 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3182 ok(!strcmp( buffer, "X" ), "expected 'X', got '%s'\n", buffer);
3183 size = sizeof(buffer);
3184 res = RegEnumValueA( hkcr, 1, buffer, &size, NULL, NULL, NULL, NULL );
3185 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3186 ok(!strcmp( buffer, "Y" ), "expected 'Y', got '%s'\n", buffer);
3187 size = sizeof(buffer);
3188 res = RegEnumValueA( hkcr, 2, buffer, &size, NULL, NULL, NULL, NULL );
3189 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3190 ok(!strcmp( buffer, "Z" ), "expected 'Z', got '%s'\n", buffer);
3191 size = sizeof(buffer);
3192 res = RegEnumValueA( hkcr, 3, buffer, &size, NULL, NULL, NULL, NULL );
3193 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
3195 res = RegEnumKeyA( hkcr, 0, buffer, size );
3196 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3197 ok(!strcmp( buffer, "A" ), "expected 'A', got '%s'\n", buffer);
3198 res = RegEnumKeyA( hkcr, 1, buffer, size );
3199 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3200 ok(!strcmp( buffer, "B" ), "expected 'B', got '%s'\n", buffer);
3201 res = RegEnumKeyA( hkcr, 2, buffer, size );
3202 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3203 ok(!strcmp( buffer, "C" ), "expected 'C', got '%s'\n", buffer);
3204 res = RegEnumKeyA( hkcr, 3, buffer, size );
3205 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
3207 /* delete values/keys from HKCU to test only on HKLM */
3208 RegCloseKey( hkcusub[0] );
3209 RegCloseKey( hkcusub[1] );
3210 delete_key( hkcu );
3211 RegCloseKey( hkcu );
3213 size = sizeof(buffer);
3214 res = RegEnumValueA( hkcr, 0, buffer, &size, NULL, NULL, NULL, NULL );
3215 ok(res == ERROR_KEY_DELETED ||
3216 res == ERROR_NO_SYSTEM_RESOURCES, /* Windows XP */
3217 "expected ERROR_KEY_DELETED, got %d\n", res);
3218 size = sizeof(buffer);
3219 res = RegEnumKeyA( hkcr, 0, buffer, size );
3220 ok(res == ERROR_KEY_DELETED ||
3221 res == ERROR_NO_SYSTEM_RESOURCES, /* Windows XP */
3222 "expected ERROR_KEY_DELETED, got %d\n", res);
3224 /* reopen HKCR handle */
3225 RegCloseKey( hkcr );
3226 res = RegOpenKeyA( HKEY_CLASSES_ROOT, "WineTestCls", &hkcr );
3227 ok(res == ERROR_SUCCESS, "test key not found in hkcr: %d\n", res);
3228 if (res) goto cleanup;
3230 /* test on values/keys in HKLM */
3231 size = sizeof(buffer);
3232 res = RegEnumValueA( hkcr, 0, buffer, &size, NULL, NULL, NULL, NULL );
3233 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3234 ok(!strcmp( buffer, "X" ), "expected 'X', got '%s'\n", buffer);
3235 size = sizeof(buffer);
3236 res = RegEnumValueA( hkcr, 1, buffer, &size, NULL, NULL, NULL, NULL );
3237 ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
3238 ok(!strcmp( buffer, "Z" ), "expected 'Z', got '%s'\n", buffer);
3239 size = sizeof(buffer);
3240 res = RegEnumValueA( hkcr, 2, buffer, &size, NULL, NULL, NULL, NULL );
3241 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
3243 res = RegEnumKeyA( hkcr, 0, buffer, size );
3244 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3245 ok(!strcmp( buffer, "A" ), "expected 'A', got '%s'\n", buffer);
3246 res = RegEnumKeyA( hkcr, 1, buffer, size );
3247 ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
3248 ok(!strcmp( buffer, "C" ), "expected 'C', got '%s'\n", buffer);
3249 res = RegEnumKeyA( hkcr, 2, buffer, size );
3250 ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
3252 cleanup:
3253 RegCloseKey( hklmsub[0] );
3254 RegCloseKey( hklmsub[1] );
3255 delete_key( hklm );
3256 RegCloseKey( hklm );
3257 RegCloseKey( hkcr );
3260 static void test_classesroot_mask(void)
3262 HKEY hkey;
3263 LSTATUS res;
3265 res = RegOpenKeyA( HKEY_CLASSES_ROOT, "CLSID", &hkey );
3266 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %d\n", res);
3267 todo_wine ok(IS_HKCR(hkey) || broken(!IS_HKCR(hkey)) /* WinNT */,
3268 "hkcr mask not set in %p\n", hkey);
3269 RegCloseKey( hkey );
3271 res = RegOpenKeyA( HKEY_CURRENT_USER, "Software", &hkey );
3272 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %d\n", res);
3273 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3274 RegCloseKey( hkey );
3276 res = RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software", &hkey );
3277 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %d\n", res);
3278 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3279 RegCloseKey( hkey );
3281 res = RegOpenKeyA( HKEY_USERS, ".Default", &hkey );
3282 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %d\n", res);
3283 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3284 RegCloseKey( hkey );
3286 res = RegOpenKeyA( HKEY_CURRENT_CONFIG, "Software", &hkey );
3287 ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %d\n", res);
3288 ok(!IS_HKCR(hkey), "hkcr mask set in %p\n", hkey);
3289 RegCloseKey( hkey );
3292 static void test_deleted_key(void)
3294 HKEY hkey, hkey2;
3295 char value[20];
3296 DWORD val_count, type;
3297 LONG res;
3299 /* Open the test key, then delete it while it's open */
3300 RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey );
3302 delete_key( hkey_main );
3304 val_count = sizeof(value);
3305 type = 0;
3306 res = RegEnumValueA( hkey, 0, value, &val_count, NULL, &type, 0, 0 );
3307 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3309 res = RegEnumKeyA( hkey, 0, value, sizeof(value) );
3310 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3312 val_count = sizeof(value);
3313 type = 0;
3314 res = RegQueryValueExA( hkey, "test", NULL, &type, (BYTE *)value, &val_count );
3315 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3317 res = RegSetValueExA( hkey, "test", 0, REG_SZ, (const BYTE*)"value", 6);
3318 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3320 res = RegOpenKeyA( hkey, "test", &hkey2 );
3321 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3322 if (res == 0)
3323 RegCloseKey( hkey2 );
3325 res = RegCreateKeyA( hkey, "test", &hkey2 );
3326 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3327 if (res == 0)
3328 RegCloseKey( hkey2 );
3330 res = RegFlushKey( hkey );
3331 ok(res == ERROR_KEY_DELETED, "expect ERROR_KEY_DELETED, got %i\n", res);
3333 RegCloseKey( hkey );
3335 setup_main_key();
3338 static void test_delete_value(void)
3340 LONG res;
3341 char longname[401];
3343 res = RegSetValueExA( hkey_main, "test", 0, REG_SZ, (const BYTE*)"value", 6 );
3344 ok(res == ERROR_SUCCESS, "expect ERROR_SUCCESS, got %i\n", res);
3346 res = RegQueryValueExA( hkey_main, "test", NULL, NULL, NULL, NULL);
3347 ok(res == ERROR_SUCCESS, "expect ERROR_SUCCESS, got %i\n", res);
3349 res = RegDeleteValueA( hkey_main, "test" );
3350 ok(res == ERROR_SUCCESS, "expect ERROR_SUCCESS, got %i\n", res);
3352 res = RegQueryValueExA( hkey_main, "test", NULL, NULL, NULL, NULL);
3353 ok(res == ERROR_FILE_NOT_FOUND, "expect ERROR_FILE_NOT_FOUND, got %i\n", res);
3355 res = RegDeleteValueA( hkey_main, "test" );
3356 ok(res == ERROR_FILE_NOT_FOUND, "expect ERROR_FILE_NOT_FOUND, got %i\n", res);
3358 memset(longname, 'a', 400);
3359 longname[400] = 0;
3360 res = RegDeleteValueA( hkey_main, longname );
3361 ok(res == ERROR_FILE_NOT_FOUND || broken(res == ERROR_MORE_DATA), /* nt4, win2k */
3362 "expect ERROR_FILE_NOT_FOUND, got %i\n", res);
3364 /* Default registry value */
3365 res = RegSetValueExA(hkey_main, "", 0, REG_SZ, (const BYTE *)"value", 6);
3366 ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res);
3368 res = RegQueryValueExA(hkey_main, "", NULL, NULL, NULL, NULL);
3369 ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res);
3371 res = RegDeleteValueA(hkey_main, "" );
3372 ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res);
3374 res = RegQueryValueExA(hkey_main, "", NULL, NULL, NULL, NULL);
3375 ok(res == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", res);
3378 static void test_delete_key_value(void)
3380 HKEY subkey;
3381 LONG ret;
3383 if (!pRegDeleteKeyValueA)
3385 win_skip("RegDeleteKeyValue is not available.\n");
3386 return;
3389 ret = pRegDeleteKeyValueA(NULL, NULL, NULL);
3390 ok(ret == ERROR_INVALID_HANDLE, "got %d\n", ret);
3392 ret = pRegDeleteKeyValueA(hkey_main, NULL, NULL);
3393 ok(ret == ERROR_FILE_NOT_FOUND, "got %d\n", ret);
3395 ret = RegSetValueExA(hkey_main, "test", 0, REG_SZ, (const BYTE*)"value", 6);
3396 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3398 ret = RegQueryValueExA(hkey_main, "test", NULL, NULL, NULL, NULL);
3399 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3401 /* NULL subkey name means delete from open key */
3402 ret = pRegDeleteKeyValueA(hkey_main, NULL, "test");
3403 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3405 ret = RegQueryValueExA(hkey_main, "test", NULL, NULL, NULL, NULL);
3406 ok(ret == ERROR_FILE_NOT_FOUND, "got %d\n", ret);
3408 /* now with real subkey */
3409 ret = RegCreateKeyExA(hkey_main, "Subkey1", 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &subkey, NULL);
3410 ok(!ret, "failed with error %d\n", ret);
3412 ret = RegSetValueExA(subkey, "test", 0, REG_SZ, (const BYTE*)"value", 6);
3413 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3415 ret = RegQueryValueExA(subkey, "test", NULL, NULL, NULL, NULL);
3416 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3418 ret = pRegDeleteKeyValueA(hkey_main, "Subkey1", "test");
3419 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
3421 ret = RegQueryValueExA(subkey, "test", NULL, NULL, NULL, NULL);
3422 ok(ret == ERROR_FILE_NOT_FOUND, "got %d\n", ret);
3424 /* Default registry value */
3425 ret = RegSetValueExA(subkey, "", 0, REG_SZ, (const BYTE *)"value", 6);
3426 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3428 ret = RegQueryValueExA(subkey, "", NULL, NULL, NULL, NULL);
3429 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3431 ret = pRegDeleteKeyValueA(hkey_main, "Subkey1", "" );
3432 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3434 ret = RegQueryValueExA(subkey, "", NULL, NULL, NULL, NULL);
3435 ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
3437 RegDeleteKeyA(subkey, "");
3438 RegCloseKey(subkey);
3441 static void test_RegOpenCurrentUser(void)
3443 HKEY key;
3444 LONG ret;
3446 key = HKEY_CURRENT_USER;
3447 ret = RegOpenCurrentUser(KEY_READ, &key);
3448 ok(!ret, "got %d, error %d\n", ret, GetLastError());
3449 ok(key != HKEY_CURRENT_USER, "got %p\n", key);
3450 RegCloseKey(key);
3453 struct notify_data {
3454 HKEY key;
3455 DWORD flags;
3456 HANDLE event;
3459 static DWORD WINAPI notify_change_thread(void *arg)
3461 struct notify_data *data = arg;
3462 LONG ret;
3464 ret = RegNotifyChangeKeyValue(data->key, TRUE,
3465 REG_NOTIFY_CHANGE_NAME|data->flags, data->event, TRUE);
3466 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3467 return 0;
3470 static void test_RegNotifyChangeKeyValue(void)
3472 struct notify_data data;
3473 HKEY key, subkey, subsubkey;
3474 HANDLE thread;
3475 HANDLE event;
3476 DWORD dwret;
3477 LONG ret;
3479 event = CreateEventW(NULL, FALSE, TRUE, NULL);
3480 ok(event != NULL, "CreateEvent failed, error %u\n", GetLastError());
3481 ret = RegCreateKeyA(hkey_main, "TestKey", &key);
3482 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3484 ret = RegNotifyChangeKeyValue(key, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, event, TRUE);
3485 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3486 dwret = WaitForSingleObject(event, 0);
3487 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", dwret);
3489 ret = RegCreateKeyA(key, "SubKey", &subkey);
3490 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3491 dwret = WaitForSingleObject(event, 0);
3492 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
3494 /* watching deeper keys */
3495 ret = RegNotifyChangeKeyValue(key, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, event, TRUE);
3496 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3497 dwret = WaitForSingleObject(event, 0);
3498 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", dwret);
3500 ret = RegCreateKeyA(subkey, "SubKey", &subsubkey);
3501 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3502 dwret = WaitForSingleObject(event, 0);
3503 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
3505 /* watching deeper values */
3506 ret = RegNotifyChangeKeyValue(key, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, event, TRUE);
3507 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3508 dwret = WaitForSingleObject(event, 0);
3509 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", dwret);
3511 ret = RegSetValueA(subsubkey, NULL, REG_SZ, "SubSubKeyValue", 0);
3512 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3513 dwret = WaitForSingleObject(event, 0);
3514 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
3516 /* don't watch deeper values */
3517 RegCloseKey(key);
3518 ret = RegOpenKeyA(hkey_main, "TestKey", &key);
3519 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3521 ret = RegNotifyChangeKeyValue(key, FALSE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, event, TRUE);
3522 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3523 dwret = WaitForSingleObject(event, 0);
3524 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", dwret);
3526 ret = RegSetValueA(subsubkey, NULL, REG_SZ, "SubSubKeyValueNEW", 0);
3527 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3528 dwret = WaitForSingleObject(event, 0);
3529 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", dwret);
3531 RegDeleteKeyA(subkey, "SubKey");
3532 RegDeleteKeyA(key, "SubKey");
3533 RegCloseKey(subsubkey);
3534 RegCloseKey(subkey);
3535 RegCloseKey(key);
3537 /* test same thread with REG_NOTIFY_THREAD_AGNOSTIC */
3538 ret = RegOpenKeyA(hkey_main, "TestKey", &key);
3539 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3540 ret = RegNotifyChangeKeyValue(key, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_THREAD_AGNOSTIC,
3541 event, TRUE);
3542 if (ret == ERROR_INVALID_PARAMETER)
3544 win_skip("REG_NOTIFY_THREAD_AGNOSTIC is not supported\n");
3545 RegCloseKey(key);
3546 CloseHandle(event);
3547 return;
3550 ret = RegCreateKeyA(key, "SubKey", &subkey);
3551 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3552 dwret = WaitForSingleObject(event, 0);
3553 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
3555 RegDeleteKeyA(key, "SubKey");
3556 RegCloseKey(subkey);
3557 RegCloseKey(key);
3559 /* test different thread without REG_NOTIFY_THREAD_AGNOSTIC */
3560 ret = RegOpenKeyA(hkey_main, "TestKey", &key);
3561 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3563 data.key = key;
3564 data.flags = 0;
3565 data.event = event;
3566 thread = CreateThread(NULL, 0, notify_change_thread, &data, 0, NULL);
3567 WaitForSingleObject(thread, INFINITE);
3568 CloseHandle(thread);
3570 /* the thread exiting causes event to signal on Windows
3571 this is worked around on Windows using REG_NOTIFY_THREAD_AGNOSTIC
3572 Wine already behaves as if the flag is set */
3573 dwret = WaitForSingleObject(event, 0);
3574 todo_wine
3575 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
3576 RegCloseKey(key);
3578 /* test different thread with REG_NOTIFY_THREAD_AGNOSTIC */
3579 ret = RegOpenKeyA(hkey_main, "TestKey", &key);
3580 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3582 data.flags = REG_NOTIFY_THREAD_AGNOSTIC;
3583 thread = CreateThread(NULL, 0, notify_change_thread, &data, 0, NULL);
3584 WaitForSingleObject(thread, INFINITE);
3585 CloseHandle(thread);
3587 dwret = WaitForSingleObject(event, 0);
3588 ok(dwret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", dwret);
3590 ret = RegCreateKeyA(key, "SubKey", &subkey);
3591 ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
3593 dwret = WaitForSingleObject(event, 0);
3594 ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
3596 RegDeleteKeyA(key, "SubKey");
3597 RegDeleteKeyA(key, "");
3598 RegCloseKey(subkey);
3599 RegCloseKey(key);
3600 CloseHandle(event);
3603 static const char *find_counter_value(const char *text, const char *index)
3605 const char *p = text;
3607 while (*p)
3609 if (!strcmp(p, index))
3610 return p + strlen(p) + 1;
3612 p += strlen(p) + 1;
3613 p += strlen(p) + 1;
3616 return NULL;
3619 static void test_counter_values(const char *text, HKEY key)
3621 const char *p = text;
3622 const char *name;
3624 ok(!strcmp(p, "1"), "got first index %s\n", debugstr_a(p));
3625 p += strlen(p) + 1;
3626 ok(!strcmp(p, "1847"), "got first name %s\n", debugstr_a(p));
3627 p += strlen(p) + 1;
3629 while (*p)
3631 unsigned int index = atoi(p);
3633 ok(index > 0, "expected nonzero index\n");
3635 p += strlen(p) + 1;
3636 ok(*p, "name missing for %u\n", index);
3637 p += strlen(p) + 1;
3640 name = find_counter_value(text, "1846");
3641 ok(name != NULL, "did not find name\n");
3642 if (key != HKEY_PERFORMANCE_NLSTEXT)
3643 ok(!strcmp(name, "End Marker"), "got name %s\n", debugstr_a(name));
3646 static void test_help_values(const char *text, HKEY key)
3648 const char *p = text;
3649 const char *name;
3651 while (*p)
3653 unsigned int index = atoi(p);
3655 ok(index > 0, "expected nonzero index\n");
3657 p += strlen(p) + 1;
3658 p += strlen(p) + 1;
3661 name = find_counter_value(text, "1847");
3662 ok(name != NULL, "did not find name\n");
3663 if (key != HKEY_PERFORMANCE_NLSTEXT)
3664 ok(!strcmp(name, "End Marker"), "got name %s\n", debugstr_a(name));
3667 static void test_performance_keys(void)
3669 static const HKEY keys[] = {HKEY_PERFORMANCE_DATA, HKEY_PERFORMANCE_TEXT, HKEY_PERFORMANCE_NLSTEXT};
3670 static const char *const names[] = {NULL, "", "Global", "2", "invalid counter name", "System"};
3671 DWORD size, type, sysname_len, expect_size, key_count, value_count;
3672 LARGE_INTEGER perftime1, perftime2, systime1, systime2, freq;
3673 WCHAR sysname[MAX_COMPUTERNAME_LENGTH + 1];
3674 unsigned int buffer_size = 1024 * 1024;
3675 void *buffer, *bufferW;
3676 PERF_DATA_BLOCK *data;
3677 union
3679 FILETIME f;
3680 LONGLONG l;
3681 } file_time;
3682 unsigned int i, j;
3683 HKEY key;
3684 LONG ret;
3686 buffer = malloc(buffer_size);
3688 sysname_len = ARRAY_SIZE(sysname);
3689 GetComputerNameW(sysname, &sysname_len);
3691 for (i = 0; i < ARRAY_SIZE(keys); ++i)
3693 winetest_push_context("key %p", keys[i]);
3695 for (j = 0; j < ARRAY_SIZE(names); ++j)
3697 winetest_push_context("value %s", debugstr_a(names[j]));
3699 QueryPerformanceFrequency(&freq);
3701 size = 0;
3702 ret = RegQueryValueExA(keys[i], names[j], NULL, NULL, NULL, &size);
3703 todo_wine_if (keys[i] != HKEY_PERFORMANCE_DATA)
3704 ok(ret == ERROR_MORE_DATA, "got %u\n", ret);
3705 ok(!size, "got size %u\n", size);
3707 size = 10;
3708 ret = RegQueryValueExA(keys[i], names[j], NULL, NULL, buffer, &size);
3709 todo_wine_if (keys[i] != HKEY_PERFORMANCE_DATA)
3710 ok(ret == ERROR_MORE_DATA, "got %u\n", ret);
3711 todo_wine_if (keys[i] == HKEY_PERFORMANCE_DATA)
3712 ok(size == 10, "got size %u\n", size);
3714 size = buffer_size;
3715 ret = RegQueryValueExA(keys[i], names[j], NULL, NULL, NULL, &size);
3716 todo_wine_if (keys[i] != HKEY_PERFORMANCE_DATA)
3717 ok(ret == ERROR_MORE_DATA, "got %u\n", ret);
3719 QueryPerformanceCounter(&perftime1);
3720 NtQuerySystemTime(&systime1);
3722 size = buffer_size;
3723 type = 0xdeadbeef;
3724 ret = RegQueryValueExA(keys[i], names[j], NULL, &type, buffer, &size);
3725 todo_wine_if (keys[i] != HKEY_PERFORMANCE_DATA)
3727 ok(!ret, "got %u\n", ret);
3728 ok(type == REG_BINARY, "got type %u\n", type);
3729 ok(size >= sizeof(PERF_DATA_BLOCK) && size < buffer_size, "got size %u\n", size);
3732 if (ret)
3734 winetest_pop_context();
3735 continue;
3738 QueryPerformanceCounter(&perftime2);
3739 NtQuerySystemTime(&systime2);
3741 data = buffer;
3742 ok(!wcsncmp(data->Signature, L"PERF", 4), "got signature %s\n",
3743 debugstr_wn(data->Signature, 4));
3744 ok(data->LittleEndian == 1, "got endianness %u\n", data->LittleEndian);
3745 ok(data->Version == 1, "got version %u\n", data->Version);
3746 ok(data->Revision == 1, "got version %u\n", data->Revision);
3747 ok(data->TotalByteLength == size, "expected size %u, got %u\n",
3748 size, data->TotalByteLength);
3750 expect_size = sizeof(PERF_DATA_BLOCK) + data->SystemNameLength;
3751 expect_size = (expect_size + 7) & ~7;
3753 ok(data->HeaderLength == expect_size, "expected header size %u, got %u\n",
3754 expect_size, data->HeaderLength);
3755 /* todo: test objects... */
3756 todo_wine ok(data->DefaultObject == 238, "got default object %u\n", data->DefaultObject);
3758 ok(data->PerfTime.QuadPart >= perftime1.QuadPart
3759 && data->PerfTime.QuadPart <= perftime2.QuadPart,
3760 "got times %I64u, %I64u, %I64u\n",
3761 perftime1.QuadPart, data->PerfTime.QuadPart, perftime2.QuadPart);
3762 ok(data->PerfFreq.QuadPart == freq.QuadPart, "expected frequency %I64u, got %I64u\n",
3763 freq.QuadPart, data->PerfFreq.QuadPart);
3764 ok(data->PerfTime100nSec.QuadPart >= systime1.QuadPart
3765 && data->PerfTime100nSec.QuadPart <= systime2.QuadPart,
3766 "got times %I64u, %I64u, %I64u\n",
3767 systime1.QuadPart, data->PerfTime100nSec.QuadPart, systime2.QuadPart);
3768 SystemTimeToFileTime(&data->SystemTime, &file_time.f);
3769 /* SYSTEMTIME has a granularity of 1 ms */
3770 ok(file_time.l >= systime1.QuadPart - 10000 && file_time.l <= systime2.QuadPart,
3771 "got times %I64u, %I64u, %I64u\n", systime1.QuadPart, file_time.l, systime2.QuadPart);
3773 ok(data->SystemNameLength == (sysname_len + 1) * sizeof(WCHAR),
3774 "expected name len %u, got %u\n",
3775 (sysname_len + 1) * sizeof(WCHAR), data->SystemNameLength);
3776 ok(data->SystemNameOffset == sizeof(PERF_DATA_BLOCK),
3777 "got name offset %u\n", data->SystemNameOffset);
3778 ok(!wcscmp(sysname, (const WCHAR *)(data + 1)), "expected name %s, got %s\n",
3779 debugstr_w(sysname), debugstr_w((const WCHAR *)(data + 1)));
3781 winetest_pop_context();
3784 /* test the "Counter" value */
3786 size = 0xdeadbeef;
3787 ret = RegQueryValueExA(keys[i], "cOuNtEr", NULL, NULL, NULL, &size);
3788 todo_wine
3790 ok(!ret, "got %u\n", ret);
3791 ok(size > 0 && size < 0xdeadbeef, "got size %u\n", size);
3794 type = 0xdeadbeef;
3795 size = 0;
3796 ret = RegQueryValueExA(keys[i], "cOuNtEr", NULL, &type, buffer, &size);
3797 todo_wine_if (keys[i] != HKEY_PERFORMANCE_DATA)
3798 ok(ret == ERROR_MORE_DATA, "got %u\n", ret);
3799 todo_wine ok(size > 0, "got size %u\n", size);
3801 type = 0xdeadbeef;
3802 size = buffer_size;
3803 ret = RegQueryValueExA(keys[i], "cOuNtEr", NULL, &type, buffer, &size);
3804 todo_wine_if (keys[i] != HKEY_PERFORMANCE_DATA)
3805 ok(!ret, "got %u\n", ret);
3806 todo_wine ok(type == REG_MULTI_SZ, "got type %u\n", type);
3807 if (type == REG_MULTI_SZ)
3808 test_counter_values(buffer, keys[i]);
3810 type = 0xdeadbeef;
3811 size = buffer_size;
3812 ret = RegQueryValueExA(keys[i], "cOuNtErwine", NULL, &type, buffer, &size);
3813 todo_wine_if (keys[i] != HKEY_PERFORMANCE_DATA)
3814 ok(!ret, "got %u\n", ret);
3815 todo_wine ok(type == REG_MULTI_SZ, "got type %u\n", type);
3816 if (type == REG_MULTI_SZ)
3817 test_counter_values(buffer, keys[i]);
3819 size = 0;
3820 ret = RegQueryValueExW(keys[i], L"cOuNtEr", NULL, NULL, NULL, &size);
3821 todo_wine
3823 ok(!ret, "got %u\n", ret);
3824 ok(size > 0, "got size %u\n", size);
3827 bufferW = malloc(size);
3829 type = 0xdeadbeef;
3830 ret = RegQueryValueExW(keys[i], L"cOuNtEr", NULL, &type, bufferW, &size);
3831 todo_wine
3833 ok(!ret, "got %u\n", ret);
3834 ok(type == REG_MULTI_SZ, "got type %u\n", type);
3836 if (type == REG_MULTI_SZ)
3838 WideCharToMultiByte(CP_ACP, 0, bufferW, size / sizeof(WCHAR), buffer, buffer_size, NULL, NULL);
3839 test_counter_values(buffer, keys[i]);
3842 /* test the "Help" value */
3844 size = 0xdeadbeef;
3845 ret = RegQueryValueExA(keys[i], "hElP", NULL, NULL, NULL, &size);
3846 todo_wine
3848 ok(!ret, "got %u\n", ret);
3849 ok(size > 0 && size < 0xdeadbeef, "got size %u\n", size);
3852 type = 0xdeadbeef;
3853 size = 0;
3854 ret = RegQueryValueExA(keys[i], "hElP", NULL, &type, buffer, &size);
3855 todo_wine_if (keys[i] != HKEY_PERFORMANCE_DATA)
3856 ok(ret == ERROR_MORE_DATA, "got %u\n", ret);
3857 todo_wine ok(size > 0, "got size %u\n", size);
3859 type = 0xdeadbeef;
3860 size = buffer_size;
3861 ret = RegQueryValueExA(keys[i], "hElP", NULL, &type, buffer, &size);
3862 todo_wine_if (keys[i] != HKEY_PERFORMANCE_DATA)
3863 ok(!ret, "got %u\n", ret);
3864 todo_wine ok(type == REG_MULTI_SZ, "got type %u\n", type);
3865 if (type == REG_MULTI_SZ)
3866 test_help_values(buffer, keys[i]);
3868 type = 0xdeadbeef;
3869 size = buffer_size;
3870 ret = RegQueryValueExA(keys[i], "hElPwine", NULL, &type, buffer, &size);
3871 todo_wine_if (keys[i] != HKEY_PERFORMANCE_DATA)
3872 ok(!ret, "got %u\n", ret);
3873 todo_wine ok(type == REG_MULTI_SZ, "got type %u\n", type);
3874 if (type == REG_MULTI_SZ)
3875 test_help_values(buffer, keys[i]);
3877 size = 0;
3878 ret = RegQueryValueExW(keys[i], L"hElP", NULL, NULL, NULL, &size);
3879 todo_wine
3881 ok(!ret, "got %u\n", ret);
3882 ok(size > 0, "got size %u\n", size);
3885 bufferW = malloc(size);
3887 type = 0xdeadbeef;
3888 ret = RegQueryValueExW(keys[i], L"hElP", NULL, &type, bufferW, &size);
3889 todo_wine
3891 ok(!ret, "got %u\n", ret);
3892 ok(type == REG_MULTI_SZ, "got type %u\n", type);
3894 if (type == REG_MULTI_SZ)
3896 WideCharToMultiByte(CP_ACP, 0, bufferW, size / sizeof(WCHAR), buffer, buffer_size, NULL, NULL);
3897 test_help_values(buffer, keys[i]);
3900 /* test other registry APIs */
3902 ret = RegOpenKeyA(keys[i], NULL, &key);
3903 todo_wine ok(ret == ERROR_INVALID_HANDLE, "got %u\n", ret);
3905 ret = RegOpenKeyA(keys[i], "Global", &key);
3906 todo_wine_if (keys[i] == HKEY_PERFORMANCE_DATA)
3907 ok(ret == ERROR_INVALID_HANDLE, "got %u\n", ret);
3909 ret = RegOpenKeyExA(keys[i], "Global", 0, KEY_READ, &key);
3910 todo_wine_if (keys[i] == HKEY_PERFORMANCE_DATA)
3911 ok(ret == ERROR_INVALID_HANDLE, "got %u\n", ret);
3913 size = 0;
3914 ret = RegQueryValueA(keys[i], "Global", NULL, (LONG *)&size);
3915 todo_wine_if (keys[i] == HKEY_PERFORMANCE_DATA)
3916 ok(ret == ERROR_INVALID_HANDLE, "got %u\n", ret);
3918 ret = RegSetValueA(keys[i], "Global", REG_SZ, "dummy", 5);
3919 todo_wine_if (keys[i] == HKEY_PERFORMANCE_DATA)
3920 ok(ret == ERROR_INVALID_HANDLE, "got %u\n", ret);
3922 ret = RegQueryInfoKeyA(keys[i], NULL, NULL, NULL, &key_count, NULL,
3923 NULL, &value_count, NULL, NULL, NULL, NULL);
3924 todo_wine_if (keys[i] != HKEY_PERFORMANCE_DATA)
3925 ok(!ret, "got %u\n", ret);
3926 todo_wine ok(!key_count, "got %u subkeys\n", key_count);
3927 todo_wine ok(value_count == 2, "got %u values\n", value_count);
3929 size = buffer_size;
3930 ret = RegEnumValueA(keys[i], 0, buffer, &size, NULL, NULL, NULL, NULL);
3931 todo_wine ok(ret == ERROR_MORE_DATA, "got %u\n", ret);
3932 ok(size == buffer_size, "got size %u\n", size);
3934 ret = RegCloseKey(keys[i]);
3935 ok(!ret, "got %u\n", ret);
3937 ret = RegCloseKey(keys[i]);
3938 ok(!ret, "got %u\n", ret);
3940 winetest_pop_context();
3943 ret = RegSetValueExA(HKEY_PERFORMANCE_DATA, "Global", 0, REG_SZ, (const BYTE *)"dummy", 5);
3944 todo_wine ok(ret == ERROR_INVALID_HANDLE, "got %u\n", ret);
3946 ret = RegSetValueExA(HKEY_PERFORMANCE_TEXT, "Global", 0, REG_SZ, (const BYTE *)"dummy", 5);
3947 todo_wine ok(ret == ERROR_BADKEY, "got %u\n", ret);
3949 ret = RegSetValueExA(HKEY_PERFORMANCE_NLSTEXT, "Global", 0, REG_SZ, (const BYTE *)"dummy", 5);
3950 todo_wine ok(ret == ERROR_BADKEY, "got %u\n", ret);
3952 if (pRegSetKeyValueW)
3954 ret = pRegSetKeyValueW(HKEY_PERFORMANCE_DATA, NULL, L"Global", REG_SZ, L"dummy", 10);
3955 todo_wine ok(ret == ERROR_INVALID_HANDLE, "got %u\n", ret);
3957 ret = pRegSetKeyValueW(HKEY_PERFORMANCE_TEXT, NULL, L"Global", REG_SZ, L"dummy", 10);
3958 todo_wine ok(ret == ERROR_BADKEY, "got %u\n", ret);
3960 ret = pRegSetKeyValueW(HKEY_PERFORMANCE_NLSTEXT, NULL, L"Global", REG_SZ, L"dummy", 10);
3961 todo_wine ok(ret == ERROR_BADKEY, "got %u\n", ret);
3964 ret = RegEnumKeyA(HKEY_PERFORMANCE_DATA, 0, buffer, buffer_size);
3965 todo_wine ok(ret == ERROR_INVALID_HANDLE, "got %u\n", ret);
3967 ret = RegEnumKeyA(HKEY_PERFORMANCE_TEXT, 0, buffer, buffer_size);
3968 todo_wine ok(ret == ERROR_NO_MORE_ITEMS, "got %u\n", ret);
3970 ret = RegEnumKeyA(HKEY_PERFORMANCE_NLSTEXT, 0, buffer, buffer_size);
3971 todo_wine ok(ret == ERROR_NO_MORE_ITEMS, "got %u\n", ret);
3973 free(buffer);
3976 static void test_perflib_key(void)
3978 unsigned int primary_lang = PRIMARYLANGID(GetUserDefaultLangID());
3979 unsigned int buffer_size = 1024 * 1024;
3980 OBJECT_NAME_INFORMATION *name_info;
3981 HKEY perflib_key, key, key2;
3982 OBJECT_ATTRIBUTES attr;
3983 UNICODE_STRING string;
3984 char lang_name[4];
3985 char *buffer;
3986 DWORD size;
3987 LONG ret;
3989 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
3990 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Perflib", 0, KEY_READ, &perflib_key);
3991 ok(!ret, "got %u\n", ret);
3993 ret = RegOpenKeyExA(perflib_key, "009", 0, KEY_READ, &key);
3994 ok(!ret, "got %u\n", ret);
3995 /* English always returns TEXT; most other languages return NLSTEXT, but
3996 * some (e.g. Hindi) return TEXT */
3997 ok(key == HKEY_PERFORMANCE_TEXT || key == HKEY_PERFORMANCE_NLSTEXT, "got key %p\n", key);
3999 ret = RegCloseKey(key);
4000 ok(!ret, "got %u\n", ret);
4002 RtlInitUnicodeString(&string, L"009");
4003 InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE, perflib_key, NULL);
4004 ret = NtOpenKey((HANDLE *)&key, KEY_ALL_ACCESS, &attr);
4005 ok(ret == STATUS_PREDEFINED_HANDLE || ret == STATUS_ACCESS_DENIED
4006 || ret == STATUS_SUCCESS /* Win < 7 */, "got %#x\n", ret);
4007 if (ret == STATUS_PREDEFINED_HANDLE)
4008 ok(!is_special_key(key), "expected a normal handle, got %p\n", key);
4009 else if (ret == STATUS_SUCCESS)
4010 ok(key == HKEY_PERFORMANCE_TEXT, "got key %p\n", key);
4011 else
4013 skip("Not enough permissions to test the perflib key.\n");
4014 RegCloseKey(perflib_key);
4015 return;
4018 buffer = malloc(buffer_size);
4020 ret = NtQueryKey(key, KeyFullInformation, buffer, buffer_size, &size);
4021 ok(ret == STATUS_INVALID_HANDLE, "got %#x\n", ret);
4023 ret = NtEnumerateKey(key, 0, KeyFullInformation, buffer, buffer_size, &size);
4024 ok(ret == STATUS_INVALID_HANDLE, "got %#x\n", ret);
4026 RtlInitUnicodeString(&string, L"counter");
4027 ret = NtQueryValueKey(key, &string, KeyValuePartialInformation, buffer, buffer_size, &size);
4028 ok(ret == STATUS_INVALID_HANDLE, "got %#x\n", ret);
4030 ret = NtEnumerateValueKey(key, 0, KeyValuePartialInformation, buffer, buffer_size, &size);
4031 ok(ret == STATUS_INVALID_HANDLE, "got %#x\n", ret);
4033 ret = NtSetValueKey(key, &string, 0, REG_SZ, "test", 5);
4034 ok(ret == STATUS_INVALID_HANDLE, "got %#x\n", ret);
4036 ret = NtDeleteValueKey(key, &string);
4037 ok(ret == STATUS_INVALID_HANDLE, "got %#x\n", ret);
4039 ret = NtDeleteKey(key);
4040 ok(ret == STATUS_INVALID_HANDLE, "got %#x\n", ret);
4042 RtlInitUnicodeString(&string, L"subkey");
4043 InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE, key, NULL);
4044 ret = NtOpenKey((HANDLE *)&key2, KEY_READ, &attr);
4045 if (is_special_key(key))
4046 ok(ret == STATUS_INVALID_HANDLE, "got %#x\n", ret);
4047 else
4048 ok(ret == STATUS_OBJECT_NAME_NOT_FOUND
4049 || broken(ret == STATUS_INVALID_HANDLE) /* WoW64 */, "got %#x\n", ret);
4051 ret = NtCreateKey((HANDLE *)&key2, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL);
4052 if (is_special_key(key))
4053 ok(ret == STATUS_INVALID_HANDLE, "got %#x\n", ret);
4054 else
4055 ok(!ret || broken(ret == STATUS_ACCESS_DENIED) /* w8adm */
4056 || broken(ret == STATUS_INVALID_HANDLE) /* WoW64 */, "got %#x\n", ret);
4057 if (!ret)
4059 NtDeleteKey(key2);
4060 NtClose(key2);
4063 /* it's a real handle, though */
4064 ret = NtQueryObject(key, ObjectNameInformation, buffer, buffer_size, &size);
4065 if (is_special_key(key))
4066 ok(ret == STATUS_INVALID_HANDLE, "got %#x\n", ret);
4067 else
4068 ok(!ret, "got %#x\n", ret);
4069 if (!ret)
4071 name_info = (OBJECT_NAME_INFORMATION *)buffer;
4072 ok(!wcsicmp(name_info->Name.Buffer, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT"
4073 "\\CurrentVersion\\Perflib\\009"), "got name %s\n", debugstr_w(name_info->Name.Buffer));
4076 ret = NtClose(key);
4077 if (is_special_key(key))
4078 ok(ret == STATUS_INVALID_HANDLE, "got %#x\n", ret);
4079 else
4080 ok(!ret, "got %#x\n", ret);
4082 /* multilingual support was not really completely thought through */
4084 sprintf(lang_name, "%03x", primary_lang);
4085 if (primary_lang != LANG_ENGLISH)
4087 ret = RegOpenKeyExA(perflib_key, lang_name, 0, KEY_READ, &key);
4088 todo_wine ok(!ret, "got %u\n", ret);
4089 ok(!is_special_key(key), "expected a normal handle, got %p\n", key);
4091 ret = RegQueryValueExA(key, "counter", NULL, NULL, (BYTE *)buffer, &size);
4092 todo_wine ok(ret == ERROR_FILE_NOT_FOUND, "got %u\n", ret);
4094 ret = RegCloseKey(key);
4095 todo_wine ok(!ret, "got %u\n", ret);
4098 ret = RegCloseKey(perflib_key);
4099 ok(!ret, "got %u\n", ret);
4101 RtlInitUnicodeString(&string, L"\\Registry\\PerfData");
4102 InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE, NULL, NULL);
4103 ret = NtOpenKey((HANDLE *)&key, KEY_READ, &attr);
4104 todo_wine ok(ret == STATUS_OBJECT_NAME_NOT_FOUND, "got %#x\n", ret);
4106 free(buffer);
4109 static void test_RegLoadMUIString(void)
4111 HMODULE hUser32, hResDll, hFile;
4112 int (WINAPI *pLoadStringW)(HMODULE, UINT, WCHAR *, int);
4113 LONG ret;
4114 HKEY hkey;
4115 DWORD type, size, text_size;
4116 UINT i;
4117 char buf[64], *p, sysdir[MAX_PATH];
4118 char with_env_var[128], filename[MAX_PATH], tmp_path[MAX_PATH];
4119 WCHAR textW[64], bufW[64];
4120 WCHAR curdirW[MAX_PATH], sysdirW[MAX_PATH];
4121 const static char tz_value[] = "MUI_Std";
4122 const static WCHAR tz_valueW[] = L"MUI_Std";
4123 struct {
4124 const char* value;
4125 DWORD type;
4126 BOOL use_sysdir;
4127 DWORD expected;
4128 DWORD broken_ret;
4129 } test_case[] = {
4130 /* 0 */
4131 { "", REG_SZ, FALSE, ERROR_INVALID_DATA },
4132 { "not a MUI string", REG_SZ, FALSE, ERROR_INVALID_DATA },
4133 { "@unknown.dll", REG_SZ, TRUE, ERROR_INVALID_DATA },
4134 { "@unknown.dll,-10", REG_SZ, TRUE, ERROR_FILE_NOT_FOUND },
4135 /* 4 */
4136 { with_env_var, REG_SZ, FALSE, ERROR_SUCCESS },
4137 { with_env_var, REG_EXPAND_SZ, FALSE, ERROR_SUCCESS },
4138 { "%WineMuiTest1%", REG_EXPAND_SZ, TRUE, ERROR_INVALID_DATA },
4139 { "@%WineMuiTest2%", REG_EXPAND_SZ, TRUE, ERROR_SUCCESS },
4140 /* 8 */
4141 { "@%WineMuiExe%,a", REG_SZ, FALSE, ERROR_INVALID_DATA },
4142 { "@%WineMuiExe%,-4", REG_SZ, FALSE, ERROR_NOT_FOUND, ERROR_FILE_NOT_FOUND },
4143 { "@%WineMuiExe%,-39", REG_SZ, FALSE, ERROR_RESOURCE_NAME_NOT_FOUND },
4144 { "@%WineMuiDat%,-16", REG_EXPAND_SZ, FALSE, ERROR_BAD_EXE_FORMAT, ERROR_FILE_NOT_FOUND },
4147 if (!pRegLoadMUIStringA || !pRegLoadMUIStringW)
4149 win_skip("RegLoadMUIString is not available\n");
4150 return;
4153 hUser32 = LoadLibraryA("user32.dll");
4154 ok(hUser32 != NULL, "cannot load user32.dll\n");
4155 pLoadStringW = (void *)GetProcAddress(hUser32, "LoadStringW");
4156 ok(pLoadStringW != NULL, "failed to get LoadStringW address\n");
4158 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
4159 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\UTC", 0,
4160 KEY_READ, &hkey);
4161 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
4163 size = ARRAY_SIZE(buf);
4164 ret = RegQueryValueExA(hkey, tz_value, NULL, &type, (BYTE *)buf, &size);
4165 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
4166 ok(buf[0] == '@', "got %s\n", buf);
4168 /* setup MUI string for tests */
4169 strcpy(with_env_var, "@%windir%\\system32\\");
4170 strcat(with_env_var, &buf[1]);
4171 SetEnvironmentVariableA("WineMuiTest1", buf);
4172 SetEnvironmentVariableA("WineMuiTest2", &buf[1]);
4174 /* load expecting text */
4175 p = strrchr(buf, ',');
4176 *p = '\0';
4177 i = atoi(p + 2); /* skip ',-' */
4178 hResDll = LoadLibraryExA(&buf[1], NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
4179 memset(textW, 0xaa, sizeof(textW));
4180 ret = pLoadStringW(hResDll, i, textW, ARRAY_SIZE(textW));
4181 ok(ret > 0, "failed to load string resource\n");
4182 text_size = (ret + 1) * sizeof(WCHAR);
4183 FreeLibrary(hResDll);
4184 FreeLibrary(hUser32);
4186 ret = GetSystemDirectoryW(sysdirW, ARRAY_SIZE(sysdirW));
4187 ok(ret > 0, "GetSystemDirectoryW failed\n");
4188 ret = GetSystemDirectoryA(sysdir, ARRAY_SIZE(sysdir));
4189 ok(ret > 0, "GetSystemDirectoryA failed\n");
4191 /* change the current directory to system32 */
4192 GetCurrentDirectoryW(ARRAY_SIZE(curdirW), curdirW);
4193 SetCurrentDirectoryW(sysdirW);
4195 size = 0xdeadbeef;
4196 ret = pRegLoadMUIStringW(hkey, tz_valueW, NULL, 0, &size, 0, NULL);
4197 ok(ret == ERROR_MORE_DATA, "got %d, expected ERROR_MORE_DATA\n", ret);
4198 ok(size == text_size, "got %u, expected %u\n", size, text_size);
4200 memset(bufW, 0xff, sizeof(bufW));
4201 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)+1, &size, 0, NULL);
4202 ok(ret == ERROR_INVALID_PARAMETER, "got %d, expected ERROR_INVALID_PARAMETER\n", ret);
4203 ok(bufW[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW[0]);
4205 size = 0xdeadbeef;
4206 memset(bufW, 0xff, sizeof(bufW));
4207 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)*2, &size, 0, NULL);
4208 ok(ret == ERROR_MORE_DATA, "got %d, expected ERROR_MORE_DATA\n", ret);
4209 ok(size == text_size || broken(size == text_size + sizeof(WCHAR) /* vista */),
4210 "got %u, expected %u\n", size, text_size);
4211 ok(bufW[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW[0]);
4213 memset(bufW, 0xff, sizeof(bufW));
4214 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)*2, &size, REG_MUI_STRING_TRUNCATE, NULL);
4215 ok(ret == ERROR_INVALID_PARAMETER, "got %d, expected ERROR_INVALID_PARAMETER\n", ret);
4216 ok(bufW[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW[0]);
4218 memset(bufW, 0xff, sizeof(bufW));
4219 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)*2, NULL, 0xdeadbeef, NULL);
4220 ok(ret == ERROR_INVALID_PARAMETER, "got %d, expected ERROR_INVALID_PARAMETER\n", ret);
4221 ok(bufW[0] == 0xffff, "got 0x%04x, expected 0xffff\n", bufW[0]);
4223 memset(bufW, 0xff, sizeof(bufW));
4224 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, sizeof(WCHAR)*2, NULL, REG_MUI_STRING_TRUNCATE, NULL);
4225 ok(ret == ERROR_SUCCESS, "got %d, expected ERROR_SUCCESS\n", ret);
4226 ok(bufW[0] == textW[0], "got 0x%04x, expected 0x%04x\n", bufW[0], textW[0]);
4227 ok(bufW[1] == 0, "got 0x%04x, expected nul\n", bufW[1]);
4229 size = 0xdeadbeef;
4230 memset(bufW, 0xff, sizeof(bufW));
4231 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, ARRAY_SIZE(bufW), &size, 0, NULL);
4232 ok(ret == ERROR_SUCCESS, "got %d, expected ERROR_SUCCESS\n", ret);
4233 ok(size == text_size, "got %u, expected %u\n", size, text_size);
4234 ok(!memcmp(textW, bufW, size), "got %s, expected %s\n",
4235 wine_dbgstr_wn(bufW, size / sizeof(WCHAR)), wine_dbgstr_wn(textW, text_size / sizeof(WCHAR)));
4237 ret = pRegLoadMUIStringA(hkey, tz_value, buf, ARRAY_SIZE(buf), &size, 0, NULL);
4238 ok(ret == ERROR_CALL_NOT_IMPLEMENTED, "got %d, expected ERROR_CALL_NOT_IMPLEMENTED\n", ret);
4240 /* change the current directory to other than system32 directory */
4241 SetCurrentDirectoryA("\\");
4243 size = 0xdeadbeef;
4244 memset(bufW, 0xff, sizeof(bufW));
4245 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, ARRAY_SIZE(bufW), &size, 0, sysdirW);
4246 ok(ret == ERROR_SUCCESS, "got %d, expected ERROR_SUCCESS\n", ret);
4247 ok(size == text_size, "got %u, expected %u\n", size, text_size);
4248 ok(!memcmp(textW, bufW, size), "got %s, expected %s\n",
4249 wine_dbgstr_wn(bufW, size / sizeof(WCHAR)), wine_dbgstr_wn(textW, text_size / sizeof(WCHAR)));
4251 ret = pRegLoadMUIStringA(hkey, tz_value, buf, ARRAY_SIZE(buf), &size, 0, sysdir);
4252 ok(ret == ERROR_CALL_NOT_IMPLEMENTED, "got %d, expected ERROR_CALL_NOT_IMPLEMENTED\n", ret);
4254 ret = pRegLoadMUIStringW(hkey, tz_valueW, bufW, ARRAY_SIZE(bufW), &size, 0, NULL);
4255 ok(ret == ERROR_FILE_NOT_FOUND, "got %d, expected ERROR_FILE_NOT_FOUND\n", ret);
4257 ret = pRegLoadMUIStringA(hkey, tz_value, buf, ARRAY_SIZE(buf), &size, 0, NULL);
4258 ok(ret == ERROR_CALL_NOT_IMPLEMENTED, "got %d, expected ERROR_CALL_NOT_IMPLEMENTED\n", ret);
4260 RegCloseKey(hkey);
4262 GetModuleFileNameA(NULL, filename, ARRAY_SIZE(filename));
4263 SetEnvironmentVariableA("WineMuiExe", filename);
4265 GetTempPathA(ARRAY_SIZE(tmp_path), tmp_path);
4266 GetTempFileNameA(tmp_path, "mui", 0, filename);
4267 SetEnvironmentVariableA("WineMuiDat", filename);
4269 /* write dummy data to the file, i.e. it's not a PE file. */
4270 hFile = CreateFileA(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
4271 ok(hFile != INVALID_HANDLE_VALUE, "can't open %s\n", filename);
4272 WriteFile(hFile, filename, strlen(filename), &size, NULL);
4273 CloseHandle(hFile);
4275 for (i = 0; i < ARRAY_SIZE(test_case); i++)
4277 size = test_case[i].value ? strlen(test_case[i].value) + 1 : 0;
4278 ret = RegSetValueExA(hkey_main, tz_value, 0, test_case[i].type,
4279 (const BYTE *)test_case[i].value, size);
4280 ok(ret == ERROR_SUCCESS, "[%2u] got %d\n", i, ret);
4282 size = 0xdeadbeef;
4283 memset(bufW, 0xff, sizeof(bufW));
4284 ret = pRegLoadMUIStringW(hkey_main, tz_valueW, bufW, ARRAY_SIZE(bufW),
4285 &size, 0,
4286 test_case[i].use_sysdir ? sysdirW : NULL);
4287 ok(ret == test_case[i].expected ||
4288 broken(test_case[i].value[0] == '%' && ret == ERROR_SUCCESS /* vista */) ||
4289 broken(test_case[i].broken_ret && ret == test_case[i].broken_ret /* vista */),
4290 "[%2u] expected %d, got %d\n", i, test_case[i].expected, ret);
4291 if (ret == ERROR_SUCCESS && test_case[i].expected == ERROR_SUCCESS)
4293 ok(size == text_size, "[%2u] got %u, expected %u\n", i, size, text_size);
4294 ok(!memcmp(bufW, textW, size), "[%2u] got %s, expected %s\n", i,
4295 wine_dbgstr_wn(bufW, size/sizeof(WCHAR)),
4296 wine_dbgstr_wn(textW, text_size/sizeof(WCHAR)));
4300 SetCurrentDirectoryW(curdirW);
4301 DeleteFileA(filename);
4302 SetEnvironmentVariableA("WineMuiTest1", NULL);
4303 SetEnvironmentVariableA("WineMuiTest2", NULL);
4304 SetEnvironmentVariableA("WineMuiExe", NULL);
4305 SetEnvironmentVariableA("WineMuiDat", NULL);
4308 static void test_EnumDynamicTimeZoneInformation(void)
4310 LSTATUS status;
4311 HKEY key, subkey;
4312 WCHAR name[128];
4313 WCHAR keyname[128];
4314 WCHAR sysdir[MAX_PATH];
4315 DWORD index, ret, gle, size;
4316 DYNAMIC_TIME_ZONE_INFORMATION bogus_dtzi, dtzi;
4317 struct tz_reg_data
4319 LONG bias;
4320 LONG std_bias;
4321 LONG dlt_bias;
4322 SYSTEMTIME std_date;
4323 SYSTEMTIME dlt_date;
4324 } tz_data;
4326 if (!pEnumDynamicTimeZoneInformation)
4328 win_skip("EnumDynamicTimeZoneInformation is not supported.\n");
4329 return;
4332 if (pRegLoadMUIStringW)
4333 GetSystemDirectoryW(sysdir, ARRAY_SIZE(sysdir));
4335 SetLastError(0xdeadbeef);
4336 ret = pEnumDynamicTimeZoneInformation(0, NULL);
4337 gle = GetLastError();
4338 ok(gle == 0xdeadbeef, "got 0x%x\n", gle);
4339 ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret);
4341 memset(&bogus_dtzi, 0xcc, sizeof(bogus_dtzi));
4342 memset(&dtzi, 0xcc, sizeof(dtzi));
4343 SetLastError(0xdeadbeef);
4344 ret = pEnumDynamicTimeZoneInformation(-1, &dtzi);
4345 gle = GetLastError();
4346 ok(gle == 0xdeadbeef, "got 0x%x\n", gle);
4347 ok(ret == ERROR_NO_MORE_ITEMS, "got %d\n", ret);
4348 ok(!memcmp(&dtzi, &bogus_dtzi, sizeof(dtzi)), "mismatch\n");
4350 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
4351 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0,
4352 KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE, &key);
4353 ok(status == ERROR_SUCCESS, "got %d\n", status);
4354 index = 0;
4355 while (!(status = RegEnumKeyW(key, index, keyname, ARRAY_SIZE(keyname))))
4357 winetest_push_context("%s" , wine_dbgstr_w(keyname));
4358 subkey = NULL;
4359 status = RegOpenKeyExW(key, keyname, 0, KEY_QUERY_VALUE, &subkey);
4360 ok(status == ERROR_SUCCESS, "got %d\n", status);
4362 memset(&dtzi, 0xcc, sizeof(dtzi));
4363 SetLastError(0xdeadbeef);
4364 ret = pEnumDynamicTimeZoneInformation(index, &dtzi);
4365 gle = GetLastError();
4366 /* recently added time zones may not have MUI strings */
4367 ok(gle == ERROR_SUCCESS ||
4368 gle == ERROR_RESOURCE_TYPE_NOT_FOUND /* Win10 1809 32-bit */ ||
4369 gle == ERROR_MUI_FILE_NOT_FOUND /* Win10 1809 64-bit */,
4370 "got 0x%x\n", gle);
4371 ok(ret == ERROR_SUCCESS, "got %d\n", ret);
4372 ok(!lstrcmpW(dtzi.TimeZoneKeyName, keyname), "expected %s, got %s\n",
4373 wine_dbgstr_w(keyname), wine_dbgstr_w(dtzi.TimeZoneKeyName));
4375 if (gle == ERROR_SUCCESS)
4377 size = sizeof(name);
4378 memset(name, 0, sizeof(name));
4379 status = pRegGetValueW(subkey, NULL, L"Std", RRF_RT_REG_SZ, NULL, name, &size);
4380 ok(status == ERROR_SUCCESS, "status %d Std %s\n", status,
4381 wine_dbgstr_w(name));
4382 ok(*name, "Std name is empty\n");
4383 if (pRegLoadMUIStringW)
4385 size = sizeof(name);
4386 memset(name, 0, sizeof(name));
4387 status = pRegLoadMUIStringW(subkey, L"MUI_Std", name, size, &size, 0, sysdir);
4388 ok(status == ERROR_SUCCESS, "status %d MUI_Std %s\n",
4389 status, wine_dbgstr_w(name));
4390 ok(*name, "MUI_Std name is empty\n");
4392 ok(!memcmp(&dtzi.StandardName, name, size), "expected %s, got %s\n",
4393 wine_dbgstr_w(name), wine_dbgstr_w(dtzi.StandardName));
4395 size = sizeof(name);
4396 memset(name, 0, sizeof(name));
4397 status = pRegGetValueW(subkey, NULL, L"Dlt", RRF_RT_REG_SZ, NULL, name, &size);
4398 ok(status == ERROR_SUCCESS, "status %d %s Dlt %s\n",
4399 status, wine_dbgstr_w(keyname), wine_dbgstr_w(name));
4400 ok(*name, "Dlt name is empty\n");
4401 if (pRegLoadMUIStringW)
4403 size = sizeof(name);
4404 memset(name, 0, sizeof(name));
4405 status = pRegLoadMUIStringW(subkey, L"MUI_Dlt", name, size, &size, 0, sysdir);
4406 ok(status == ERROR_SUCCESS, "status %d %s MUI_Dlt %s\n",
4407 status, wine_dbgstr_w(keyname), wine_dbgstr_w(name));
4408 ok(*name, "MUI_Dlt name is empty\n");
4410 ok(!memcmp(&dtzi.DaylightName, name, size), "expected %s, got %s\n",
4411 wine_dbgstr_w(name), wine_dbgstr_w(dtzi.DaylightName));
4413 size = sizeof(name);
4414 memset(name, 0, sizeof(name));
4415 status = pRegGetValueW(subkey, NULL, L"Display", RRF_RT_REG_SZ, NULL, name, &size);
4416 ok(status == ERROR_SUCCESS, "status %d %s Display %s\n",
4417 status, wine_dbgstr_w(keyname), wine_dbgstr_w(name));
4418 ok(*name, "Display name is empty\n");
4419 if (pRegLoadMUIStringW)
4421 size = sizeof(name);
4422 memset(name, 0, sizeof(name));
4423 status = pRegLoadMUIStringW(subkey, L"MUI_Display", name, size, &size, 0, sysdir);
4424 /* recently added time zones may not have MUI strings */
4425 todo_wine ok((status == ERROR_SUCCESS && *name) ||
4426 broken(status == ERROR_RESOURCE_TYPE_NOT_FOUND) /* Win10 1809 32-bit */ ||
4427 broken(status == ERROR_MUI_FILE_NOT_FOUND) /* Win10 1809 64-bit */,
4428 "status %d MUI_Display %s\n", status, wine_dbgstr_w(name));
4431 else
4433 ok(!dtzi.StandardName[0], "expected empty StandardName\n");
4434 ok(!dtzi.DaylightName[0], "expected empty DaylightName\n");
4437 ok(!dtzi.DynamicDaylightTimeDisabled, "got %d\n", dtzi.DynamicDaylightTimeDisabled);
4439 size = sizeof(tz_data);
4440 status = pRegGetValueW(key, keyname, L"TZI", RRF_RT_REG_BINARY, NULL, &tz_data, &size);
4441 ok(status == ERROR_SUCCESS, "got %d\n", status);
4443 ok(dtzi.Bias == tz_data.bias, "expected %d, got %d\n",
4444 tz_data.bias, dtzi.Bias);
4445 ok(dtzi.StandardBias == tz_data.std_bias, "expected %d, got %d\n",
4446 tz_data.std_bias, dtzi.StandardBias);
4447 ok(dtzi.DaylightBias == tz_data.dlt_bias, "expected %d, got %d\n",
4448 tz_data.dlt_bias, dtzi.DaylightBias);
4450 ok(!memcmp(&dtzi.StandardDate, &tz_data.std_date, sizeof(dtzi.StandardDate)),
4451 "expected %s, got %s\n",
4452 dbgstr_SYSTEMTIME(&tz_data.std_date), dbgstr_SYSTEMTIME(&dtzi.StandardDate));
4454 ok(!memcmp(&dtzi.DaylightDate, &tz_data.dlt_date, sizeof(dtzi.DaylightDate)),
4455 "expected %s, got %s\n",
4456 dbgstr_SYSTEMTIME(&tz_data.dlt_date), dbgstr_SYSTEMTIME(&dtzi.DaylightDate));
4458 winetest_pop_context();
4459 RegCloseKey(subkey);
4460 index++;
4462 ok(status == ERROR_NO_MORE_ITEMS, "got %d\n", status);
4464 memset(&dtzi, 0xcc, sizeof(dtzi));
4465 SetLastError(0xdeadbeef);
4466 ret = pEnumDynamicTimeZoneInformation(index, &dtzi);
4467 gle = GetLastError();
4468 ok(gle == 0xdeadbeef, "got 0x%x\n", gle);
4469 ok(ret == ERROR_NO_MORE_ITEMS, "got %d\n", ret);
4470 ok(!memcmp(&dtzi, &bogus_dtzi, sizeof(dtzi)), "mismatch\n");
4472 RegCloseKey(key);
4475 START_TEST(registry)
4477 /* Load pointers for functions that are not available in all Windows versions */
4478 InitFunctionPtrs();
4480 setup_main_key();
4481 check_user_privs();
4482 test_set_value();
4483 create_test_entries();
4484 test_enum_value();
4485 test_query_value_ex();
4486 test_get_value();
4487 test_reg_open_key();
4488 test_reg_create_key();
4489 test_reg_close_key();
4490 test_reg_delete_key();
4491 test_reg_query_value();
4492 test_reg_query_info();
4493 test_string_termination();
4494 test_symlinks();
4495 test_redirection();
4496 test_classesroot();
4497 test_classesroot_enum();
4498 test_classesroot_mask();
4499 test_reg_save_key();
4500 test_reg_load_key();
4501 test_reg_unload_key();
4502 test_reg_copy_tree();
4503 test_reg_delete_tree();
4504 test_rw_order();
4505 test_deleted_key();
4506 test_delete_value();
4507 test_delete_key_value();
4508 test_RegOpenCurrentUser();
4509 test_RegNotifyChangeKeyValue();
4510 test_performance_keys();
4511 test_RegLoadMUIString();
4512 test_EnumDynamicTimeZoneInformation();
4513 test_perflib_key();
4515 /* cleanup */
4516 delete_key( hkey_main );
4518 test_regconnectregistry();