1 /* Unit test suite for SHReg* functions
3 * Copyright 2002 Juergen Schmied
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/test.h"
31 /* Keys used for testing */
32 #define REG_TEST_KEY "Software\\Wine\\Test"
33 #define REG_CURRENT_VERSION "Software\\Microsoft\\Windows\\CurrentVersion\\explorer"
35 static HMODULE hshlwapi
;
37 static DWORD (WINAPI
*pSHCopyKeyA
)(HKEY
,LPCSTR
,HKEY
,DWORD
);
38 static DWORD (WINAPI
*pSHRegGetPathA
)(HKEY
,LPCSTR
,LPCSTR
,LPSTR
,DWORD
);
39 static LSTATUS (WINAPI
*pSHRegGetValueA
)(HKEY
,LPCSTR
,LPCSTR
,SRRF
,LPDWORD
,LPVOID
,LPDWORD
);
40 static LSTATUS (WINAPI
*pSHRegCreateUSKeyW
)(LPCWSTR
,REGSAM
,HUSKEY
,PHUSKEY
,DWORD
);
41 static LSTATUS (WINAPI
*pSHRegOpenUSKeyW
)(LPCWSTR
,REGSAM
,HUSKEY
,PHUSKEY
,BOOL
);
42 static LSTATUS (WINAPI
*pSHRegCloseUSKey
)(HUSKEY
);
44 static const char sTestpath1
[] = "%LONGSYSTEMVAR%\\subdir1";
45 static const char sTestpath2
[] = "%FOO%\\subdir1";
47 static const char * sEnvvar1
= "bar";
48 static const char * sEnvvar2
= "ImARatherLongButIndeedNeededString";
50 static char sExpTestpath1
[MAX_PATH
];
51 static char sExpTestpath2
[MAX_PATH
];
52 static DWORD nExpLen1
;
53 static DWORD nExpLen2
;
55 static const char * sEmptyBuffer
="0123456789";
57 /* delete key and all its subkeys */
58 static DWORD
delete_key( HKEY hkey
, LPCSTR parent
, LPCSTR keyname
)
65 /* open the parent of the key to close */
66 ret
= RegOpenKeyExA( HKEY_CURRENT_USER
, parent
, 0, KEY_ALL_ACCESS
, &parentKey
);
67 if (ret
!= ERROR_SUCCESS
)
70 ret
= SHDeleteKeyA( parentKey
, keyname
);
71 RegCloseKey(parentKey
);
76 static HKEY
create_test_entries(void)
80 DWORD nExpectedLen1
, nExpectedLen2
;
82 SetEnvironmentVariableA("LONGSYSTEMVAR", sEnvvar1
);
83 SetEnvironmentVariableA("FOO", sEnvvar2
);
85 ret
= RegCreateKeyA(HKEY_CURRENT_USER
, REG_TEST_KEY
, &hKey
);
86 ok( ERROR_SUCCESS
== ret
, "RegCreateKeyA failed, ret=%u\n", ret
);
90 ok(!RegSetValueExA(hKey
,"Test1",0,REG_EXPAND_SZ
, (LPBYTE
) sTestpath1
, strlen(sTestpath1
)+1), "RegSetValueExA failed\n");
91 ok(!RegSetValueExA(hKey
,"Test2",0,REG_SZ
, (LPBYTE
) sTestpath1
, strlen(sTestpath1
)+1), "RegSetValueExA failed\n");
92 ok(!RegSetValueExA(hKey
,"Test3",0,REG_EXPAND_SZ
, (LPBYTE
) sTestpath2
, strlen(sTestpath2
)+1), "RegSetValueExA failed\n");
95 nExpLen1
= ExpandEnvironmentStringsA(sTestpath1
, sExpTestpath1
, sizeof(sExpTestpath1
));
96 nExpLen2
= ExpandEnvironmentStringsA(sTestpath2
, sExpTestpath2
, sizeof(sExpTestpath2
));
98 nExpectedLen1
= strlen(sTestpath1
) - strlen("%LONGSYSTEMVAR%") + strlen(sEnvvar1
) + 1;
99 nExpectedLen2
= strlen(sTestpath2
) - strlen("%FOO%") + strlen(sEnvvar2
) + 1;
100 /* ExpandEnvironmentStringsA on NT4 returns 2x the correct result */
101 trace("sExplen1 = (%d)\n", nExpLen1
);
102 if (nExpectedLen1
!= nExpLen1
)
103 trace( "Expanding %s failed (expected %d) - known bug in NT4\n", sTestpath1
, nExpectedLen1
);
105 trace("sExplen2 = (%d)\n", nExpLen2
);
106 if (nExpectedLen2
!= nExpLen2
)
107 trace( "Expanding %s failed (expected %d) - known bug in NT4\n", sTestpath2
, nExpectedLen2
);
109 /* Make sure we carry on with correct values */
110 nExpLen1
= nExpectedLen1
;
111 nExpLen2
= nExpectedLen2
;
115 static void test_SHGetValue(void)
122 strcpy(buf
, sEmptyBuffer
);
125 dwRet
= SHGetValueA(HKEY_CURRENT_USER
, REG_TEST_KEY
, "Test1", &dwType
, buf
, &dwSize
);
126 ok( ERROR_SUCCESS
== dwRet
, "SHGetValueA failed, ret=%u\n", dwRet
);
127 ok( 0 == strcmp(sExpTestpath1
, buf
) ||
128 broken(0 == strcmp(sTestpath1
, buf
)), /* IE4.x */
129 "Comparing of (%s) with (%s) failed\n", buf
, sExpTestpath1
);
130 ok( REG_SZ
== dwType
||
131 broken(REG_EXPAND_SZ
== dwType
), /* IE4.x */
132 "Expected REG_SZ, got (%u)\n", dwType
);
134 strcpy(buf
, sEmptyBuffer
);
137 dwRet
= SHGetValueA(HKEY_CURRENT_USER
, REG_TEST_KEY
, "Test2", &dwType
, buf
, &dwSize
);
138 ok( ERROR_SUCCESS
== dwRet
, "SHGetValueA failed, ret=%u\n", dwRet
);
139 ok( 0 == strcmp(sTestpath1
, buf
) , "Comparing of (%s) with (%s) failed\n", buf
, sTestpath1
);
140 ok( REG_SZ
== dwType
, "Expected REG_SZ, got (%u)\n", dwType
);
143 static void test_SHRegGetValue(void)
153 ret
= pSHRegGetValueA(HKEY_CURRENT_USER
, REG_TEST_KEY
, "Test1", SRRF_RT_REG_EXPAND_SZ
, &type
, data
, &size
);
154 ok(ret
== ERROR_INVALID_PARAMETER
, "SHRegGetValue failed, ret=%u\n", ret
);
157 ret
= pSHRegGetValueA(HKEY_CURRENT_USER
, REG_TEST_KEY
, "Test1", SRRF_RT_REG_SZ
, &type
, data
, &size
);
158 ok(ret
== ERROR_SUCCESS
, "SHRegGetValue failed, ret=%u\n", ret
);
159 ok(!strcmp(data
, sExpTestpath1
), "data = %s, expected %s\n", data
, sExpTestpath1
);
160 ok(type
== REG_SZ
, "type = %d, expected REG_SZ\n", type
);
163 ret
= pSHRegGetValueA(HKEY_CURRENT_USER
, REG_TEST_KEY
, "Test1", SRRF_RT_REG_DWORD
, &type
, data
, &size
);
164 ok(ret
== ERROR_UNSUPPORTED_TYPE
, "SHRegGetValue failed, ret=%u\n", ret
);
167 ret
= pSHRegGetValueA(HKEY_CURRENT_USER
, REG_TEST_KEY
, "Test2", SRRF_RT_REG_EXPAND_SZ
, &type
, data
, &size
);
168 ok(ret
== ERROR_INVALID_PARAMETER
, "SHRegGetValue failed, ret=%u\n", ret
);
171 ret
= pSHRegGetValueA(HKEY_CURRENT_USER
, REG_TEST_KEY
, "Test2", SRRF_RT_REG_SZ
, &type
, data
, &size
);
172 ok(ret
== ERROR_SUCCESS
, "SHRegGetValue failed, ret=%u\n", ret
);
173 ok(!strcmp(data
, sTestpath1
), "data = %s, expected %s\n", data
, sTestpath1
);
174 ok(type
== REG_SZ
, "type = %d, expected REG_SZ\n", type
);
177 ret
= pSHRegGetValueA(HKEY_CURRENT_USER
, REG_TEST_KEY
, "Test2", SRRF_RT_REG_QWORD
, &type
, data
, &size
);
178 ok(ret
== ERROR_UNSUPPORTED_TYPE
, "SHRegGetValue failed, ret=%u\n", ret
);
181 static void test_SHGetRegPath(void)
189 strcpy(buf
, sEmptyBuffer
);
190 dwRet
= (*pSHRegGetPathA
)(HKEY_CURRENT_USER
, REG_TEST_KEY
, "Test1", buf
, 0);
191 ok( ERROR_SUCCESS
== dwRet
, "SHRegGetPathA failed, ret=%u\n", dwRet
);
192 ok( 0 == strcmp(sExpTestpath1
, buf
) , "Comparing (%s) with (%s) failed\n", buf
, sExpTestpath1
);
195 static void test_SHQueryValueEx(void)
202 const char * sTestedFunction
= "";
203 DWORD nUsedBuffer1
,nUsedBuffer2
;
205 sTestedFunction
= "RegOpenKeyExA";
206 dwRet
= RegOpenKeyExA(HKEY_CURRENT_USER
, REG_TEST_KEY
, 0, KEY_QUERY_VALUE
, &hKey
);
207 ok( ERROR_SUCCESS
== dwRet
, "%s failed, ret=%u\n", sTestedFunction
, dwRet
);
209 /****** SHQueryValueExA ******/
211 sTestedFunction
= "SHQueryValueExA";
212 nUsedBuffer1
= max(strlen(sExpTestpath1
)+1, strlen(sTestpath1
)+1);
213 nUsedBuffer2
= max(strlen(sExpTestpath2
)+1, strlen(sTestpath2
)+1);
215 * Case 1.1 All arguments are NULL
217 dwRet
= SHQueryValueExA( hKey
, "Test1", NULL
, NULL
, NULL
, NULL
);
218 ok( ERROR_SUCCESS
== dwRet
, "%s failed, ret=%u\n", sTestedFunction
, dwRet
);
221 * Case 1.2 dwType is set
224 dwRet
= SHQueryValueExA( hKey
, "Test1", NULL
, &dwType
, NULL
, NULL
);
225 ok( ERROR_SUCCESS
== dwRet
, "%s failed, ret=%u\n", sTestedFunction
, dwRet
);
226 ok( REG_SZ
== dwType
, "Expected REG_SZ, got (%u)\n", dwType
);
230 * dwExpanded < dwUnExpanded
233 dwRet
= SHQueryValueExA( hKey
, "Test1", NULL
, NULL
, NULL
, &dwSize
);
234 ok( ERROR_SUCCESS
== dwRet
, "%s failed, ret=%u\n", sTestedFunction
, dwRet
);
235 ok( dwSize
== nUsedBuffer1
, "Buffer sizes (%u) and (%u) are not equal\n", dwSize
, nUsedBuffer1
);
238 * dwExpanded > dwUnExpanded
241 dwRet
= SHQueryValueExA( hKey
, "Test3", NULL
, NULL
, NULL
, &dwSize
);
242 ok( ERROR_SUCCESS
== dwRet
, "%s failed, ret=%u\n", sTestedFunction
, dwRet
);
243 ok( dwSize
>= nUsedBuffer2
||
244 broken(dwSize
== (strlen(sTestpath2
) + 1)), /* < IE4.x */
245 "Buffer size (%u) should be >= (%u)\n", dwSize
, nUsedBuffer2
);
248 * Case 1 string shrinks during expanding
250 strcpy(buf
, sEmptyBuffer
);
253 dwRet
= SHQueryValueExA( hKey
, "Test1", NULL
, &dwType
, buf
, &dwSize
);
254 ok( ERROR_MORE_DATA
== dwRet
, "Expected ERROR_MORE_DATA, got (%u)\n", dwRet
);
255 ok( 0 == strcmp(sEmptyBuffer
, buf
) , "Comparing (%s) with (%s) failed\n", buf
, sEmptyBuffer
);
256 ok( dwSize
== nUsedBuffer1
, "Buffer sizes (%u) and (%u) are not equal\n", dwSize
, nUsedBuffer1
);
257 ok( REG_SZ
== dwType
||
258 broken(REG_EXPAND_SZ
== dwType
), /* < IE6 */
259 "Expected REG_SZ, got (%u)\n", dwType
);
262 * string grows during expanding
263 * dwSize is smaller than the size of the unexpanded string
265 strcpy(buf
, sEmptyBuffer
);
268 dwRet
= SHQueryValueExA( hKey
, "Test3", NULL
, &dwType
, buf
, &dwSize
);
269 ok( ERROR_MORE_DATA
== dwRet
, "Expected ERROR_MORE_DATA, got (%u)\n", dwRet
);
270 ok( 0 == strcmp(sEmptyBuffer
, buf
) , "Comparing (%s) with (%s) failed\n", buf
, sEmptyBuffer
);
271 ok( dwSize
>= nUsedBuffer2
||
272 broken(dwSize
== (strlen(sTestpath2
) + 1)), /* < IE6 */
273 "Buffer size (%u) should be >= (%u)\n", dwSize
, nUsedBuffer2
);
274 ok( REG_SZ
== dwType
||
275 broken(REG_EXPAND_SZ
== dwType
), /* < IE6 */
276 "Expected REG_SZ, got (%u)\n", dwType
);
279 * string grows during expanding
280 * dwSize is larger than the size of the unexpanded string, but
281 * smaller than the part before the backslash. If the unexpanded
282 * string fits into the buffer, it can get cut when expanded.
284 strcpy(buf
, sEmptyBuffer
);
285 dwSize
= strlen(sEnvvar2
) - 2;
287 dwRet
= SHQueryValueExA( hKey
, "Test3", NULL
, &dwType
, buf
, &dwSize
);
288 ok( ERROR_MORE_DATA
== dwRet
||
289 broken(ERROR_ENVVAR_NOT_FOUND
== dwRet
) || /* IE5.5 */
290 broken(ERROR_SUCCESS
== dwRet
), /* < IE5.5*/
291 "Expected ERROR_MORE_DATA, got (%u)\n", dwRet
);
295 ok( (0 == strcmp("", buf
)) || (0 == strcmp(sTestpath2
, buf
)),
296 "Expected empty or unexpanded string (win98), got (%s)\n", buf
);
299 ok( dwSize
>= nUsedBuffer2
||
300 broken(dwSize
== (strlen("") + 1)), /* < IE 5.5 */
301 "Buffer size (%u) should be >= (%u)\n", dwSize
, nUsedBuffer2
);
302 ok( REG_SZ
== dwType
, "Expected REG_SZ, got (%u)\n", dwType
);
305 * string grows during expanding
306 * dwSize is larger than the size of the part before the backslash,
307 * but smaller than the expanded string. If the unexpanded string fits
308 * into the buffer, it can get cut when expanded.
310 strcpy(buf
, sEmptyBuffer
);
311 dwSize
= nExpLen2
- 4;
313 dwRet
= SHQueryValueExA( hKey
, "Test3", NULL
, &dwType
, buf
, &dwSize
);
314 ok( ERROR_MORE_DATA
== dwRet
||
315 broken(ERROR_ENVVAR_NOT_FOUND
== dwRet
) || /* IE5.5 */
316 broken(ERROR_SUCCESS
== dwRet
), /* < IE5.5 */
317 "Expected ERROR_MORE_DATA, got (%u)\n", dwRet
);
321 ok( (0 == strcmp("", buf
)) || (0 == strcmp(sEnvvar2
, buf
)) ||
322 broken(0 == strcmp(sTestpath2
, buf
)), /* IE 5.5 */
323 "Expected empty or first part of the string \"%s\", got \"%s\"\n", sEnvvar2
, buf
);
326 ok( dwSize
>= nUsedBuffer2
||
327 broken(dwSize
== (strlen(sEnvvar2
) + 1)) || /* IE4.01 SP1 (W98) and IE5 (W98SE) */
328 broken(dwSize
== (strlen("") + 1)), /* IE4.01 (NT4) and IE5.x (W2K) */
329 "Buffer size (%u) should be >= (%u)\n", dwSize
, nUsedBuffer2
);
330 ok( REG_SZ
== dwType
, "Expected REG_SZ, got (%u)\n", dwType
);
333 * The buffer is NULL but the size is set
335 strcpy(buf
, sEmptyBuffer
);
338 dwRet
= SHQueryValueExA( hKey
, "Test3", NULL
, &dwType
, NULL
, &dwSize
);
339 ok( ERROR_SUCCESS
== dwRet
, "%s failed, ret=%u\n", sTestedFunction
, dwRet
);
340 ok( dwSize
>= nUsedBuffer2
||
341 broken(dwSize
== (strlen(sTestpath2
) + 1)), /* IE4.01 SP1 (Win98) */
342 "Buffer size (%u) should be >= (%u)\n", dwSize
, nUsedBuffer2
);
343 ok( REG_SZ
== dwType
, "Expected REG_SZ, got (%u)\n", dwType
);
348 static void test_SHCopyKey(void)
350 HKEY hKeySrc
, hKeyDst
;
355 win_skip("SHCopyKeyA is not available\n");
359 /* Delete existing destination sub keys */
361 if (!RegOpenKeyA(HKEY_CURRENT_USER
, REG_TEST_KEY
"\\CopyDestination", &hKeyDst
) && hKeyDst
)
363 SHDeleteKeyA(hKeyDst
, NULL
);
364 RegCloseKey(hKeyDst
);
368 dwRet
= RegCreateKeyA(HKEY_CURRENT_USER
, REG_TEST_KEY
"\\CopyDestination", &hKeyDst
);
369 if (dwRet
|| !hKeyDst
)
371 ok( 0, "Destination couldn't be created, RegCreateKeyA returned (%u)\n", dwRet
);
376 dwRet
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, REG_CURRENT_VERSION
, &hKeySrc
);
377 if (dwRet
|| !hKeySrc
)
379 ok( 0, "Source couldn't be opened, RegOpenKeyA returned (%u)\n", dwRet
);
380 RegCloseKey(hKeyDst
);
384 dwRet
= (*pSHCopyKeyA
)(hKeySrc
, NULL
, hKeyDst
, 0);
385 ok ( ERROR_SUCCESS
== dwRet
, "Copy failed, ret=(%u)\n", dwRet
);
387 RegCloseKey(hKeySrc
);
388 RegCloseKey(hKeyDst
);
390 /* Check we copied the sub keys, i.e. something that's on every windows system (including Wine) */
392 dwRet
= RegOpenKeyA(HKEY_CURRENT_USER
, REG_TEST_KEY
"\\CopyDestination\\Shell Folders", &hKeyDst
);
393 if (dwRet
|| !hKeyDst
)
395 ok ( 0, "Copy couldn't be opened, RegOpenKeyA returned (%u)\n", dwRet
);
399 /* And the we copied the values too */
400 ok(!SHQueryValueExA(hKeyDst
, "Common AppData", NULL
, NULL
, NULL
, NULL
), "SHQueryValueExA failed\n");
402 RegCloseKey(hKeyDst
);
405 static void test_SHDeleteKey(void)
407 HKEY hKeyTest
, hKeyS
;
411 if (!RegOpenKeyA(HKEY_CURRENT_USER
, REG_TEST_KEY
, &hKeyTest
))
413 if (!RegCreateKeyA(hKeyTest
, "ODBC", &hKeyS
))
417 if (!RegCreateKeyA(hKeyS
, "ODBC.INI", &hKeyO
))
421 if (!RegCreateKeyA(hKeyS
, "ODBCINST.INI", &hKeyO
))
429 RegCloseKey (hKeyTest
);
435 dwRet
= SHDeleteKeyA(HKEY_CURRENT_USER
, REG_TEST_KEY
"\\ODBC");
436 ok ( ERROR_SUCCESS
== dwRet
, "SHDeleteKey failed, ret=(%u)\n", dwRet
);
438 dwRet
= RegOpenKeyA(HKEY_CURRENT_USER
, REG_TEST_KEY
"\\ODBC", &hKeyS
);
439 ok ( ERROR_FILE_NOT_FOUND
== dwRet
, "SHDeleteKey did not delete\n");
441 if (dwRet
== ERROR_SUCCESS
)
445 ok( 0, "Could not set up SHDeleteKey test\n");
448 static void test_SHRegCreateUSKeyW(void)
450 static const WCHAR subkeyW
[] = {'s','u','b','k','e','y',0};
453 if (!pSHRegCreateUSKeyW
)
455 win_skip("SHRegCreateUSKeyW not available\n");
459 ret
= pSHRegCreateUSKeyW(subkeyW
, KEY_ALL_ACCESS
, NULL
, NULL
, SHREGSET_FORCE_HKCU
);
460 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
463 static void test_SHRegCloseUSKey(void)
465 static const WCHAR localW
[] = {'S','o','f','t','w','a','r','e',0};
469 if (!pSHRegOpenUSKeyW
|| !pSHRegCloseUSKey
)
471 win_skip("SHRegOpenUSKeyW or SHRegCloseUSKey not available\n");
475 ret
= pSHRegCloseUSKey(NULL
);
476 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
478 ret
= pSHRegOpenUSKeyW(localW
, KEY_ALL_ACCESS
, NULL
, &key
, FALSE
);
479 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
481 ret
= pSHRegCloseUSKey(key
);
482 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
484 /* Test with limited rights, specially without KEY_SET_VALUE */
485 ret
= pSHRegOpenUSKeyW(localW
, KEY_QUERY_VALUE
, NULL
, &key
, FALSE
);
486 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
488 ret
= pSHRegCloseUSKey(key
);
489 ok(ret
== ERROR_SUCCESS
, "got %d\n", ret
);
494 HKEY hkey
= create_test_entries();
498 hshlwapi
= GetModuleHandleA("shlwapi.dll");
500 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
501 if(!GetProcAddress(hshlwapi
, "SHCreateStreamOnFileEx")){
502 win_skip("Too old shlwapi version\n");
506 pSHCopyKeyA
= (void*)GetProcAddress(hshlwapi
,"SHCopyKeyA");
507 pSHRegGetPathA
= (void*)GetProcAddress(hshlwapi
,"SHRegGetPathA");
508 pSHRegGetValueA
= (void*)GetProcAddress(hshlwapi
,"SHRegGetValueA");
509 pSHRegCreateUSKeyW
= (void*)GetProcAddress(hshlwapi
, "SHRegCreateUSKeyW");
510 pSHRegOpenUSKeyW
= (void*)GetProcAddress(hshlwapi
, "SHRegOpenUSKeyW");
511 pSHRegCloseUSKey
= (void*)GetProcAddress(hshlwapi
, "SHRegCloseUSKey");
514 test_SHRegGetValue();
515 test_SHQueryValueEx();
519 test_SHRegCreateUSKeyW();
520 test_SHRegCloseUSKey();
522 delete_key( hkey
, "Software\\Wine", "Test" );