1 /* Unit test suite for SHLWAPI string functions
3 * Copyright 2003 Jon Griffiths
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
22 #include "wine/test.h"
26 #define NO_SHLWAPI_REG
27 #define NO_SHLWAPI_PATH
28 #define NO_SHLWAPI_GDI
29 #define NO_SHLWAPI_STREAM
33 #define expect_eq(expr, val, type, fmt) do { \
35 ok(ret == val, "Unexpected value of '" #expr "': " #fmt " instead of " #val "\n", ret); \
38 #define expect_eq2(expr, val1, val2, type, fmt) do { \
40 ok(ret == val1 || ret == val2, "Unexpected value of '" #expr "': " #fmt " instead of " #val1 " or " #val2 "\n", ret); \
43 static BOOL (WINAPI
*pChrCmpIA
)(CHAR
, CHAR
);
44 static BOOL (WINAPI
*pChrCmpIW
)(WCHAR
, WCHAR
);
45 static BOOL (WINAPI
*pIntlStrEqWorkerA
)(BOOL
,LPCSTR
,LPCSTR
,int);
46 static BOOL (WINAPI
*pIntlStrEqWorkerW
)(BOOL
,LPCWSTR
,LPCWSTR
,int);
47 static DWORD (WINAPI
*pSHAnsiToAnsi
)(LPCSTR
,LPSTR
,int);
48 static DWORD (WINAPI
*pSHUnicodeToUnicode
)(LPCWSTR
,LPWSTR
,int);
49 static LPSTR (WINAPI
*pStrCatBuffA
)(LPSTR
,LPCSTR
,INT
);
50 static LPWSTR (WINAPI
*pStrCatBuffW
)(LPWSTR
,LPCWSTR
,INT
);
51 static DWORD (WINAPI
*pStrCatChainW
)(LPWSTR
,DWORD
,DWORD
,LPCWSTR
);
52 static LPSTR (WINAPI
*pStrCpyNXA
)(LPSTR
,LPCSTR
,int);
53 static LPWSTR (WINAPI
*pStrCpyNXW
)(LPWSTR
,LPCWSTR
,int);
54 static LPSTR (WINAPI
*pStrFormatByteSize64A
)(LONGLONG
,LPSTR
,UINT
);
55 static LPSTR (WINAPI
*pStrFormatKBSizeA
)(LONGLONG
,LPSTR
,UINT
);
56 static LPWSTR (WINAPI
*pStrFormatKBSizeW
)(LONGLONG
,LPWSTR
,UINT
);
57 static BOOL (WINAPI
*pStrIsIntlEqualA
)(BOOL
,LPCSTR
,LPCSTR
,int);
58 static BOOL (WINAPI
*pStrIsIntlEqualW
)(BOOL
,LPCWSTR
,LPCWSTR
,int);
59 static LPWSTR (WINAPI
*pStrPBrkW
)(LPCWSTR
,LPCWSTR
);
60 static LPSTR (WINAPI
*pStrRChrA
)(LPCSTR
,LPCSTR
,WORD
);
61 static HRESULT (WINAPI
*pStrRetToBSTR
)(STRRET
*,LPCITEMIDLIST
,BSTR
*);
62 static HRESULT (WINAPI
*pStrRetToBufA
)(STRRET
*,LPCITEMIDLIST
,LPSTR
,UINT
);
63 static HRESULT (WINAPI
*pStrRetToBufW
)(STRRET
*,LPCITEMIDLIST
,LPWSTR
,UINT
);
64 static LPWSTR (WINAPI
*pStrStrNW
)(LPCWSTR
,LPCWSTR
,UINT
);
65 static LPWSTR (WINAPI
*pStrStrNIW
)(LPCWSTR
,LPCWSTR
,UINT
);
66 static INT (WINAPIV
*pwnsprintfA
)(LPSTR
,INT
,LPCSTR
, ...);
67 static INT (WINAPIV
*pwnsprintfW
)(LPWSTR
,INT
,LPCWSTR
, ...);
68 static LPWSTR (WINAPI
*pStrChrNW
)(LPCWSTR
,WCHAR
,UINT
);
69 static BOOL (WINAPI
*pStrToInt64ExA
)(LPCSTR
,DWORD
,LONGLONG
*);
70 static BOOL (WINAPI
*pStrToInt64ExW
)(LPCWSTR
,DWORD
,LONGLONG
*);
72 /* StrToInt/StrToIntEx results */
73 typedef struct tagStrToIntResult
77 LONGLONG str_to_int64_ex
;
78 LONGLONG str_to_int64_hex
;
82 static const StrToIntResult StrToInt_results
[] = {
83 { "1099", 1099, 1099, 1099 },
84 { "4294967319", 23, ((LONGLONG
)1 << 32) | 23, ((LONGLONG
)1 << 32) | 23 },
85 { "+88987", 0, 88987, 88987 },
86 { "012", 12, 12, 12 },
87 { "-55", -55, -55, -55 },
89 { "0x44ff", 0, 0, 0x44ff },
90 { "0x2bdc546291f4b1", 0, 0, ((LONGLONG
)0x2bdc54 << 32) | 0x6291f4b1 },
91 { "+0x44f4", 0, 0, 0x44f4 },
92 { "-0x44fd", 0, 0, 0x44fd },
93 { "+ 88987", 0, 0, 0, TRUE
},
95 { "- 55", 0, 0, 0, TRUE
},
96 { "- 0", 0, 0, 0, TRUE
},
97 { "+ 0x44f4", 0, 0, 0, TRUE
},
98 { "--0x44fd", 0, 0, 0, TRUE
},
99 { " 1999", 0, 1999, 1999 },
100 { " +88987", 0, 88987, 88987 },
101 { " 012", 0, 12, 12 },
102 { " -55", 0, -55, -55 },
103 { " 0x44ff", 0, 0, 0x44ff },
104 { " +0x44f4", 0, 0, 0x44f4 },
105 { " -0x44fd", 0, 0, 0x44fd },
106 { "\t\n +3", 0, 3, 3 },
107 { "\v+4", 0, 0, 0, TRUE
},
108 { "\f+5", 0, 0, 0, TRUE
},
109 { "\r+6", 0, 0, 0, TRUE
},
113 /* pStrFormatByteSize64/StrFormatKBSize results */
114 typedef struct tagStrFormatSizeResult
117 const char* byte_size_64
;
120 const char* kb_size2
;
121 } StrFormatSizeResult
;
124 static const StrFormatSizeResult StrFormatSize_results
[] = {
125 { -1023, "-1023 bytes", "0 KB"},
126 { -24, "-24 bytes", "0 KB"},
127 { 309, "309 bytes", "1 KB"},
128 { 10191, "9.95 KB", "10 KB"},
129 { 100353, "98.0 KB", "99 KB"},
130 { 1022286, "998 KB", "999 KB"},
131 { 1046862, "0.99 MB", "1,023 KB", 1, "1023 KB"},
132 { 1048574619, "999 MB", "1,023,999 KB", 1, "1023999 KB"},
133 { 1073741775, "0.99 GB", "1,048,576 KB", 1, "1048576 KB"},
134 { ((LONGLONG
)0x000000f9 << 32) | 0xfffff94e, "999 GB", "1,048,575,999 KB", 1, "1048575999 KB"},
135 { ((LONGLONG
)0x000000ff << 32) | 0xfffffa9b, "0.99 TB", "1,073,741,823 KB", 1, "1073741823 KB"},
136 { ((LONGLONG
)0x0003e7ff << 32) | 0xfffffa9b, "999 TB", "1,073,741,823,999 KB", 1, "4294967295 KB"},
137 { ((LONGLONG
)0x0003ffff << 32) | 0xfffffbe8, "0.99 PB", "1,099,511,627,775 KB", 1, "4294967295 KB"},
138 { ((LONGLONG
)0x0f9fffff << 32) | 0xfffffd35, "999 PB", "1,099,511,627,776,000 KB", 1, "0 KB"},
139 { ((LONGLONG
)0x0fffffff << 32) | 0xfffffa9b, "0.99 EB", "1,125,899,906,842,623 KB", 1, "4294967295 KB"},
143 /* StrFromTimeIntervalA/StrFromTimeIntervalW results */
144 typedef struct tagStrFromTimeIntervalResult
148 const char* time_interval
;
149 } StrFromTimeIntervalResult
;
152 static const StrFromTimeIntervalResult StrFromTimeInterval_results
[] = {
161 { 1000000, 1, " 10 min" },
162 { 1000000, 2, " 16 min" },
163 { 1000000, 3, " 16 min 40 sec" },
164 { 1000000, 4, " 16 min 40 sec" },
165 { 1000000, 5, " 16 min 40 sec" },
166 { 1000000, 6, " 16 min 40 sec" },
167 { 1000000, 7, " 16 min 40 sec" },
169 { 1999999, 1, " 30 min" },
170 { 1999999, 2, " 33 min" },
171 { 1999999, 3, " 33 min 20 sec" },
172 { 1999999, 4, " 33 min 20 sec" },
173 { 1999999, 5, " 33 min 20 sec" },
174 { 1999999, 6, " 33 min 20 sec" },
175 { 1999999, 7, " 33 min 20 sec" },
177 { 3999997, 1, " 1 hr" },
178 { 3999997, 2, " 1 hr 6 min" },
179 { 3999997, 3, " 1 hr 6 min 40 sec" },
180 { 3999997, 4, " 1 hr 6 min 40 sec" },
181 { 3999997, 5, " 1 hr 6 min 40 sec" },
182 { 3999997, 6, " 1 hr 6 min 40 sec" },
183 { 3999997, 7, " 1 hr 6 min 40 sec" },
185 { 149999851, 7, " 41 hr 40 min 0 sec" },
186 { 150999850, 1, " 40 hr" },
187 { 150999850, 2, " 41 hr" },
188 { 150999850, 3, " 41 hr 50 min" },
189 { 150999850, 4, " 41 hr 56 min" },
190 { 150999850, 5, " 41 hr 56 min 40 sec" },
191 { 150999850, 6, " 41 hr 56 min 40 sec" },
192 { 150999850, 7, " 41 hr 56 min 40 sec" },
194 { 493999507, 1, " 100 hr" },
195 { 493999507, 2, " 130 hr" },
196 { 493999507, 3, " 137 hr" },
197 { 493999507, 4, " 137 hr 10 min" },
198 { 493999507, 5, " 137 hr 13 min" },
199 { 493999507, 6, " 137 hr 13 min 20 sec" },
200 { 493999507, 7, " 137 hr 13 min 20 sec" },
206 /* Returns true if the user interface is in English. Note that this does not
207 * presume of the formatting of dates, numbers, etc.
209 static BOOL
is_lang_english(void)
211 static HMODULE hkernel32
= NULL
;
212 static LANGID (WINAPI
*pGetThreadUILanguage
)(void) = NULL
;
213 static LANGID (WINAPI
*pGetUserDefaultUILanguage
)(void) = NULL
;
217 hkernel32
= GetModuleHandleA("kernel32.dll");
218 pGetThreadUILanguage
= (void*)GetProcAddress(hkernel32
, "GetThreadUILanguage");
219 pGetUserDefaultUILanguage
= (void*)GetProcAddress(hkernel32
, "GetUserDefaultUILanguage");
221 if (pGetThreadUILanguage
)
222 return PRIMARYLANGID(pGetThreadUILanguage()) == LANG_ENGLISH
;
223 if (pGetUserDefaultUILanguage
)
224 return PRIMARYLANGID(pGetUserDefaultUILanguage()) == LANG_ENGLISH
;
226 return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH
;
229 /* Returns true if the dates, numbers, etc. are formatted using English
232 static BOOL
is_locale_english(void)
234 /* Surprisingly GetThreadLocale() is irrelevant here */
235 return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH
;
238 static void test_StrChrA(void)
243 /* this test crashes on win2k SP4 */
244 /*ok(!StrChrA(NULL,'\0'), "found a character in a NULL string!\n");*/
246 for (count
= 32; count
< 128; count
++)
247 string
[count
] = (char)count
;
250 for (count
= 32; count
< 128; count
++)
252 LPSTR result
= StrChrA(string
+32, count
);
253 INT pos
= result
- string
;
254 ok(pos
== count
, "found char '%c' in wrong place: got %d, expected %d\n", count
, pos
, count
);
257 for (count
= 32; count
< 128; count
++)
259 LPSTR result
= StrChrA(string
+count
+1, count
);
260 ok(!result
, "found char '%c' not in the string\n", count
);
264 static void test_StrChrW(void)
269 /* this test crashes on win2k SP4 */
270 /*ok(!StrChrW(NULL,'\0'), "found a character in a NULL string!\n");*/
272 for (count
= 32; count
< 16384; count
++)
273 string
[count
] = count
;
274 string
[16384] = '\0';
276 for (count
= 32; count
< 16384; count
++)
278 LPWSTR result
= StrChrW(string
+32, count
);
279 ok((result
- string
) == count
, "found char %d in wrong place\n", count
);
282 for (count
= 32; count
< 16384; count
++)
284 LPWSTR result
= StrChrW(string
+count
+1, count
);
285 ok(!result
, "found char not in the string\n");
289 static void test_StrChrIA(void)
294 /* this test crashes on win2k SP4 */
295 /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/
297 for (count
= 32; count
< 128; count
++)
298 string
[count
] = (char)count
;
301 for (count
= 'A'; count
<= 'X'; count
++)
303 LPSTR result
= StrChrIA(string
+32, count
);
305 ok(result
- string
== count
, "found char '%c' in wrong place\n", count
);
306 ok(StrChrIA(result
, count
)!=NULL
, "didn't find lowercase '%c'\n", count
);
309 for (count
= 'a'; count
< 'z'; count
++)
311 LPSTR result
= StrChrIA(string
+count
+1, count
);
312 ok(!result
, "found char not in the string\n");
316 static void test_StrChrIW(void)
321 /* this test crashes on win2k SP4 */
322 /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/
324 for (count
= 32; count
< 128; count
++)
325 string
[count
] = count
;
328 for (count
= 'A'; count
<= 'X'; count
++)
330 LPWSTR result
= StrChrIW(string
+32, count
);
332 ok(result
- string
== count
, "found char '%c' in wrong place\n", count
);
333 ok(StrChrIW(result
, count
)!=NULL
, "didn't find lowercase '%c'\n", count
);
336 for (count
= 'a'; count
< 'z'; count
++)
338 LPWSTR result
= StrChrIW(string
+count
+1, count
);
339 ok(!result
, "found char not in the string\n");
343 static void test_StrRChrA(void)
348 /* this test crashes on win2k SP4 */
349 /*ok(!StrRChrA(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/
351 for (count
= 32; count
< 128; count
++)
352 string
[count
] = (char)count
;
355 for (count
= 32; count
< 128; count
++)
357 LPSTR result
= StrRChrA(string
+32, NULL
, count
);
358 ok(result
- string
== count
, "found char %d in wrong place\n", count
);
361 for (count
= 32; count
< 128; count
++)
363 LPSTR result
= StrRChrA(string
+count
+1, NULL
, count
);
364 ok(!result
, "found char not in the string\n");
367 for (count
= 32; count
< 128; count
++)
369 LPSTR result
= StrRChrA(string
+count
+1, string
+ 127, count
);
370 ok(!result
, "found char not in the string\n");
374 static void test_StrRChrW(void)
379 /* this test crashes on win2k SP4 */
380 /*ok(!StrRChrW(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/
382 for (count
= 32; count
< 128; count
++)
383 string
[count
] = count
;
386 for (count
= 32; count
< 128; count
++)
388 LPWSTR result
= StrRChrW(string
+32, NULL
, count
);
389 INT pos
= result
- string
;
390 ok(pos
== count
, "found char %d in wrong place: got %d, expected %d\n", count
, pos
, count
);
393 for (count
= 32; count
< 128; count
++)
395 LPWSTR result
= StrRChrW(string
+count
+1, NULL
, count
);
396 ok(!result
, "found char %d not in the string\n", count
);
399 for (count
= 32; count
< 128; count
++)
401 LPWSTR result
= StrRChrW(string
+count
+1, string
+ 127, count
);
402 ok(!result
, "found char %d not in the string\n", count
);
406 static void test_StrCpyW(void)
410 const StrFormatSizeResult
* result
= StrFormatSize_results
;
415 MultiByteToWideChar(CP_ACP
, 0, result
->byte_size_64
, -1, szSrc
, ARRAY_SIZE(szSrc
));
417 lpRes
= StrCpyW(szBuff
, szSrc
);
418 ok(!StrCmpW(szSrc
, szBuff
) && lpRes
== szBuff
, "Copied string %s wrong\n", result
->byte_size_64
);
422 /* this test crashes on win2k SP4 */
423 /*lpRes = StrCpyW(szBuff, NULL);*/
424 /*ok(lpRes == szBuff, "Wrong return value: got %p expected %p\n", lpRes, szBuff);*/
426 /* this test crashes on win2k SP4 */
427 /*lpRes = StrCpyW(NULL, szSrc);*/
428 /*ok(lpRes == NULL, "Wrong return value: got %p expected NULL\n", lpRes);*/
430 /* this test crashes on win2k SP4 */
431 /*lpRes = StrCpyW(NULL, NULL);*/
432 /*ok(lpRes == NULL, "Wrong return value: got %p expected NULL\n", lpRes);*/
435 static void test_StrChrNW(void)
437 static const WCHAR string
[] = {'T','e','s','t','i','n','g',' ','S','t','r','i','n','g',0};
442 win_skip("StrChrNW not available\n");
446 p
= pStrChrNW(string
,'t',10);
447 ok(*p
=='t',"Found wrong 't'\n");
448 ok(*(p
+1)=='i',"next should be 'i'\n");
450 p
= pStrChrNW(string
,'S',10);
451 ok(*p
=='S',"Found wrong 'S'\n");
453 p
= pStrChrNW(string
,'r',10);
454 ok(p
==NULL
,"Should not have found 'r'\n");
457 static void test_StrToIntA(void)
459 const StrToIntResult
*result
= StrToInt_results
;
462 while (result
->string
)
464 return_val
= StrToIntA(result
->string
);
465 ok(return_val
== result
->str_to_int
, "converted '%s' wrong (%d)\n",
466 result
->string
, return_val
);
471 static void test_StrToIntW(void)
474 const StrToIntResult
*result
= StrToInt_results
;
477 while (result
->string
)
479 MultiByteToWideChar(CP_ACP
, 0, result
->string
, -1, szBuff
, ARRAY_SIZE(szBuff
));
480 return_val
= StrToIntW(szBuff
);
481 ok(return_val
== result
->str_to_int
, "converted '%s' wrong (%d)\n",
482 result
->string
, return_val
);
487 static void test_StrToIntExA(void)
489 const StrToIntResult
*result
= StrToInt_results
;
493 while (result
->string
)
496 bRet
= StrToIntExA(result
->string
,0,&return_val
);
498 ok(!bRet
, "Got %d instead of failure for '%s'\n", return_val
, result
->string
);
500 ok(bRet
, "Failed for '%s'\n", result
->string
);
502 ok(return_val
== (int)result
->str_to_int64_ex
, "converted '%s' wrong (%d)\n",
503 result
->string
, return_val
);
507 result
= StrToInt_results
;
508 while (result
->string
)
511 bRet
= StrToIntExA(result
->string
,STIF_SUPPORT_HEX
,&return_val
);
513 ok(!bRet
, "Got %d instead of failure for '%s'\n", return_val
, result
->string
);
515 ok(bRet
, "Failed for '%s'\n", result
->string
);
517 ok(return_val
== (int)result
->str_to_int64_hex
, "converted '%s' wrong (%d)\n",
518 result
->string
, return_val
);
523 static void test_StrToIntExW(void)
526 const StrToIntResult
*result
= StrToInt_results
;
530 while (result
->string
)
533 MultiByteToWideChar(CP_ACP
, 0, result
->string
, -1, szBuff
, ARRAY_SIZE(szBuff
));
534 bRet
= StrToIntExW(szBuff
, 0, &return_val
);
536 ok(!bRet
, "Got %d instead of failure for '%s'\n", return_val
, result
->string
);
538 ok(bRet
, "Failed for '%s'\n", result
->string
);
540 ok(return_val
== (int)result
->str_to_int64_ex
, "converted '%s' wrong (%d)\n",
541 result
->string
, return_val
);
545 result
= StrToInt_results
;
546 while (result
->string
)
549 MultiByteToWideChar(CP_ACP
, 0, result
->string
, -1, szBuff
, ARRAY_SIZE(szBuff
));
550 bRet
= StrToIntExW(szBuff
, STIF_SUPPORT_HEX
, &return_val
);
552 ok(!bRet
, "Got %d instead of failure for '%s'\n", return_val
, result
->string
);
554 ok(bRet
, "Failed for '%s'\n", result
->string
);
556 ok(return_val
== (int)result
->str_to_int64_hex
, "converted '%s' wrong (%d)\n",
557 result
->string
, return_val
);
562 bRet
= StrToIntExW(L
"\x0661\x0662", 0, &return_val
);
563 ok( !bRet
, "Returned %d for Unicode digits\n", return_val
);
564 bRet
= StrToIntExW(L
"\x07c3\x07c4", 0, &return_val
);
565 ok( !bRet
, "Returned %d for Unicode digits\n", return_val
);
566 bRet
= StrToIntExW(L
"\xa0-2", 0, &return_val
);
567 ok( !bRet
, "Returned %d for Unicode space\n", return_val
);
570 static void test_StrToInt64ExA(void)
572 const StrToIntResult
*result
= StrToInt_results
;
578 win_skip("StrToInt64ExA() is not available\n");
582 while (result
->string
)
585 bRet
= pStrToInt64ExA(result
->string
,0,&return_val
);
587 ok(!bRet
, "Got %s instead of failure for '%s'\n",
588 wine_dbgstr_longlong(return_val
), result
->string
);
590 ok(bRet
, "Failed for '%s'\n", result
->string
);
592 ok(return_val
== result
->str_to_int64_ex
, "converted '%s' wrong (%s)\n",
593 result
->string
, wine_dbgstr_longlong(return_val
));
597 result
= StrToInt_results
;
598 while (result
->string
)
601 bRet
= pStrToInt64ExA(result
->string
,STIF_SUPPORT_HEX
,&return_val
);
603 ok(!bRet
, "Got %s instead of failure for '%s'\n",
604 wine_dbgstr_longlong(return_val
), result
->string
);
606 ok(bRet
, "Failed for '%s'\n", result
->string
);
608 ok(return_val
== result
->str_to_int64_hex
, "converted '%s' wrong (%s)\n",
609 result
->string
, wine_dbgstr_longlong(return_val
));
614 static void test_StrToInt64ExW(void)
617 const StrToIntResult
*result
= StrToInt_results
;
623 win_skip("StrToInt64ExW() is not available\n");
627 while (result
->string
)
630 MultiByteToWideChar(CP_ACP
, 0, result
->string
, -1, szBuff
, ARRAY_SIZE(szBuff
));
631 bRet
= pStrToInt64ExW(szBuff
, 0, &return_val
);
633 ok(!bRet
, "Got %s instead of failure for '%s'\n",
634 wine_dbgstr_longlong(return_val
), result
->string
);
636 ok(bRet
, "Failed for '%s'\n", result
->string
);
638 ok(return_val
== result
->str_to_int64_ex
, "converted '%s' wrong (%s)\n",
639 result
->string
, wine_dbgstr_longlong(return_val
));
643 result
= StrToInt_results
;
644 while (result
->string
)
647 MultiByteToWideChar(CP_ACP
, 0, result
->string
, -1, szBuff
, ARRAY_SIZE(szBuff
));
648 bRet
= pStrToInt64ExW(szBuff
, STIF_SUPPORT_HEX
, &return_val
);
650 ok(!bRet
, "Got %s instead of failure for '%s'\n",
651 wine_dbgstr_longlong(return_val
), result
->string
);
653 ok(bRet
, "Failed for '%s'\n", result
->string
);
655 ok(return_val
== result
->str_to_int64_hex
, "converted '%s' wrong (%s)\n",
656 result
->string
, wine_dbgstr_longlong(return_val
));
661 bRet
= pStrToInt64ExW(L
"\x0661\x0662", 0, &return_val
);
662 ok( !bRet
, "Returned %s for Unicode digits\n", wine_dbgstr_longlong(return_val
) );
663 bRet
= pStrToInt64ExW(L
"\x07c3\x07c4", 0, &return_val
);
664 ok( !bRet
, "Returned %s for Unicode digits\n", wine_dbgstr_longlong(return_val
) );
665 bRet
= pStrToInt64ExW(L
"\xa0-2", 0, &return_val
);
666 ok( !bRet
, "Returned %s for Unicode space\n", wine_dbgstr_longlong(return_val
) );
669 static void test_StrDupA(void)
672 const StrFormatSizeResult
* result
= StrFormatSize_results
;
676 lpszStr
= StrDupA(result
->byte_size_64
);
678 ok(lpszStr
!= NULL
, "Dup failed\n");
681 ok(!strcmp(result
->byte_size_64
, lpszStr
), "Copied string wrong\n");
687 /* Later versions of shlwapi return NULL for this, but earlier versions
688 * returned an empty string (as Wine does).
690 lpszStr
= StrDupA(NULL
);
691 ok(lpszStr
== NULL
|| *lpszStr
== '\0', "NULL string returned %p\n", lpszStr
);
695 static void test_StrFormatByteSize64A(void)
698 const StrFormatSizeResult
* result
= StrFormatSize_results
;
700 if (!pStrFormatByteSize64A
)
702 win_skip("StrFormatByteSize64A() is not available\n");
708 pStrFormatByteSize64A(result
->value
, szBuff
, 256);
710 ok(!strcmp(result
->byte_size_64
, szBuff
),
711 "Formatted %s wrong: got %s, expected %s\n",
712 wine_dbgstr_longlong(result
->value
), szBuff
, result
->byte_size_64
);
718 static void test_StrFormatKBSizeW(void)
722 const StrFormatSizeResult
* result
= StrFormatSize_results
;
724 if (!pStrFormatKBSizeW
)
726 win_skip("StrFormatKBSizeW() is not available\n");
732 pStrFormatKBSizeW(result
->value
, szBuffW
, 256);
733 WideCharToMultiByte(CP_ACP
, 0, szBuffW
, -1, szBuff
, ARRAY_SIZE(szBuff
), NULL
, NULL
);
735 ok(!strcmp(result
->kb_size
, szBuff
), "Formatted %s wrong: got %s, expected %s\n",
736 wine_dbgstr_longlong(result
->value
), szBuff
, result
->kb_size
);
741 static void test_StrFormatKBSizeA(void)
744 const StrFormatSizeResult
* result
= StrFormatSize_results
;
746 if (!pStrFormatKBSizeA
)
748 win_skip("StrFormatKBSizeA() is not available\n");
754 pStrFormatKBSizeA(result
->value
, szBuff
, 256);
756 /* shlwapi on Win98 SE does not appear to apply delimiters to the output
757 * and does not correctly handle extremely large values. */
758 ok(!strcmp(result
->kb_size
, szBuff
) ||
759 (result
->kb_size_broken
&& !strcmp(result
->kb_size2
, szBuff
)),
760 "Formatted %s wrong: got %s, expected %s\n",
761 wine_dbgstr_longlong(result
->value
), szBuff
, result
->kb_size
);
766 static void test_StrFromTimeIntervalA(void)
769 const StrFromTimeIntervalResult
* result
= StrFromTimeInterval_results
;
773 StrFromTimeIntervalA(szBuff
, 256, result
->ms
, result
->digits
);
775 ok(!strcmp(result
->time_interval
, szBuff
), "Formatted %d %d wrong: %s\n",
776 result
->ms
, result
->digits
, szBuff
);
781 static void test_StrCmpA(void)
783 static const char str1
[] = {'a','b','c','d','e','f'};
784 static const char str2
[] = {'a','B','c','d','e','f'};
785 ok(0 != StrCmpNA(str1
, str2
, 6), "StrCmpNA is case-insensitive\n");
786 ok(0 == StrCmpNIA(str1
, str2
, 6), "StrCmpNIA is case-sensitive\n");
788 ok(!pChrCmpIA('a', 'a'), "ChrCmpIA doesn't work at all!\n");
789 ok(!pChrCmpIA('b', 'B'), "ChrCmpIA is not case-insensitive\n");
790 ok(pChrCmpIA('a', 'z'), "ChrCmpIA believes that a == z!\n");
793 win_skip("ChrCmpIA() is not available\n");
795 if (pStrIsIntlEqualA
)
797 ok(pStrIsIntlEqualA(FALSE
, str1
, str2
, 5), "StrIsIntlEqualA(FALSE,...) isn't case-insensitive\n");
798 ok(!pStrIsIntlEqualA(TRUE
, str1
, str2
, 5), "StrIsIntlEqualA(TRUE,...) isn't case-sensitive\n");
801 win_skip("StrIsIntlEqualA() is not available\n");
803 if (pIntlStrEqWorkerA
)
805 ok(pIntlStrEqWorkerA(FALSE
, str1
, str2
, 5), "IntlStrEqWorkerA(FALSE,...) isn't case-insensitive\n");
806 ok(!pIntlStrEqWorkerA(TRUE
, str1
, str2
, 5), "pIntlStrEqWorkerA(TRUE,...) isn't case-sensitive\n");
809 win_skip("IntlStrEqWorkerA() is not available\n");
812 static void test_StrCmpW(void)
814 static const WCHAR str1
[] = {'a','b','c','d','e','f'};
815 static const WCHAR str2
[] = {'a','B','c','d','e','f'};
816 ok(0 != StrCmpNW(str1
, str2
, 5), "StrCmpNW is case-insensitive\n");
817 ok(0 == StrCmpNIW(str1
, str2
, 5), "StrCmpNIW is case-sensitive\n");
819 ok(!pChrCmpIW('a', 'a'), "ChrCmpIW doesn't work at all!\n");
820 ok(!pChrCmpIW('b', 'B'), "ChrCmpIW is not case-insensitive\n");
821 ok(pChrCmpIW('a', 'z'), "ChrCmpIW believes that a == z!\n");
824 win_skip("ChrCmpIW() is not available\n");
826 if (pStrIsIntlEqualW
)
828 ok(pStrIsIntlEqualW(FALSE
, str1
, str2
, 5), "StrIsIntlEqualW(FALSE,...) isn't case-insensitive\n");
829 ok(!pStrIsIntlEqualW(TRUE
, str1
, str2
, 5), "StrIsIntlEqualW(TRUE,...) isn't case-sensitive\n");
832 win_skip("StrIsIntlEqualW() is not available\n");
834 if (pIntlStrEqWorkerW
)
836 ok(pIntlStrEqWorkerW(FALSE
, str1
, str2
, 5), "IntlStrEqWorkerW(FALSE,...) isn't case-insensitive\n");
837 ok(!pIntlStrEqWorkerW(TRUE
, str1
, str2
, 5), "IntlStrEqWorkerW(TRUE,...) isn't case-sensitive\n");
840 win_skip("IntlStrEqWorkerW() is not available\n");
843 static WCHAR
*CoDupStrW(const char* src
)
845 INT len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
846 WCHAR
* szTemp
= CoTaskMemAlloc(len
* sizeof(WCHAR
));
847 MultiByteToWideChar(CP_ACP
, 0, src
, -1, szTemp
, len
);
851 static void test_StrRetToBSTR(void)
853 static const WCHAR szTestW
[] = { 'T','e','s','t','\0' };
861 win_skip("StrRetToBSTR() is not available\n");
865 strret
.uType
= STRRET_WSTR
;
866 U(strret
).pOleStr
= CoDupStrW("Test");
868 ret
= pStrRetToBSTR(&strret
, NULL
, &bstr
);
869 ok(ret
== S_OK
&& bstr
&& !wcscmp(bstr
, szTestW
),
870 "STRRET_WSTR: dup failed, ret=0x%08x, bstr %p\n", ret
, bstr
);
873 strret
.uType
= STRRET_CSTR
;
874 lstrcpyA(U(strret
).cStr
, "Test");
875 ret
= pStrRetToBSTR(&strret
, NULL
, &bstr
);
876 ok(ret
== S_OK
&& bstr
&& !wcscmp(bstr
, szTestW
),
877 "STRRET_CSTR: dup failed, ret=0x%08x, bstr %p\n", ret
, bstr
);
880 strret
.uType
= STRRET_OFFSET
;
881 U(strret
).uOffset
= 1;
882 strcpy((char*)&iidl
, " Test");
883 ret
= pStrRetToBSTR(&strret
, iidl
, &bstr
);
884 ok(ret
== S_OK
&& bstr
&& !wcscmp(bstr
, szTestW
),
885 "STRRET_OFFSET: dup failed, ret=0x%08x, bstr %p\n", ret
, bstr
);
888 /* Native crashes if str is NULL */
891 static void test_StrCpyNXA(void)
893 LPCSTR lpSrc
= "hello";
899 win_skip("StrCpyNXA() is not available\n");
903 memset(dest
, '\n', sizeof(dest
));
904 lpszRes
= pStrCpyNXA(dest
, lpSrc
, ARRAY_SIZE(dest
));
905 ok(lpszRes
== dest
+ 5 && !memcmp(dest
, "hello\0\n\n", sizeof(dest
)),
906 "StrCpyNXA: expected %p, \"hello\\0\\n\\n\", got %p, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
907 dest
+ 5, lpszRes
, dest
[0], dest
[1], dest
[2], dest
[3], dest
[4], dest
[5], dest
[6], dest
[7]);
910 static void test_StrCpyNXW(void)
912 static const WCHAR lpInit
[] = { '\n','\n','\n','\n','\n','\n','\n','\n' };
913 static const WCHAR lpSrc
[] = { 'h','e','l','l','o','\0' };
914 static const WCHAR lpRes
[] = { 'h','e','l','l','o','\0','\n','\n' };
920 win_skip("StrCpyNXW() is not available\n");
924 memcpy(dest
, lpInit
, sizeof(lpInit
));
925 lpszRes
= pStrCpyNXW(dest
, lpSrc
, ARRAY_SIZE(dest
));
926 ok(lpszRes
== dest
+ 5 && !memcmp(dest
, lpRes
, sizeof(dest
)),
927 "StrCpyNXW: expected %p, \"hello\\0\\n\\n\", got %p, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
928 dest
+ 5, lpszRes
, dest
[0], dest
[1], dest
[2], dest
[3], dest
[4], dest
[5], dest
[6], dest
[7]);
931 #define check_strrstri(type, str, pos, needle, exp) \
932 ret##type = StrRStrI##type(str, str+pos, needle); \
933 ok(ret##type == (exp), "Type " #type ", expected %p but got %p (string base %p)\n", \
934 (exp), ret##type, str);
936 static void test_StrRStrI(void)
938 static const CHAR szTest
[] = "yAxxxxAy";
939 static const CHAR szTest2
[] = "ABABABAB";
940 static const WCHAR wszTest
[] = {'y','A','x','x','x','x','A','y',0};
941 static const WCHAR wszTest2
[] = {'A','B','A','B','A','B','A','B',0};
943 static const WCHAR wszPattern1
[] = {'A',0};
944 static const WCHAR wszPattern2
[] = {'a','X',0};
945 static const WCHAR wszPattern3
[] = {'A','y',0};
946 static const WCHAR wszPattern4
[] = {'a','b',0};
950 check_strrstri(A
, szTest
, 4, "A", szTest
+1);
951 check_strrstri(A
, szTest
, 4, "aX", szTest
+1);
952 check_strrstri(A
, szTest
, 4, "Ay", NULL
);
953 check_strrstri(W
, wszTest
, 4, wszPattern1
, wszTest
+1);
954 check_strrstri(W
, wszTest
, 4, wszPattern2
, wszTest
+1);
955 check_strrstri(W
, wszTest
, 4, wszPattern3
, NULL
);
957 check_strrstri(A
, szTest2
, 4, "ab", szTest2
+2);
958 check_strrstri(A
, szTest2
, 3, "ab", szTest2
+2);
959 check_strrstri(A
, szTest2
, 2, "ab", szTest2
);
960 check_strrstri(A
, szTest2
, 1, "ab", szTest2
);
961 check_strrstri(A
, szTest2
, 0, "ab", NULL
);
962 check_strrstri(W
, wszTest2
, 4, wszPattern4
, wszTest2
+2);
963 check_strrstri(W
, wszTest2
, 3, wszPattern4
, wszTest2
+2);
964 check_strrstri(W
, wszTest2
, 2, wszPattern4
, wszTest2
);
965 check_strrstri(W
, wszTest2
, 1, wszPattern4
, wszTest2
);
966 check_strrstri(W
, wszTest2
, 0, wszPattern4
, NULL
);
970 static void test_SHAnsiToAnsi(void)
977 win_skip("SHAnsiToAnsi() is not available\n");
981 if (pSHAnsiToAnsi
== (void *)pStrPBrkW
)
983 win_skip("Ordinal 345 corresponds to StrPBrkW, skipping SHAnsiToAnsi tests\n");
987 memset(dest
, '\n', sizeof(dest
));
988 dwRet
= pSHAnsiToAnsi("hello", dest
, ARRAY_SIZE(dest
));
989 ok(dwRet
== 6 && !memcmp(dest
, "hello\0\n\n", sizeof(dest
)),
990 "SHAnsiToAnsi: expected 6, \"hello\\0\\n\\n\", got %d, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
991 dwRet
, dest
[0], dest
[1], dest
[2], dest
[3], dest
[4], dest
[5], dest
[6], dest
[7]);
994 static void test_SHUnicodeToUnicode(void)
996 static const WCHAR lpInit
[] = { '\n','\n','\n','\n','\n','\n','\n','\n' };
997 static const WCHAR lpSrc
[] = { 'h','e','l','l','o','\0' };
998 static const WCHAR lpRes
[] = { 'h','e','l','l','o','\0','\n','\n' };
1002 if (!pSHUnicodeToUnicode
)
1004 win_skip("SHUnicodeToUnicode() is not available\n");
1008 if (pSHUnicodeToUnicode
== (void *)pStrRChrA
)
1010 win_skip("Ordinal 346 corresponds to StrRChrA, skipping SHUnicodeToUnicode tests\n");
1014 memcpy(dest
, lpInit
, sizeof(lpInit
));
1015 dwRet
= pSHUnicodeToUnicode(lpSrc
, dest
, ARRAY_SIZE(dest
));
1016 ok(dwRet
== 6 && !memcmp(dest
, lpRes
, sizeof(dest
)),
1017 "SHUnicodeToUnicode: expected 6, \"hello\\0\\n\\n\", got %d, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
1018 dwRet
, dest
[0], dest
[1], dest
[2], dest
[3], dest
[4], dest
[5], dest
[6], dest
[7]);
1021 static void test_StrXXX_overflows(void)
1023 CHAR str1
[2*MAX_PATH
+1], buf
[2*MAX_PATH
];
1024 WCHAR wstr1
[2*MAX_PATH
+1], wbuf
[2*MAX_PATH
];
1025 const WCHAR fmt
[] = {'%','s',0};
1031 for (i
=0; i
<2*MAX_PATH
; i
++)
1033 str1
[i
] = '0'+(i
%10);
1034 wstr1
[i
] = '0'+(i
%10);
1036 str1
[2*MAX_PATH
] = 0;
1037 wstr1
[2*MAX_PATH
] = 0;
1039 memset(buf
, 0xbf, sizeof(buf
));
1040 expect_eq(StrCpyNA(buf
, str1
, 10), buf
, PCHAR
, "%p");
1041 expect_eq(buf
[9], 0, CHAR
, "%x");
1042 expect_eq(buf
[10], '\xbf', CHAR
, "%x");
1046 expect_eq(pStrCatBuffA(buf
, str1
, 100), buf
, PCHAR
, "%p");
1047 expect_eq(buf
[99], 0, CHAR
, "%x");
1048 expect_eq(buf
[100], '\xbf', CHAR
, "%x");
1051 win_skip("StrCatBuffA() is not available\n");
1056 StrCpyNW(wbuf
, (LPCWSTR
)0x1, 10);
1057 StrCpyNW((LPWSTR
)0x1, wstr1
, 10);
1060 memset(wbuf
, 0xbf, sizeof(wbuf
));
1061 expect_eq(StrCpyNW(wbuf
, (LPCWSTR
)0x1, 1), wbuf
, PWCHAR
, "%p");
1062 expect_eq(wbuf
[0], 0, WCHAR
, "%x");
1063 expect_eq(wbuf
[1], (WCHAR
)0xbfbf, WCHAR
, "%x");
1065 memset(wbuf
, 0xbf, sizeof(wbuf
));
1066 expect_eq(StrCpyNW(wbuf
, 0, 10), wbuf
, PWCHAR
, "%p");
1067 expect_eq(wbuf
[0], 0, WCHAR
, "%x");
1068 expect_eq(wbuf
[1], (WCHAR
)0xbfbf, WCHAR
, "%x");
1070 memset(wbuf
, 0xbf, sizeof(wbuf
));
1071 expect_eq(StrCpyNW(wbuf
, 0, 0), wbuf
, PWCHAR
, "%p");
1072 expect_eq(wbuf
[0], (WCHAR
)0xbfbf, WCHAR
, "%x");
1073 expect_eq(wbuf
[1], (WCHAR
)0xbfbf, WCHAR
, "%x");
1075 memset(wbuf
, 0xbf, sizeof(wbuf
));
1076 expect_eq(StrCpyNW(wbuf
, wstr1
, 0), wbuf
, PWCHAR
, "%p");
1077 expect_eq(wbuf
[0], (WCHAR
)0xbfbf, WCHAR
, "%x");
1078 expect_eq(wbuf
[1], (WCHAR
)0xbfbf, WCHAR
, "%x");
1080 memset(wbuf
, 0xbf, sizeof(wbuf
));
1081 expect_eq(StrCpyNW(wbuf
, wstr1
, 10), wbuf
, PWCHAR
, "%p");
1082 expect_eq(wbuf
[9], 0, WCHAR
, "%x");
1083 expect_eq(wbuf
[10], (WCHAR
)0xbfbf, WCHAR
, "%x");
1087 expect_eq(pStrCatBuffW(wbuf
, wstr1
, 100), wbuf
, PWCHAR
, "%p");
1088 expect_eq(wbuf
[99], 0, WCHAR
, "%x");
1089 expect_eq(wbuf
[100], (WCHAR
)0xbfbf, WCHAR
, "%x");
1092 win_skip("StrCatBuffW() is not available\n");
1096 memset(wbuf
, 0xbf, sizeof(wbuf
));
1097 strret
.uType
= STRRET_WSTR
;
1098 U(strret
).pOleStr
= StrDupW(wstr1
);
1099 hres
= pStrRetToBufW(&strret
, NULL
, wbuf
, 10);
1100 ok(hres
== E_NOT_SUFFICIENT_BUFFER
|| broken(hres
== S_OK
) /* winxp */,
1101 "StrRetToBufW returned %08x\n", hres
);
1102 if (hres
== E_NOT_SUFFICIENT_BUFFER
)
1103 expect_eq(wbuf
[0], 0, WCHAR
, "%x");
1104 expect_eq(wbuf
[9], 0, WCHAR
, "%x");
1105 expect_eq(wbuf
[10], (WCHAR
)0xbfbf, WCHAR
, "%x");
1107 memset(wbuf
, 0xbf, sizeof(wbuf
));
1108 strret
.uType
= STRRET_CSTR
;
1109 StrCpyNA(U(strret
).cStr
, str1
, MAX_PATH
);
1110 hres
= pStrRetToBufW(&strret
, NULL
, wbuf
, 10);
1111 ok(hres
== S_OK
, "StrRetToBufW returned %08x\n", hres
);
1112 ok(!memcmp(wbuf
, wstr1
, 9*sizeof(WCHAR
)) && !wbuf
[9], "StrRetToBuf returned %s\n", wine_dbgstr_w(wbuf
));
1114 memset(wbuf
, 0xbf, sizeof(wbuf
));
1115 strret
.uType
= STRRET_WSTR
;
1116 U(strret
).pOleStr
= NULL
;
1117 hres
= pStrRetToBufW(&strret
, NULL
, wbuf
, 10);
1118 ok(hres
== E_FAIL
, "StrRetToBufW returned %08x\n", hres
);
1119 ok(!wbuf
[0], "StrRetToBuf returned %s\n", wine_dbgstr_w(wbuf
));
1122 win_skip("StrRetToBufW() is not available\n");
1126 memset(buf
, 0xbf, sizeof(buf
));
1127 strret
.uType
= STRRET_CSTR
;
1128 StrCpyNA(U(strret
).cStr
, str1
, MAX_PATH
);
1129 expect_eq2(pStrRetToBufA(&strret
, NULL
, buf
, 10), S_OK
, E_NOT_SUFFICIENT_BUFFER
/* Vista */, HRESULT
, "%x");
1130 expect_eq(buf
[9], 0, CHAR
, "%x");
1131 expect_eq(buf
[10], (CHAR
)0xbf, CHAR
, "%x");
1134 win_skip("StrRetToBufA() is not available\n");
1138 memset(buf
, 0xbf, sizeof(buf
));
1139 ret
= pwnsprintfA(buf
, 10, "%s", str1
);
1140 ok(broken(ret
== 9) || ret
== -1 /* Vista */, "Unexpected wnsprintfA return %d, expected 9 or -1\n", ret
);
1141 expect_eq(buf
[9], 0, CHAR
, "%x");
1142 expect_eq(buf
[10], (CHAR
)0xbf, CHAR
, "%x");
1145 win_skip("wnsprintfA() is not available\n");
1149 memset(wbuf
, 0xbf, sizeof(wbuf
));
1150 ret
= pwnsprintfW(wbuf
, 10, fmt
, wstr1
);
1151 ok(broken(ret
== 9) || ret
== -1 /* Vista */, "Unexpected wnsprintfW return %d, expected 9 or -1\n", ret
);
1152 expect_eq(wbuf
[9], 0, WCHAR
, "%x");
1153 expect_eq(wbuf
[10], (WCHAR
)0xbfbf, WCHAR
, "%x");
1156 win_skip("wnsprintfW() is not available\n");
1159 static void test_StrStrA(void)
1161 static const char *deadbeefA
= "DeAdBeEf";
1170 {"DeAd", deadbeefA
},
1172 {"AdBe", deadbeefA
+ 2},
1174 {"BeEf", deadbeefA
+ 4},
1181 /* Tests crash on Win2k */
1184 ret
= StrStrA(NULL
, NULL
);
1185 ok(!ret
, "Expected StrStrA to return NULL, got %p\n", ret
);
1187 ret
= StrStrA(NULL
, "");
1188 ok(!ret
, "Expected StrStrA to return NULL, got %p\n", ret
);
1190 ret
= StrStrA("", NULL
);
1191 ok(!ret
, "Expected StrStrA to return NULL, got %p\n", ret
);
1194 ret
= StrStrA("", "");
1195 ok(!ret
, "Expected StrStrA to return NULL, got %p\n", ret
);
1197 for (i
= 0; i
< ARRAY_SIZE(StrStrA_cases
); i
++)
1199 ret
= StrStrA(deadbeefA
, StrStrA_cases
[i
].search
);
1200 ok(ret
== StrStrA_cases
[i
].expect
,
1201 "[%d] Expected StrStrA to return %p, got %p\n",
1202 i
, StrStrA_cases
[i
].expect
, ret
);
1206 static void test_StrStrW(void)
1208 static const WCHAR emptyW
[] = {0};
1209 static const WCHAR deadbeefW
[] = {'D','e','A','d','B','e','E','f',0};
1210 static const WCHAR deadW
[] = {'D','e','A','d',0};
1211 static const WCHAR dead_lowerW
[] = {'d','e','a','d',0};
1212 static const WCHAR adbeW
[] = {'A','d','B','e',0};
1213 static const WCHAR adbe_lowerW
[] = {'a','d','b','e',0};
1214 static const WCHAR beefW
[] = {'B','e','E','f',0};
1215 static const WCHAR beef_lowerW
[] = {'b','e','e','f',0};
1219 const WCHAR
*search
;
1220 const WCHAR
*expect
;
1225 {dead_lowerW
, NULL
},
1226 {adbeW
, deadbeefW
+ 2},
1227 {adbe_lowerW
, NULL
},
1228 {beefW
, deadbeefW
+ 4},
1229 {beef_lowerW
, NULL
},
1235 /* Tests crash on Win2k */
1238 ret
= StrStrW(NULL
, NULL
);
1239 ok(!ret
, "Expected StrStrW to return NULL, got %p\n", ret
);
1241 ret
= StrStrW(NULL
, emptyW
);
1242 ok(!ret
, "Expected StrStrW to return NULL, got %p\n", ret
);
1244 ret
= StrStrW(emptyW
, NULL
);
1245 ok(!ret
, "Expected StrStrW to return NULL, got %p\n", ret
);
1248 ret
= StrStrW(emptyW
, emptyW
);
1249 ok(!ret
, "Expected StrStrW to return NULL, got %p\n", ret
);
1251 for (i
= 0; i
< ARRAY_SIZE(StrStrW_cases
); i
++)
1253 ret
= StrStrW(deadbeefW
, StrStrW_cases
[i
].search
);
1254 ok(ret
== StrStrW_cases
[i
].expect
,
1255 "[%d] Expected StrStrW to return %p, got %p\n",
1256 i
, StrStrW_cases
[i
].expect
, ret
);
1260 static void test_StrStrIA(void)
1262 static const char *deadbeefA
= "DeAdBeEf";
1268 } StrStrIA_cases
[] =
1271 {"DeAd", deadbeefA
},
1272 {"dead", deadbeefA
},
1273 {"AdBe", deadbeefA
+ 2},
1274 {"adbe", deadbeefA
+ 2},
1275 {"BeEf", deadbeefA
+ 4},
1276 {"beef", deadbeefA
+ 4},
1283 /* Tests crash on Win2k */
1286 ret
= StrStrIA(NULL
, NULL
);
1287 ok(!ret
, "Expected StrStrIA to return NULL, got %p\n", ret
);
1289 ret
= StrStrIA(NULL
, "");
1290 ok(!ret
, "Expected StrStrIA to return NULL, got %p\n", ret
);
1292 ret
= StrStrIA("", NULL
);
1293 ok(!ret
, "Expected StrStrIA to return NULL, got %p\n", ret
);
1296 ret
= StrStrIA("", "");
1297 ok(!ret
, "Expected StrStrIA to return NULL, got %p\n", ret
);
1299 for (i
= 0; i
< ARRAY_SIZE(StrStrIA_cases
); i
++)
1301 ret
= StrStrIA(deadbeefA
, StrStrIA_cases
[i
].search
);
1302 ok(ret
== StrStrIA_cases
[i
].expect
,
1303 "[%d] Expected StrStrIA to return %p, got %p\n",
1304 i
, StrStrIA_cases
[i
].expect
, ret
);
1308 static void test_StrStrIW(void)
1310 static const WCHAR emptyW
[] = {0};
1311 static const WCHAR deadbeefW
[] = {'D','e','A','d','B','e','E','f',0};
1312 static const WCHAR deadW
[] = {'D','e','A','d',0};
1313 static const WCHAR dead_lowerW
[] = {'d','e','a','d',0};
1314 static const WCHAR adbeW
[] = {'A','d','B','e',0};
1315 static const WCHAR adbe_lowerW
[] = {'a','d','b','e',0};
1316 static const WCHAR beefW
[] = {'B','e','E','f',0};
1317 static const WCHAR beef_lowerW
[] = {'b','e','e','f',0};
1318 static const WCHAR cafeW
[] = {'c','a','f','e',0};
1322 const WCHAR
*search
;
1323 const WCHAR
*expect
;
1324 } StrStrIW_cases
[] =
1328 {dead_lowerW
, deadbeefW
},
1329 {adbeW
, deadbeefW
+ 2},
1330 {adbe_lowerW
, deadbeefW
+ 2},
1331 {beefW
, deadbeefW
+ 4},
1332 {beef_lowerW
, deadbeefW
+ 4},
1339 /* Tests crash on Win2k */
1342 ret
= StrStrIW(NULL
, NULL
);
1343 ok(!ret
, "Expected StrStrIW to return NULL, got %p\n", ret
);
1345 ret
= StrStrIW(NULL
, emptyW
);
1346 ok(!ret
, "Expected StrStrIW to return NULL, got %p\n", ret
);
1348 ret
= StrStrIW(emptyW
, NULL
);
1349 ok(!ret
, "Expected StrStrIW to return NULL, got %p\n", ret
);
1352 ret
= StrStrIW(emptyW
, emptyW
);
1353 ok(!ret
, "Expected StrStrIW to return NULL, got %p\n", ret
);
1355 for (i
= 0; i
< ARRAY_SIZE(StrStrIW_cases
); i
++)
1357 ret
= StrStrIW(deadbeefW
, StrStrIW_cases
[i
].search
);
1358 ok(ret
== StrStrIW_cases
[i
].expect
,
1359 "[%d] Expected StrStrIW to return %p, got %p\n",
1360 i
, StrStrIW_cases
[i
].expect
, ret
);
1364 static void test_StrStrNW(void)
1366 static const WCHAR emptyW
[] = {0};
1367 static const WCHAR deadbeefW
[] = {'D','e','A','d','B','e','E','f',0};
1368 static const WCHAR deadW
[] = {'D','e','A','d',0};
1369 static const WCHAR dead_lowerW
[] = {'d','e','a','d',0};
1370 static const WCHAR adbeW
[] = {'A','d','B','e',0};
1371 static const WCHAR adbe_lowerW
[] = {'a','d','b','e',0};
1372 static const WCHAR beefW
[] = {'B','e','E','f',0};
1373 static const WCHAR beef_lowerW
[] = {'b','e','e','f',0};
1377 const WCHAR
*search
;
1379 const WCHAR
*expect
;
1380 } StrStrNW_cases
[] =
1382 {emptyW
, ARRAY_SIZE(deadbeefW
), NULL
},
1383 {deadW
, ARRAY_SIZE(deadbeefW
), deadbeefW
},
1384 {dead_lowerW
, ARRAY_SIZE(deadbeefW
), NULL
},
1385 {adbeW
, ARRAY_SIZE(deadbeefW
), deadbeefW
+ 2},
1386 {adbe_lowerW
, ARRAY_SIZE(deadbeefW
), NULL
},
1387 {beefW
, ARRAY_SIZE(deadbeefW
), deadbeefW
+ 4},
1388 {beef_lowerW
, ARRAY_SIZE(deadbeefW
), NULL
},
1394 {beefW
, 5, deadbeefW
+ 4},
1395 {beefW
, 6, deadbeefW
+ 4},
1396 {beefW
, 7, deadbeefW
+ 4},
1397 {beefW
, 8, deadbeefW
+ 4},
1398 {beefW
, 9, deadbeefW
+ 4},
1406 win_skip("StrStrNW() is not available\n");
1410 ret
= pStrStrNW(NULL
, NULL
, 0);
1411 ok(!ret
, "Expected StrStrNW to return NULL, got %p\n", ret
);
1413 ret
= pStrStrNW(NULL
, NULL
, 10);
1414 ok(!ret
, "Expected StrStrNW to return NULL, got %p\n", ret
);
1416 ret
= pStrStrNW(NULL
, emptyW
, 10);
1417 ok(!ret
, "Expected StrStrNW to return NULL, got %p\n", ret
);
1419 ret
= pStrStrNW(emptyW
, NULL
, 10);
1420 ok(!ret
, "Expected StrStrNW to return NULL, got %p\n", ret
);
1422 ret
= pStrStrNW(emptyW
, emptyW
, 10);
1423 ok(!ret
, "Expected StrStrNW to return NULL, got %p\n", ret
);
1425 for (i
= 0; i
< ARRAY_SIZE(StrStrNW_cases
); i
++)
1427 ret
= pStrStrNW(deadbeefW
, StrStrNW_cases
[i
].search
, StrStrNW_cases
[i
].count
);
1428 ok(ret
== StrStrNW_cases
[i
].expect
,
1429 "[%d] Expected StrStrNW to return %p, got %p\n",
1430 i
, StrStrNW_cases
[i
].expect
, ret
);
1433 /* StrStrNW accepts counts larger than the search string length but rejects
1434 * counts larger than around 2G. The limit seems to change based on the
1435 * caller executable itself. */
1436 ret
= pStrStrNW(deadbeefW
, beefW
, 100);
1437 ok(ret
== deadbeefW
+ 4, "Expected StrStrNW to return deadbeefW + 4, got %p\n", ret
);
1441 ret
= pStrStrNW(deadbeefW
, beefW
, ~0U);
1442 ok(!ret
, "Expected StrStrNW to return NULL, got %p\n", ret
);
1446 static void test_StrStrNIW(void)
1448 static const WCHAR emptyW
[] = {0};
1449 static const WCHAR deadbeefW
[] = {'D','e','A','d','B','e','E','f',0};
1450 static const WCHAR deadW
[] = {'D','e','A','d',0};
1451 static const WCHAR dead_lowerW
[] = {'d','e','a','d',0};
1452 static const WCHAR adbeW
[] = {'A','d','B','e',0};
1453 static const WCHAR adbe_lowerW
[] = {'a','d','b','e',0};
1454 static const WCHAR beefW
[] = {'B','e','E','f',0};
1455 static const WCHAR beef_lowerW
[] = {'b','e','e','f',0};
1456 static const WCHAR cafeW
[] = {'c','a','f','e',0};
1460 const WCHAR
*search
;
1462 const WCHAR
*expect
;
1463 } StrStrNIW_cases
[] =
1465 {emptyW
, ARRAY_SIZE(deadbeefW
), NULL
},
1466 {deadW
, ARRAY_SIZE(deadbeefW
), deadbeefW
},
1467 {dead_lowerW
, ARRAY_SIZE(deadbeefW
), deadbeefW
},
1468 {adbeW
, ARRAY_SIZE(deadbeefW
), deadbeefW
+ 2},
1469 {adbe_lowerW
, ARRAY_SIZE(deadbeefW
), deadbeefW
+ 2},
1470 {beefW
, ARRAY_SIZE(deadbeefW
), deadbeefW
+ 4},
1471 {beef_lowerW
, ARRAY_SIZE(deadbeefW
), deadbeefW
+ 4},
1472 {cafeW
, ARRAY_SIZE(deadbeefW
), NULL
},
1478 {beefW
, 5, deadbeefW
+ 4},
1479 {beefW
, 6, deadbeefW
+ 4},
1480 {beefW
, 7, deadbeefW
+ 4},
1481 {beefW
, 8, deadbeefW
+ 4},
1482 {beefW
, 9, deadbeefW
+ 4},
1483 {beef_lowerW
, 0, NULL
},
1484 {beef_lowerW
, 1, NULL
},
1485 {beef_lowerW
, 2, NULL
},
1486 {beef_lowerW
, 3, NULL
},
1487 {beef_lowerW
, 4, NULL
},
1488 {beef_lowerW
, 5, deadbeefW
+ 4},
1489 {beef_lowerW
, 6, deadbeefW
+ 4},
1490 {beef_lowerW
, 7, deadbeefW
+ 4},
1491 {beef_lowerW
, 8, deadbeefW
+ 4},
1492 {beef_lowerW
, 9, deadbeefW
+ 4},
1500 win_skip("StrStrNIW() is not available\n");
1504 ret
= pStrStrNIW(NULL
, NULL
, 0);
1505 ok(!ret
, "Expected StrStrNIW to return NULL, got %p\n", ret
);
1507 ret
= pStrStrNIW(NULL
, NULL
, 10);
1508 ok(!ret
, "Expected StrStrNIW to return NULL, got %p\n", ret
);
1510 ret
= pStrStrNIW(NULL
, emptyW
, 10);
1511 ok(!ret
, "Expected StrStrNIW to return NULL, got %p\n", ret
);
1513 ret
= pStrStrNIW(emptyW
, NULL
, 10);
1514 ok(!ret
, "Expected StrStrNIW to return NULL, got %p\n", ret
);
1516 ret
= pStrStrNIW(emptyW
, emptyW
, 10);
1517 ok(!ret
, "Expected StrStrNIW to return NULL, got %p\n", ret
);
1519 for (i
= 0; i
< ARRAY_SIZE(StrStrNIW_cases
); i
++)
1521 ret
= pStrStrNIW(deadbeefW
, StrStrNIW_cases
[i
].search
, StrStrNIW_cases
[i
].count
);
1522 ok(ret
== StrStrNIW_cases
[i
].expect
,
1523 "[%d] Expected StrStrNIW to return %p, got %p\n",
1524 i
, StrStrNIW_cases
[i
].expect
, ret
);
1527 /* StrStrNIW accepts counts larger than the search string length but rejects
1528 * counts larger than around 2G. The limit seems to change based on the
1529 * caller executable itself. */
1530 ret
= pStrStrNIW(deadbeefW
, beefW
, 100);
1531 ok(ret
== deadbeefW
+ 4, "Expected StrStrNIW to return deadbeefW + 4, got %p\n", ret
);
1535 ret
= pStrStrNIW(deadbeefW
, beefW
, ~0U);
1536 ok(!ret
, "Expected StrStrNIW to return NULL, got %p\n", ret
);
1540 static void test_StrCatChainW(void)
1542 static const WCHAR deadbeefW
[] = {'D','e','A','d','B','e','E','f',0};
1543 static const WCHAR deadW
[] = {'D','e','A','d',0};
1544 static const WCHAR beefW
[] = {'B','e','E','f',0};
1551 win_skip("StrCatChainW is not available\n");
1555 /* Test with NULL buffer */
1556 ret
= pStrCatChainW(NULL
, 0, 0, beefW
);
1557 ok(ret
== 0, "Expected StrCatChainW to return 0, got %u\n", ret
);
1559 /* Test with empty buffer */
1560 memset(buf
, 0x11, sizeof(buf
));
1561 ret
= pStrCatChainW(buf
, 0, 0, beefW
);
1562 ok(ret
== 0, "Expected StrCatChainW to return 0, got %u\n", ret
);
1563 ok(buf
[0] == 0x1111, "Expected buf[0] = 0x1111, got %x\n", buf
[0]);
1565 memcpy(buf
, deadbeefW
, sizeof(deadbeefW
));
1566 ret
= pStrCatChainW(buf
, 0, -1, beefW
);
1567 ok(ret
== 8, "Expected StrCatChainW to return 8, got %u\n", ret
);
1568 ok(!memcmp(buf
, deadbeefW
, sizeof(deadbeefW
)), "Buffer contains wrong data\n");
1570 /* Append data to existing string with offset = -1 */
1571 memset(buf
, 0x11, sizeof(buf
));
1572 ret
= pStrCatChainW(buf
, 32, 0, deadW
);
1573 ok(ret
== 4, "Expected StrCatChainW to return 4, got %u\n", ret
);
1574 ok(!memcmp(buf
, deadW
, sizeof(deadW
)), "Buffer contains wrong data\n");
1576 ret
= pStrCatChainW(buf
, 32, -1, beefW
);
1577 ok(ret
== 8, "Expected StrCatChainW to return 8, got %u\n", ret
);
1578 ok(!memcmp(buf
, deadbeefW
, sizeof(deadbeefW
)), "Buffer contains wrong data\n");
1580 /* Append data at a fixed offset */
1581 memset(buf
, 0x11, sizeof(buf
));
1582 ret
= pStrCatChainW(buf
, 32, 0, deadW
);
1583 ok(ret
== 4, "Expected StrCatChainW to return 4, got %u\n", ret
);
1584 ok(!memcmp(buf
, deadW
, sizeof(deadW
)), "Buffer contains wrong data\n");
1586 ret
= pStrCatChainW(buf
, 32, 4, beefW
);
1587 ok(ret
== 8, "Expected StrCatChainW to return 8, got %u\n", ret
);
1588 ok(!memcmp(buf
, deadbeefW
, sizeof(deadbeefW
)), "Buffer contains wrong data\n");
1590 /* Buffer exactly sufficient for string + terminating null */
1591 memset(buf
, 0x11, sizeof(buf
));
1592 ret
= pStrCatChainW(buf
, 5, 0, deadW
);
1593 ok(ret
== 4, "Expected StrCatChainW to return 4, got %u\n", ret
);
1594 ok(!memcmp(buf
, deadW
, sizeof(deadW
)), "Buffer contains wrong data\n");
1596 /* Buffer too small, string will be truncated */
1597 memset(buf
, 0x11, sizeof(buf
));
1598 ret
= pStrCatChainW(buf
, 4, 0, deadW
);
1601 /* Windows 2000 and XP uses a slightly different implementation
1602 * for StrCatChainW, which doesn't ensure that strings are null-
1603 * terminated. Skip test if we detect such an implementation. */
1604 win_skip("Windows2000/XP behaviour detected for StrCatChainW, skipping tests\n");
1607 ok(ret
== 3, "Expected StrCatChainW to return 3, got %u\n", ret
);
1608 ok(!memcmp(buf
, deadW
, 3 * sizeof(WCHAR
)), "Buffer contains wrong data\n");
1609 ok(!buf
[3], "String is not nullterminated\n");
1610 ok(buf
[4] == 0x1111, "Expected buf[4] = 0x1111, got %x\n", buf
[4]);
1612 /* Overwrite part of an existing string */
1613 ret
= pStrCatChainW(buf
, 4, 1, beefW
);
1614 ok(ret
== 3, "Expected StrCatChainW to return 3, got %u\n", ret
);
1615 ok(buf
[0] == 'D', "Expected buf[0] = 'D', got %x\n", buf
[0]);
1616 ok(buf
[1] == 'B', "Expected buf[1] = 'B', got %x\n", buf
[1]);
1617 ok(buf
[2] == 'e', "Expected buf[2] = 'e', got %x\n", buf
[2]);
1618 ok(!buf
[3], "String is not nullterminated\n");
1619 ok(buf
[4] == 0x1111, "Expected buf[4] = 0x1111, got %x\n", buf
[4]);
1621 /* Test appending to full buffer */
1622 memset(buf
, 0x11, sizeof(buf
));
1623 memcpy(buf
, deadbeefW
, sizeof(deadbeefW
));
1624 memcpy(buf
+ 9, deadW
, sizeof(deadW
));
1625 ret
= pStrCatChainW(buf
, 9, 8, beefW
);
1626 ok(ret
== 8, "Expected StrCatChainW to return 8, got %u\n", ret
);
1627 ok(!memcmp(buf
, deadbeefW
, sizeof(deadbeefW
)), "Buffer contains wrong data\n");
1628 ok(!memcmp(buf
+ 9, deadW
, sizeof(deadW
)), "Buffer contains wrong data\n");
1630 /* Offset points at the end of the buffer */
1631 ret
= pStrCatChainW(buf
, 9, 9, beefW
);
1632 ok(ret
== 8, "Expected StrCatChainW to return 8, got %u\n", ret
);
1633 ok(!memcmp(buf
, deadbeefW
, sizeof(deadbeefW
)), "Buffer contains wrong data\n");
1634 ok(!memcmp(buf
+ 9, deadW
, sizeof(deadW
)), "Buffer contains wrong data\n");
1636 /* Offset points outside of the buffer */
1637 ret
= pStrCatChainW(buf
, 9, 10, beefW
);
1638 ok(ret
== 10, "Expected StrCatChainW to return 10, got %u\n", ret
);
1639 ok(!memcmp(buf
, deadbeefW
, sizeof(deadbeefW
)), "Buffer contains wrong data\n");
1640 ok(!memcmp(buf
+ 9, deadW
, sizeof(deadW
)), "Buffer contains wrong data\n");
1642 /* The same but without nullterminated string */
1643 memcpy(buf
, deadbeefW
, sizeof(deadbeefW
));
1644 ret
= pStrCatChainW(buf
, 5, -1, deadW
);
1645 ok(ret
== 8, "Expected StrCatChainW to return 8, got %u\n", ret
);
1646 ok(!memcmp(buf
, deadbeefW
, sizeof(deadbeefW
)), "Buffer contains wrong data\n");
1648 ret
= pStrCatChainW(buf
, 5, 5, deadW
);
1649 ok(ret
== 4, "Expected StrCatChainW to return 4, got %u\n", ret
);
1650 ok(!memcmp(buf
, deadW
, sizeof(deadW
)), "Buffer contains wrong data\n");
1651 ok(buf
[5] == 'e', "Expected buf[5] = 'e', got %x\n", buf
[5]);
1653 ret
= pStrCatChainW(buf
, 5, 6, deadW
);
1654 ok(ret
== 6, "Expected StrCatChainW to return 6, got %u\n", ret
);
1655 ok(!memcmp(buf
, deadW
, sizeof(deadW
)), "Buffer contains wrong data\n");
1656 ok(buf
[5] == 'e', "Expected buf[5] = 'e', got %x\n", buf
[5]);
1662 CHAR thousandDelim
[8];
1663 CHAR decimalDelim
[8];
1666 GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
, thousandDelim
, 8);
1667 GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, decimalDelim
, 8);
1669 hShlwapi
= GetModuleHandleA("shlwapi");
1670 pChrCmpIA
= (void *)GetProcAddress(hShlwapi
, "ChrCmpIA");
1671 pChrCmpIW
= (void *)GetProcAddress(hShlwapi
, "ChrCmpIW");
1672 pIntlStrEqWorkerA
= (void *)GetProcAddress(hShlwapi
, "IntlStrEqWorkerA");
1673 pIntlStrEqWorkerW
= (void *)GetProcAddress(hShlwapi
, "IntlStrEqWorkerW");
1674 pSHAnsiToAnsi
= (void *)GetProcAddress(hShlwapi
, (LPSTR
)345);
1675 pSHUnicodeToUnicode
= (void *)GetProcAddress(hShlwapi
, (LPSTR
)346);
1676 pStrCatBuffA
= (void *)GetProcAddress(hShlwapi
, "StrCatBuffA");
1677 pStrCatBuffW
= (void *)GetProcAddress(hShlwapi
, "StrCatBuffW");
1678 pStrCatChainW
= (void *)GetProcAddress(hShlwapi
, "StrCatChainW");
1679 pStrCpyNXA
= (void *)GetProcAddress(hShlwapi
, (LPSTR
)399);
1680 pStrCpyNXW
= (void *)GetProcAddress(hShlwapi
, (LPSTR
)400);
1681 pStrChrNW
= (void *)GetProcAddress(hShlwapi
, "StrChrNW");
1682 pStrFormatByteSize64A
= (void *)GetProcAddress(hShlwapi
, "StrFormatByteSize64A");
1683 pStrFormatKBSizeA
= (void *)GetProcAddress(hShlwapi
, "StrFormatKBSizeA");
1684 pStrFormatKBSizeW
= (void *)GetProcAddress(hShlwapi
, "StrFormatKBSizeW");
1685 pStrIsIntlEqualA
= (void *)GetProcAddress(hShlwapi
, "StrIsIntlEqualA");
1686 pStrIsIntlEqualW
= (void *)GetProcAddress(hShlwapi
, "StrIsIntlEqualW");
1687 pStrPBrkW
= (void *)GetProcAddress(hShlwapi
, "StrPBrkW");
1688 pStrRChrA
= (void *)GetProcAddress(hShlwapi
, "StrRChrA");
1689 pStrRetToBSTR
= (void *)GetProcAddress(hShlwapi
, "StrRetToBSTR");
1690 pStrRetToBufA
= (void *)GetProcAddress(hShlwapi
, "StrRetToBufA");
1691 pStrRetToBufW
= (void *)GetProcAddress(hShlwapi
, "StrRetToBufW");
1692 pStrStrNW
= (void *)GetProcAddress(hShlwapi
, "StrStrNW");
1693 pStrStrNIW
= (void *)GetProcAddress(hShlwapi
, "StrStrNIW");
1694 pwnsprintfA
= (void *)GetProcAddress(hShlwapi
, "wnsprintfA");
1695 pwnsprintfW
= (void *)GetProcAddress(hShlwapi
, "wnsprintfW");
1696 pStrToInt64ExA
= (void *)GetProcAddress(hShlwapi
, "StrToInt64ExA");
1697 pStrToInt64ExW
= (void *)GetProcAddress(hShlwapi
, "StrToInt64ExW");
1711 test_StrToInt64ExA();
1712 test_StrToInt64ExW();
1715 /* language-dependent test */
1716 if (is_lang_english() && is_locale_english())
1718 test_StrFormatByteSize64A();
1719 test_StrFormatKBSizeA();
1720 test_StrFormatKBSizeW();
1723 skip("An English UI and locale is required for the StrFormat*Size tests\n");
1724 if (is_lang_english())
1725 test_StrFromTimeIntervalA();
1727 skip("An English UI is required for the StrFromTimeInterval tests\n");
1731 test_StrRetToBSTR();
1735 test_SHAnsiToAnsi();
1736 test_SHUnicodeToUnicode();
1737 test_StrXXX_overflows();
1744 test_StrCatChainW();